ci(bench): continuous wasm dashboard shard vs @bokuweb/zstd-wasm - #372
Conversation
Track the WebAssembly build (simd128 + scalar) against the most popular npm wasm zstd, @bokuweb/zstd-wasm, on the gh-pages perf dashboard over time — previously the wasm-vs-competitor comparison ran only locally as a pre-publish gate. - Add push-to-main `bench-wasm` CI shard: builds the npm payloads, runs `node zstd-wasm/bench/bench.mjs`, captures its REPORT* lines, and publishes a dedicated wasm timeseries to gh-pages. Gated on a new `wasm_core` path filter and independent of the rust_core-gated native matrix, so a wasm-only change still updates the dashboard. Publishes only benchmark-wasm.json (index.html stays owned by benchmark-pages / pages-only), so the two publishers write disjoint files. - Add parse-wasm-bench.py (REPORT / REPORT_DICT engine triplet -> records with ratio + compress/decompress throughput) and merge-wasm-bench.py (accumulate into persisted benchmark-wasm.json, 180-day retention, dedup per snapshot). - Add a WebAssembly section to the dashboard plotting compress speed, decompress speed, and output ratio per engine over time, with our throughput shown as a multiple of bokuweb. Degrades gracefully when no wasm data is published yet. - Document the wasm comparison in BENCHMARKS.md + README.md. Closes #366
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a push-to-main wasm benchmarking shard plus parsing and merge scripts, publishes merged wasm timeseries to gh-pages, and renders an independent WebAssembly comparison card on the dashboard (simd128/scalar vs ChangesWasm Benchmarking Pipeline
Sequence Diagram(s)sequenceDiagram
participant CI as CI (bench-wasm)
participant Parser as parse-wasm-bench.py
participant Merger as merge-wasm-bench.py
participant GHPages as gh-pages
participant Dashboard as Dashboard (Browser)
CI->>CI: Build npm wasm payloads
CI->>CI: Run Node benchmark harness
CI->>Parser: Parse REPORT* stdout
Parser-->>CI: benchmark-wasm-run.json
CI->>Merger: Load run + existing history
Merger-->>CI: Deduplicate, sort, retain
Merger-->>GHPages: benchmark-wasm.json (merged)
Dashboard->>GHPages: Fetch benchmark-wasm.json
GHPages-->>Dashboard: Timestamped engine records
Dashboard->>Dashboard: Aggregate by snapshot
Dashboard->>Dashboard: Build Chart.js datasets
Dashboard->>Dashboard: Optional: ours÷bokuweb ratio
Dashboard-->>Dashboard: Render chart + legend
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/bench-dashboard/index.html:
- Around line 2269-2275: The current fetch for "./benchmark-wasm.json" treats
any non-ok response as the empty-state; change the logic so only a 404 triggers
the empty-state path (call renderWasmChart() and bindWasmControls()); for other
non-2xx statuses surface the failure (e.g., throw or call
console.error/processLogger and render an error UI) so real publish/runtime
failures aren't masked. Update the fetch handling around the response.ok check
to explicitly check response.status === 404 and otherwise handle/report the
error, keeping renderWasmChart and bindWasmControls as the 404-only branch.
- Around line 367-368: The new canvas element with id `#chart-wasm` is not
included in the shared sizing CSS selector (`#chart`, `#chart-profile`,
`#chart-aggregate`), so it uses the browser default height; update that selector
to include `#chart-wasm` (i.e., change "`#chart`, `#chart-profile`, `#chart-aggregate`"
to include "`#chart-wasm`") so the `#chart-wasm` canvas inherits the same sizing
rules as `#chart`, `#chart-profile`, and `#chart-aggregate`.
In @.github/scripts/merge-wasm-bench.py:
- Around line 48-55: The load_records function currently calls
json.loads(p.read_text()) which will raise JSONDecodeError on corrupted JSON;
update load_records to catch json.JSONDecodeError (and optionally ValueError for
compatibility) around the json.loads call, log or warn that the existing
benchmark-wasm.json is corrupted, and return an empty list so merging continues
with fresh history; keep the existing early returns for missing path/file, and
only wrap the payload parsing (the json.loads and payload.get("records", []))
inside the try/except handling in load_records.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 840353a7-7d86-41c7-ac3c-c7dd760b0381
📒 Files selected for processing (6)
.github/bench-dashboard/index.html.github/scripts/merge-wasm-bench.py.github/scripts/parse-wasm-bench.py.github/workflows/ci.ymlBENCHMARKS.mdREADME.md
- index.html: size the new #chart-wasm canvas via the shared 440px rule (was falling back to the browser default canvas height). - index.html: only treat a 404 from benchmark-wasm.json as the "no wasm data yet" empty state; surface any other non-2xx (500/403/ broken publish) as an error instead of masking it. - merge-wasm-bench.py: tolerate a corrupted persisted benchmark-wasm.json (warn + rebuild from this run's records) so one bad file can't wedge every future wasm publish.
Summary
Tracks the WebAssembly build (
simd128+scalar) against the most popular npm wasm zstd,@bokuweb/zstd-wasm, on the gh-pages perf dashboard over time. Previously the wasm-vs-competitor comparison ran only locally as a pre-publish gate, so a wasm perf/ratio regression would only surface if someone re-ran the bench by hand.What changed
bench-wasm(ci.yml): push-to-main only, gated on a newwasm_corepath filter (zstd/**,zstd-wasm/**,Cargo.*, toolchain). Builds the npm payloads, runsnode zstd-wasm/bench/bench.mjs, captures itsREPORT*lines, and publishes a dedicated wasm timeseries to gh-pages. Independent of therust_core-gated native matrix so a wasm-only change still updates the dashboard. Publishes onlybenchmark-wasm.json(index.html stays owned bybenchmark-pages/pages-only), so the two publishers write disjoint files and never race; a rebase-retry loop guards the rare concurrent-push case.parse-wasm-bench.pyturns theREPORT/REPORT_DICTengine triplet (ours-simd128,ours-scalar,bokuweb) into records carrying ratio + compress/decompress throughput;merge-wasm-bench.pyaccumulates them into the persistedbenchmark-wasm.jsonwith 180-day retention and per-snapshot dedup.index.html): a dedicated WebAssembly section plots compress speed, decompress speed, and output ratio per engine over time, with our throughput shown as a multiple of bokuweb (>1 = faster). Degrades gracefully when no wasm data is published yet — the rest of the dashboard is unaffected.Acceptance criteria
REPORT*lines captured + aggregated.dev/benchdashboard shows wasm simd128/scalar vs bokuweb ratio + speed over time.Testing
All verified against real output, not synthetic:
node bench.mjs(exit 0, all roundtrips ok).node --check(JS),py_compile(scripts), YAML validity (ci.yml).Note on the issue plan
The issue suggested extending
aggregate-bench-levels.py/merge-benchmarks.py, but those run insiderust_core-gated jobs — routing wasm through them would break the "push-to-main runs the wasm shard" criterion (a wasm-only change wouldn't update the dashboard). Implemented as a self-contained wasm pipeline instead; the goal (continuous wasm tracking) is fully met.Closes #366
Summary by CodeRabbit
New Features
Documentation