WebAssembly VM Not Viable for a Low Memory Embedded Language?
WebAssembly (WASM) is a fast, portable and lightweight execution environment, but it fails to meet memory constraints for our goal of building PageZest - an ultra-light CMS that aims to run within 10 MB total RAM memory. Our target is to embed a language that takes up only 500 KB of memory overhead in RAM.
We performed an experiment with WASM compiled binary and ran it on tinyWASM
and wasmi
runtimes. Our benchmark shows that tinyWASM requires runtime overhead of approximately 1.5 MB just to initialize the embedded language code. This is highly undesirable because it eats up 20%-30% of our RAM before running any significant code. However, Wasmi performed even worse, nearly doubling the memory consumption of TinyWASM, making it unsuitable for our use-case.
Every MB of memory wasted in overhead can be used for caching, indexing or handing more concurrent requests. We need some better alternative to reduce the overhead and bring it in few KBs.
Why TinyWASM?
We choose TinyWASM as our WASM execution environment because TinyWasm is designed to be as small as possible without significantly compromising performance or functionality. However, we needed to test whether it meets our strict memory requirements.
Measuring TinyWASM Memory Overhead
To quantify the memory footprint of a WASM instance in Rust, we used the following approach.
1 . Measuring Process Memory Usage
The function get_process_memory
determines the memory usage of the process by retrieving its Resident Set Size (RSS), which represents the non-swapped physical memory used by the process.
2 . Loading and Executing the WASM module
The call_tiny_wasm
function reads a compiled WASM file (debug.wasm
), loads it into memory and invokes exported function (add
).
3 . Benchmarking tinyWASM Overhead
The main
function captures memory before and after running a WASM module and calculates the overhead.
Observed Results
On running the benchmark the approximate results obtained were as below
Iteration | Memory Usage (kB) |
---|---|
Before WASM Instantiation | 3156 kB |
After 1st Iteration | 4728 kB |
After Subsequent Iteration | 4278 kB |
Overhead | 1572 kB |
Interestingly, only the first iteration showed a significant increase in memory usage. All subsequent iterations resulted in 0 Kb additional overhead. This suggests that the WASM module is instantiated once and reused across calls, preventing further memory allocation spikes.
Why was memory high only in the first iteration?
- Module Loading Overhead : The first iteration involves loading and parsing the module, increasing memory consumption.
- Runtime Initialization : WASM requires setting up execution state, including stacks and memory pages.
- Reusing Execution Context : Once loaded, subsequent calls leverage the existing instance, preventing further memory increases.
WASM's runtime cost makes it unsuitable to be used for PageZest. A better execution model is necessary to maximize the available RAM.
Benchmarking Wasmi Memory Overhead
To evaluate an alternative to tinyWASM, we also performed the same benchmark on wasmi
which is interpreted WebAssembly engine.
The call_wasmi_wasm
function loads the debug.wasm
file.
And it is benchmarked within main function when given wasmi
flag.
Observed Results
On running the similar benchmarks on the wasmi
, the approximate results obtained were as follows:
Iteration | Memory Usage (kB) |
---|---|
Before WASM Instantiation | 4024 kB |
After 1st Iteration | 7296 kB |
After Subsequent Iteration | 7296 kB |
Overhead | 3272 kB |
Compared to tinyWASM, Wasmi had a significantly higher memory overhead, making it even worse choice for PageZest goal. Wasmi is a pure interpreter and does not leverage compilation optimizations.
Question for Audience
Is the RAM goal of 10 MB realistic??
Is there any VM that will allow embedded language using only 500 kb or less?
Please email in suggestions to eng at pagezest dot com
Next directions
Given that both TinyWASM and Wasmi fail to meet our requirements, we need to explore alternatives that might offer better memory efficiency. Options include other WASM runtimes or considering another embedded languages other than Assembly Script.