Making Good On Momo's Compile-Time Promise

28 October 2019

When I announced momo, I wanted its users to save both binary size and compile time while keeping their code simple. I succeeded in the first goal, but failed regarding the second. The reason was that momo requires syn and quote which (unless you have other proc macros in your dependencies) add their own compile time to yours.

David Tolnay was apparently so frustrated with this problem that he took the rust-wasm runtime, added a shim to expand proc macros and put everything together under the watt project. Now I have taken momo and converted it to use watt under the hood. To the user, this shouldn’t change much, but speed up the build a bit.

To measure this, I have my check example which is quite small, so the compile time is dominated by compiling either syn or watt. The following table shows the output of time cargo run --example check (with or without --release ) measuring a clean compile:

profile debug+syn release+syn debug+watt release+watt real 10,714s 18,081s 5,786s 6,510s user 23,174s 54,530s 9,483s 18,269s sys 0,892s 0,618s 0,367s 0,257s

So this roughly halves the compile time, though the effect might be less pronounced if you have more dependencies (because of parallelism wins) or use momo more than I do in the example. The effect is larger on release builds.

The wasm blob by default is 2.8M. I got it down to 2.2M by activating LTO and setting codegen-units=1 . Furthermore, through the use of wasm-strip I was able to reduce it to 760K, and using wasm-opt -Os brought it down to 670K. This also massively reduced compile time, even more so with --release :

profile debug+watt release+watt real 1,998s 0,597s user 1,822s 0,516s sys 0,157s 0,112s

To obtain wasm-strip , you need to clone the Web Assembly Binary Toolkit. Building it requires cmake, make and a C compiler. wasm-opt is part of the binaryen package, which similarly needs to be built and installed.

I hear that using wasm-opt -Oz will reduce size further, at the cost of some runtime performance, so I left it at -Os . I also did not set panic=abort to ease debugging. I may change this later when momo has matured a little, but for now, this is plenty fast for my use case.

In Other News

I also added #[inline(never)] and #[allow(unused_mut)] attributes to the inner functions. This ensures our inner functions aren’t inadvertently inlined, which would counteract the effect of using momo, and quells warnings on AsMut arguments which need to be declared mutable, but would warn on the inner fn .

So, if you held off from using momo because you were underwhelmed by its compile time, now would be a good time to try again.