Description
Problem
This is a spin-off from #4011 ("dx serve stalls").
I've researched this some more, and have some surprising findings.
First, I've let dx serve
run to completion, to make sure the project is fully built, and the cache is warmed up.
Then, I've pressed r
to rebuild the project. This is that result:
14:37:20 [dev] Full rebuild: triggered manually
14:37:34 [dev] Build completed in 2289ms
╭────────────────────────────────────────────────────────────────────────────────────────── /:more ╮
│ App: ━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎉 1.3s Platform: Web │
│ Bundle: ━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎉 12.3s App features: ["web"] │
│ Status: Serving bifrost-frontend 🚀 13.6s Serving at: http://127.0.0.1:8123 │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
So it takes 12.3s
to bundle, but only 1.3s
to recompile! This seems excessive.
After some work with strace
, I found the culprit - it's wasm-bindgen:
/home/chrivers/.local/share/dioxus/wasm-bindgen/wasm-bindgen-0.2.100
To compare, I cloned wasm-bindgen
, and did a local compile in release mode.
After placing the resulting binary on top of the one dx
calls, this is the result:
14:38:33 [dev] Full rebuild: triggered manually
14:38:38 [dev] Build completed in 1934ms
╭────────────────────────────────────────────────────────────────────────────────────────── /:more ╮
│ App: ━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎉 1.0s Platform: Web │
│ Bundle: ━━━━━━━━━━━━━━━━━━━━━━━━━━ 🎉 2.4s App features: ["web"] │
│ Status: Serving bifrost-frontend 🚀 3.3s Serving at: http://127.0.0.1:8123 │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
Obviously, this is much, much better.
Let's take a look at individual timing.
Stock:
⎋ Timing: 557% cpu --[ 3,185s total: 3,516s user + 14,248s krnl ]--
⩧ Memory: 935 MB max --[ 0 majpf + 414113 minpf ]--
⦺ Events: yield 91441 + forced 1712 // input 0 + output 80224
Locally compiled:
⎋ Timing: 280% cpu --[ 1,716s total: 1,840s user + 2,975s krnl ]--
⩧ Memory: 934 MB max --[ 0 majpf + 197682 minpf ]--
⦺ Events: yield 98929 + forced 374 // input 0 + output 80224
The stock version is spending most of the time in kernel code. That seems weird.
Related to the strace
work, I stumbled on something strange. The version of wasm-bindgen
that comes with Dioxus performs an insane number of allocations with mmap()
:
strace -f -tt -e trace=file,execve,desc -s 1024 \
/home/chrivers/.local/share/dioxus/wasm-bindgen/wasm-bindgen-0.2.100 \
--target web --keep-debug \
--out-name bifrost-frontend \
--no-typescript \
--out-dir ${PROJECT_TARGET}/dx/bifrost-frontend/debug/web/public/wasm-bindgen \
${PROJECT_TARGET}/wasm32-unknown-unknown/wasm-dev/bifrost-frontend.wasm \
|& grep mmap | wc -l
91054
That's 91054 system calls to mmap()
! When looking through the output from strace
, almost all of these are 4K or 8K allocations. It seems something is wrong with the memory allocator.
Here's the locally compiled version:
strace -f -tt -e trace=file,execve,desc -s 1024 \
wasm-bindgen/target/release/wasm-bindgen \
--target web --keep-debug \
--out-name bifrost-frontend \
--no-typescript \
--out-dir ${PROJECT_TARGET}/dx/bifrost-frontend/debug/web/public/wasm-bindgen \
${PROJECT_TARGET}/wasm32-unknown-unknown/wasm-dev/bifrost-frontend.wasm \
|& grep mmap | wc -l
183
Just 183 calls to mmap()
, which is fine.
Expected behavior
I expect the wasm-bindgen
version that comes with dioxus to be approximately as fast as the one that I can compile myself 😄
Environment:
- Dioxus version:
dioxus = { version = "0.6.0", features = [] }
- Rust version:
rustc 1.85.0 (4d91de4e4 2025-02-17)
- OS info:
Debian Stable (12.10)
- App platform:
web