Making Good On Momo's Compile-Time Promise
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.