Goals Accomplished
- Ported WebAssembly Micro Runtime (WAMR) to run on targets supported by ARM Mbed OS.
- Demonstrated ported WAMR works by compiling to different targets and running on one.
- Measured execution time of WASM interpreters on various boards.
Technical Approach
Running WAMR on Zephyr OS.
First, we got familiar with compiling applications for embedded systems. Getting a Blinky project running on Zephyr took the most time. We were inexperienced with interacting so closely with build tools and most installed software needed to be adjusted to work. All this was further complicated by the fact that the latest version of CMake was buggy (zephyr#30232). However, Zephyr developers in their Slack channel helped us out.
WAMR already supports Zephyr OS and it has a mini-product available too. We had a Nordic nRF52840 DK board available, and so we decided to run WAMR on it. The mini-product is a sample program that sets-up the WAMR runtime, calls its main function and exits. Setting up a running baseline made us understand these key concepts about WAMR:
- A C/C++ (native) program needs to set-up WAMR runtime. This program is what we flash to the board.
- The WAMR runtime needs to know how much stack and heap memory its modules can have.
- WASM program is not sent over USB in mini-product, but its binary form is encoded in a C string available to the native program.
- Our native program can pass arguments and store the result value from any function in the WASM program, including main().
- The WASM program can pass control to any functions defined natively.
Compiling to WASM Modules
Once we had the WASM program provided with WAMR running on Zephyr, we wanted to run our own WASM programs. We learned that WASI-SDK comes with a CLang compiler that can produce WASM bytecode from C programs. Also, appropriate flags were needed to be set so that the linker does not complain of missing main() when it is not needed, and also to export other functions. There exported functions have their definition missing from the WASM module. WAMR runtime can link functions from the native program to these exported functions. This allows the WASM program to call any needed native functions to, for example, blink an LED.
Porting WAMR to Mbed
- We first needed to set-up our system so that it builds Mbed OS. We set up the toolchain and the appropriate dependencies for our application. This included installing CMake, GNU ARM, and Python 3 with some additional packages. For our Windows machines, we also had to find a workable generator for CMake, which turned out to be MinGW make.
- We needed to incorporate the compiling process of WAMR with Mbed OS, so that functions from both were available to our native program. WAMR uses CMake as its build system. The official Mbed CLI uses Python, and this was a major problem. However, we were able to find a CMake build of Mbed OS, made by researchers at USC RPL. From then, we learned CMake commands and included WAMR in the middle of the CMake files of Mbed. This allowed WAMR to be a part of the Mbed static OS library available to native programs.
- Next, we needed to implement the platform abstraction layer in WAMR. All of the OS-dependent functions have been separated down to a few functions, and the rest of WAMR is OS independent. We implemented the API required for the WAMR interpreter.
Comparing Different WASM Interpreters
With WAMR interpreter now available on Mbed devices, we wrote a recursive Fibonacci function for all the boards we had:
- WAMR
- Zephyr OS on Nordic nRF52840-DK
- Mbed OS on STM32 Nucleo F411-RE
- WASM3
- Mbed OS on Arduino Nano 33 BLE
WASM3 supports Arduino Nano 33 and is available to use through Arduino IDE. However, it only consists of an interpreter, while our WAMR porting to Mbed can be extended to allow WAMR JIT, WAMR AoT, and WAMR's libraries are also available on targets supported by Mbed.
Results
The forks of WAMR and Mbed-CMake with commits to make the porting work are described in our Github repo's README. Scripts to aid in the development process are also available.
The builds/ folder in the repo contains two binaries with WAMR. Both of them were successfully compiled using our build system for Mbed and WAMR. Both are built from the same native and WASM program, but are target to two different boards: STM32 Nucleo and Arduino Nano 33.
We were able to verify implementation by running it on a STM32 Nucleo board. Results and details are added in the Github repo. Since the STM32 Nucleo board is Mbed-enabled, we were able to run our binary without worrying about the bootloader. The output demonstrated that WAMR is now running on the Mbed device using Mbed's libraries.
› See output from provided mini-product for Mbed
stm32_mbed_wamr.cpp set up WAMR to run WASM module of fib_timed.c on a STM32F411 Nucleo board.
Performance Comparison
We used the benchmark of measuring the execution time of computing 24th Fibonacci number recursively. This computation when performed by any WASM interpreter was much slower when compared to native. This was expected. However, it was surprising that WAMR had little overhead to set up, and most of the extra time taken was while doing the computation.
› Execution time of WASM interpreter on various boards
WASM3 claims to be the fastest WASM interpreter. We could not run WASM3 and WAMR on the same board and directly compare them, as WASM3 is not supported on SMT32 Nucleo board and we could not flash to Arduino Nano 33 without using Arduino IDE. However, we indirectly attempted to compare WASM3 with WAMR, by measuring how many times slower was the interpreter in doing its computation as compared to natively calculating it. WASM3 indeed slowed down less as compared to WAMR. However, WASM3 is only an interpreter, while WAMR AoT support can be implemented for Mbed which should be faster than WASM3.
› How slow are WAMR and WASM3 compared to native?
Strengths and Possible Improvements
Strengths:
- WAMR now runs on all targets supported by Mbed-CMake, which includes numerous boards like those from Nordic, STM, NXP, Renesas among others.
Possible Improvements:
- We identified how to attach a J-Link debugger to our Arduino Nano 33 board and figured out at what offset we might have flashed it. Resources collected in the builds folder of our repo. If we could solder well, WAMR binary could be run on Arduino Nano 33 board.
- Our implementation currently does not make available the Arduino libraries. While there have been many CMake build systems for Arduino, many of them have been abandoned. If a CMake build system of Arduino is available with the support for recent lauched ArduinoCore-mbed, then that build system can be integrated into Mbed-CMake to have Arduino libraries also available to the native program.
- WAMR AoT compiler would be faster than the currently ported WAMR Interpretor, and is therefore of much interest. By implementing mmap and related functions in the platform API layer, AoT would be available on WAMR for Mbed.
- By implementing the platform API extension on WAMR, support for multi-threaded WASM applications along with application framework and remote application management would be available in WAMR for Mbed.
Existing Literature on WAMR
WebAssembly's popularity has increased and with that so has the research into other applications of the binary instruction format. Despite its benefits, WebAssembly has been shown to be 45% slower than its native commponent [1] .
This project invokes WAMR, but other run-times also exist. WASI has been created to be the run time that accesses and executes systems calls [2] . Work such as the IoT OS, Wasmachine has been created to be "a secure runtime/OS aiming to run WebAssembly applications faster than bare-metal machine" [2] .
While beneficial in terms of timing using its ahead-of-time approach, it could be some time before Wasmachine could be deployed. In additional research work has been made by the partnership of Mozill, Red Hat, Intel, and Fastly. Together, the Bytecode Alliance, has made progress in areas of code generation, run-time, and micro-runtime. Their work with the WebAssembly MicroRuntime (WAMR) has been created for Linux, macOS, Zephyr, AliOS Things, and VxWorks and has support for x86_32, x86_64, Arm, and MIPS [3] . Like Wasmachine, it uses an AOT approach to improve speed. This project's work uses the WAMR Porting Guide to port WAMR to a non-supported platform, Mbed OS.
Team Members and Contributions
-
Arelys Navarro
- Porting Mbed to Arduino - File configuration, testing, and compiling.
- Using WASM3 - Debugging
- Research - References reserch, timing comparisons of other implementations, AOT vs JIT research
- Final Documentation - Presentation, report
-
Howard Xie
- Using WASM3
- Adapted Wasm3 to our project
- Wrote program and compiled to WebAssembly
- Ran WASM program on Arduino using Wasm3 interpreter
- Recorded timing for evaluation
- Final Documentation - Presentation, report
-
Utsav Munendra
- Ran WAMR on Zephyr OS
- Combined CMake files of WAMR and Mbed
- Coded the platform API layer of WAMR for Mbed
- Wrote scripts, made graphs, managed Git repo
- Website code and content
- 🔥Burnt off metal pads on two Arduino boards while soldering🔥
Thanks a lot to Botong Ou for answering so many of our questions about working with WAMR and Zephyr.