Shrinking .wasm Size - Rust and WebAssembly (original) (raw)
- 1. Introduction
- 2. Why Rust and WebAssembly?
- 3. Background And Concepts
- 4. Tutorial
- 5. Reference
- 5.1. Crates You Should Know
- 5.2. Tools You Should Know
- 5.3. Project Templates
- 5.4. Debugging
- 5.5. Time Profiling
- 5.6. Shrinking .wasm Size
- 5.7. JavaScript Interoperation
- 5.8. Which Crates Will Work Off-the-Shelf with WebAssembly?
- 5.9. How to Add WebAssembly Support to a General-Purpose Crate
- 5.10. Deploying Rust and WebAssembly to Production
Rust and WebAssembly
For .wasm
binaries that we ship to clients over the network, such as our Game of Life Web application, we want to keep an eye on code size. The smaller our.wasm
is, the faster our page loads get, and the happier our users are.
How small can we get our Game of Life .wasm binary via build configuration?
With the default release build configuration (without debug symbols), our WebAssembly binary is 29,410 bytes:
$ wc -c pkg/wasm_game_of_life_bg.wasm
29410 pkg/wasm_game_of_life_bg.wasm
After enabling LTO, setting opt-level = "z"
, and running wasm-opt -Oz
, the resulting .wasm
binary shrinks to only 17,317 bytes:
$ wc -c pkg/wasm_game_of_life_bg.wasm
17317 pkg/wasm_game_of_life_bg.wasm
And if we compress it with gzip
(which nearly every HTTP server does) we get down to a measly 9,045 bytes!
$ gzip -9 < pkg/wasm_game_of_life_bg.wasm | wc -c
9045
- Use the wasm-snip toolto remove the panicking infrastructure functions from our Game of Life's
.wasm
binary. How many bytes does it save? - Build our Game of Life crate with and without wee_alloc as its global allocator. The
rustwasm/wasm-pack-template
template that we cloned to start this project has a "wee_alloc" cargo feature that you can enable by adding it to thedefault
key in the[features]
section ofwasm-game-of-life/Cargo.toml
:
[features]
default = ["wee_alloc"]
How much size does using wee_alloc
shave off of the .wasm
binary?
- We only ever instantiate a single
Universe
, so rather than providing a constructor, we can export operations that manipulate a singlestatic mut
global instance. If this global instance also uses the double buffering technique discussed in earlier chapters, we can make those buffers also bestatic mut
globals. This removes all dynamic allocation from our Game of Life implementation, and we can make it a#![no_std]
crate that doesn't include an allocator. How much size was removed from the.wasm
by completely removing the allocator dependency?