Skip to content
This repository was archived by the owner on Oct 20, 2026. It is now read-only.

web-render: ship the engine wasm with fat LTO (−1.7 MB); 9 MiB size gate; 0.1.0-canary.18 - #8

Merged
drietsch merged 2 commits into
mainfrom
perf/wasm-size-profile
Oct 17, 2026
Merged

drietsch merged 2 commits into
mainfrom
perf/wasm-size-profile

Conversation

@drietsch

@drietsch drietsch commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Shrinks the paged.web engine wasm (bin/blitz_web_bg.wasm) by 1.7 MB with a dedicated build profile, and tightens its size gate so growth is caught.

What changes

  • packages/web-render/Cargo.toml: a [profile.wasm-release] profile (inherits = "release", lto = "fat", codegen-units = 1). The default release profile has no cross-crate LTO and 16 codegen units. Native tests and benches keep their profiles.
  • scripts/build-wasm.sh and scripts/build-wasm-perf.sh build with --profile wasm-release. wasm-opt -Oz stays.
  • Size gate: build-wasm.sh now reads its ceiling from the manifest's capabilities.wasm[blitz].maxBytes, so the two can't drift. That value drops from 64 MiB to 9 MiB (9 437 184 bytes), about 4.7% above the new size.
  • @paged-media/web goes to 0.1.0-canary.18. The engine sources changed (Cargo.toml) and so did the manifest, so package-hash.mjs --check needs the bump. Merging publishes canary.18.
  • Docs: architecture.md and the ADR 308 row in docs/README.md now give the new ceiling. status.md and the perf record get the measured sizes.

Size

Built the way the publish workflow builds it: build-wasm.sh --engine with Rust 1.93.0, wasm-bindgen 0.2.125 (from Cargo.lock) and binaryen 119.

raw bytes brotli
before (default release profile) 10 723 939 2 612 273
after (wasm-release) 9 016 823 2 496 172
delta −1 707 116 (−15.9%) −116 101

Built in CI for this PR (the vitest job): 9 015 481 bytes (brotli 2 497 009). The published 0.1.0-canary.17 wasm is 10 723 633 bytes, so CI to CI the difference is −1 708 152 bytes. Local and CI builds differ only by a few hundred bytes of embedded build paths.

No slowdown

I timed the five perf workloads from tests/common/workloads.rs in node against both wasm builds through the exported entries. Each run did 10 alternating rounds of 40 iterations per workload on one machine, and the table gives the median of the round medians:

workload before after delta
article-40, 1 frame 5.16 ms 4.84 ms −6.2%
article-40, flow into 4 8.90 ms 8.82 ms −0.8%
article-40, flow into 12 21.40 ms 21.12 ms −1.3%
table-300, 1 frame 12.18 ms 12.16 ms −0.2%
styled-runs-200, 1 frame 2.10 ms 2.03 ms −3.2%
cold boot (instantiate) 9.9 ms 8.7 ms

For every workload, the JSON output of the two builds is byte-identical. test/perf/perf-budgets.spec.ts with PERF_SHOW=1 (3 interleaved runs each) gives the same door, wasm-call and byte counts for both builds, and its wall-clock stays within noise.

Tests

  • REQUIRE_REAL_ENGINE=1 pnpm -r exec vitest run against the new wasm: web-bundle 339/339, web-conformance 103/103, web-model 290 passed (the 9 corpus-dependent tests skip, as in CI). Contract-import lint and typecheck are clean.
  • cargo fmt --check, clippy -D warnings for all three feature sets, cargo test --features blitz, cargo test and the perf_budgets count budgets all pass.
  • The gate fails on the old 10.7 MB wasm and passes on the new one.

🤖 Generated with Claude Code

drietsch and others added 2 commits October 17, 2026 09:05
…-canary.18

The engine wasm was built with cargo's default release profile: no
cross-crate LTO and 16 codegen units. A `wasm-release` profile (release,
lto = "fat", codegen-units = 1) used by scripts/build-wasm.sh and
scripts/build-wasm-perf.sh takes blitz_web_bg.wasm from 10 723 939 to
9 016 823 bytes (-1 707 116, -15.9%; brotli 2 612 273 -> 2 496 172), built
with the CI pins (Rust 1.93.0, wasm-bindgen 0.2.125, binaryen 119,
wasm-opt -Oz unchanged). The native tests and benches keep their profiles.

No slowdown: the five perf workloads, timed in node against both wasm
builds in alternating rounds, run 0-6% faster, and every workload's JSON
output is byte-identical between the two builds.

The size gate now reads its ceiling from the manifest's maxBytes for the
blitz wasm, lowered from 64 MiB to 9 MiB (9 437 184), so growth past the
current size plus ~4.7% fails the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
status.md gets an "Engine size" section: 9 015 481 bytes as CI builds it
(2 497 009 brotli), against 10 723 633 for the published canary.17 wasm,
and the 9 MiB manifest gate. The perf record gets the size and wall-clock
comparison of the release and wasm-release builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@drietsch
drietsch merged commit a6369f7 into main Oct 17, 2026
3 of 4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant