How to reduce size of WASM binary?

1.4k Views Asked by At

I have a project written in C++, and the platform to be deployed in has a limitation of 256KB of binary size.

The toolchain is wasi-sdk-16.0 clang++, we use this compiler to compile the source code into binary in WASM format. In this step we compile the sources with the following CXX_FLAGS.

-fstack-protector-strong -Os -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security -Wl,-z,relro,-z,now -Wno-psabi

Then we strip the binary with

strip -s output_binary.wasm

After steps above, the compiled binary size in this step is 254KB.

Then we use wamrc in WAMR to compile the WASM binary with AOT runtime, the command is shown below.

wamrc --enable-indirect-mode --disable-llvm-intrinsics -o output.aot output.wasm

the output binary size become 428KB, much bigger than the limitation (256KB).


After google'd, I use wasm-opt to reduce size,

wasm-opt -Oz output.wasm -o output.wasm

The size become 4KB smaller. (almost useless)


I tried to comfirm how much does my code affects the binary size, so I write simple minimum sample code just called the standard c++ library, as the following,

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1,2,3,4,5};
    for (auto v: vec) {
        std::cout << v << " ";
    }
}

The binary size after compiled has alrealy become 205KB.


I also tried to use a binary size profiler (twiggy) to track the size of each part of the bianry, but the tool failed to open this binary.


So I want to ask

  1. While just including two standard C++ headers makes the binary size reach the size limitation, how can I strip the C++ standard library with the function I really use(I cannot use strip unused function flag because my project is a library provide to others), or is really the c++ standard library affected the binary size?

  2. Is there any other compiler flags, or strip flags, or any other optimization tools can significantly reduce the binary size?

2

There are 2 best solutions below

1
On BEST ANSWER

I solve this issue with just replacing iostream and fstream to cstdio. It reduces size from 254KB to 85KB, because there contains too many templates in iostream.

Using iostream Count of functions (with readelf -Ws) Size of Binary
Yes 685 254KB
No 76 85KB

While specifying compiler flags such as -Oz also reduces some size, but the main factor is too many codes were generated from templates. So, do not use C++ stream API (and any other template-heavy general-purpose libraries) when there are binary size limitations. (C libraries are always worth to believe.)

0
On

One of the things I didn't see mentioned in your post is wabt's wasm-strip. I am not familiar enough with it to know if it does more than the simple strip command, but maybe it is worth a try. You can install it with apt install wasm-strip on a Debian system.

From the few micro-benchmarks I see on the internet, C++ wasm binaries have large overhead. For a totally-not-scientific slide you can watch this.

If, for whatever reason, you cannot work the language to produce smaller binaries, you may try to optimize also at the link level, as busybox does.