sagemathinc / cowasm

CoWasm: Collaborative WebAssembly for Servers and Browsers. Built using Zig. Supports Python with extension modules, including numpy.
https://cowasm.org
BSD 3-Clause "New" or "Revised" License
482 stars 23 forks source link

Optimize wasm files with wasm-opt #39

Closed kripken closed 1 year ago

kripken commented 1 year ago

I noticed that the wasm files on the website are not optimized with wasm-opt. E.g. running wasm-opt -O on b5423d0ccb3dd1ef21ca.wasm leads to a 5% code size reduction. (There might also be a speed benefit, as e.g. it ends up removing around 10% of total functions - unless those were entirely unused before, they'd be inlined now.)

Not a big deal of course, just wanted to mention this as a possible improvement. Also it might be nice to port wasm-opt itself with CoWasm, and then optimize the website with those.

Really cool project btw!

williamstein commented 1 year ago

noticed that the wasm files on the website are not optimized

That's correct. Many thanks for your suggestion, and I will definitely figure out how to add wasm-opt to the release workflow.

Really cool project btw!

Thanks! I'm totally star struck that you had a chance to look at it. I'm a huge fan of your work!

williamstein commented 1 year ago

Note to myself: Every wasm file in CoWasm (except the file "kernel.wasm" that is loaded first) is a dynamic -fPIC library. This makes it so the wasm files have no redundant code in them, and enables doing things like fork-exec in a single wasm process (e.g., to support shells, subprocesses, etc.). So I had to use the --enable-mutable-globals flag. This was slightly difficult for me to figure out. I wonder if the error here could be modified to also mention the enable-mutable-globals flag?

~/cowasm/packages/kernel$ wasm-opt -O build/test/hello.wasm -o a.wasm
[wasm-validator error in module] unexpected true: Imported global cannot be mutable, on 
gimport$0
Fatal: error validating input
~/cowasm/packages/kernel$ 

~/cowasm/packages/kernel$ wasm-opt --enable-mutable-globals -O build/test/hello.wasm -o a.wasm
# works
williamstein commented 1 year ago

Also it might be nice to port wasm-opt itself with CoWasm

Some motivation for this is that native wasm-opt is potentially 10x faster due to multithreading, etc.

~/cowasm/packages/python-wasm$ time ~/upstream/binaryen-release/binaryen-version_110/bin/wasm-opt --enable-mutable-globals -O dist/python.wasm -o python.opt.wasm

real    0m3.325s
user    0m10.788s
sys     0m0.123s
# This is the webassembly version of wasm-opt
~/cowasm/packages/python-wasm$ time ../../bin/wasm-opt  --enable-mutable-globals -O dist/python.wasm -o python.opt2.wasm

real    0m28.216s
user    0m29.319s
sys     0m0.115s

This is relevant to me, since my matrix of supported build platforms is larger than the list of binaries provided by Binaryen at https://github.com/WebAssembly/binaryen/releases; in particular, that is missing arm64 Linux, which I support.

On the other hand, note that binaryen maybe takes 5+ minutes to build from source (since it's a big C++ program), and that's a lot longer than other components of CoWasm. So keep that in mind.

sloccount .
Totals grouped by language (dominant language first):
cpp:         161545 (89.00%)
ansic:        14120 (7.78%)

This does not work for me using the current version of Zig on macos:

~/upstream/binaryen-release/binaryen-version_110$ CC="zig cc" CXX="zig c++" cmake . -DBUILD_TESTS=OFF && time make
...
zig: error: overriding '-mmacosx-version-min=10.14' option with '-target aarch64-unknown-macosx13.0.0-unknown' [-Werror,-Woverriding-t-option]

So building binaryen with zig might also be something that would need to be fixed. Binaryen of course builds fine with XCode.

I realize you may have meant "build binaryen to WebAssembly via CoWasm", and above here I'm taking notes about building it natively for use in the CoWasm build toolchain instead.

williamstein commented 1 year ago

I tried asyncify on kernel.wasm and the python3.11.wasm binary that is directly build by cPython (4.6MB):

- Asyncify makes kernel.wasm over 50% larger, as expected. 
- It takes **a very long time** to run `wasm-opt --asyncify` on python.wasm, e.g.,

with the wasm version of binaryen I gave up after 10+ minutes. The native version took 16 minutes to run successfully. The asyncified version takes 42% longer to run my benchmark suite (40.5 seconds instead of 28 seconds). So asyncify is not a realistic option for a program as complicated as Python, at least not without more work.

kripken commented 1 year ago

I wonder if the error here could be modified to also mention the enable-mutable-globals flag?

Good point, thanks! I'll make a note to look into that.