Encode output modules in parallel - #58
Conversation
The output modules are independent: each ModuleEmitState borrows the shared EmitState immutably and encodes its own module. Encoding them with a rayon parallel iterator keeps the output order (indexed collect). Measured on a 2.39 GB input with 6,720 output modules (384-core host): the encoding phase drops from 46.0 s to 2.8 s and the whole transform from 72 s to 29 s. RelocInfo's warn-once invalid_reloc_warn cell becomes a std::sync::OnceLock so the shared state is Sync; behaviour is unchanged (the warning still fires once). Output equivalence was verified functionally on that module: every emitted module passes wasm-tools validate and wasm-bindgen 0.2.127 accepts the emitted main module. A byte comparison is not meaningful here: identical serial runs already differ run-to-run (hash-map iteration order), before this change.
I fixed a bunch of this behaviour in #47 which was not in a released version yet. If you are comparing against the git version and still find unstable output, that is a separate bug. Nice wins overall. I was looking into a more involved parallelisation approach with a jobserver protocol a few months ago instead of just spreading over as many cores as rayon guesses there are, but realised that the build tools don't expose this anyway ( Are you looking into multi-threading for the dependency graph analysis? I expect this to be a bit more involved, since the algo choice is not so clear from a preliminary literature dive. If you want, we can have that as a separate PR. |
Problem
emit_modulesencodes every output module serially. On large inputs this phase dominates the whole transform: on a 2.39 GB module with 6,720 output modules (a large Leptos application, split via cargo-leptos), the phase timings areChange
The output modules are independent — each
ModuleEmitStateborrows the sharedEmitStateimmutably and encodes only its own module — so encode them with a rayon parallel iterator. The indexed collect keeps theoutput_modulesorder.RelocInfo's warn-onceinvalid_reloc_warncell becomes astd::sync::OnceLockso the borrowed state isSync; the warning still fires once.On the module above the encoding phase drops from 46.0 s to 2.8 s and the whole transform from 72 s to 29 s (384-core host; smaller hosts gain proportionally to core count).
Verification
cargo test --workspaceinintegration/(host leg) passes; I could not run the browser-mode wasm leg locally, so CI is the authority there.wasm-tools validate, andwasm-bindgen0.2.127 accepts the emitted main module.