Skip to content

feat(gc): add opt-in GC statistics behind a gc-stats feature - #5613

Open
tarushmohindru wants to merge 4 commits into
boa-dev:mainfrom
tarushmohindru:gc-stats
Open

tarushmohindru wants to merge 4 commits into
boa-dev:mainfrom
tarushmohindru:gc-stats

Conversation

@tarushmohindru

Copy link
Copy Markdown
Contributor

This Pull Request is a part of #5567.

It changes the following:

  • Adds a gc-stats feature to boa_gc, forwarded by boa_engine and boa_cli. It is off by default and gates all new code.
  • Records per-thread statistics in BoaGc: collections, collections that ran finalize + second mark, cumulative bytes/objects allocated and freed, and wall time per collection phase plus total.
  • Adds boa_gc::stats() -> GcStats (a Copy snapshot) and boa_gc::reset_stats().
  • Adds $boa.gc.stats() and $boa.gc.resetStats() to the CLI debug object.
  • Adds tests in core/gc/src/test/stats.rs.

Design notes

  • Everything is behind the feature. Without gc-stats the collector is unchanged. std::time::Instant::now() panics on wasm32-unknown-unknown, so timing has to stay opt-in.
  • Separate from GcRuntimeData. Stats live in their own stats: GcStats field on BoaGc, so reset_stats() can't touch bytes_allocated or the collection threshold. runtime.collections is left as is (tests rely on it), and GcStats::collections is a separate counter that resets.
  • Shallow byte counts. Only size_of_val of each GcBox/EphemeronBox is counted, matching the existing bytes_allocated. Heap memory owned by values (e.g. a Vec's buffer) and the boxes backing WeakMaps are not counted. This is documented on GcStats.
  • Freed counts without touching sweep. Bytes and objects freed are computed from bytes_allocated and the heap lengths before and after the sweep, so the unsafe code is unchanged.
  • Phase timing uses a small private timed! macro that expands to the plain expression when the feature is off, which keeps collect() readable.
  • GcStats is #[non_exhaustive] so more counters can be added later without a breaking change.

Overhead

Release boa_cli built with and without --features gc-stats; V8 Richards and Splay from benches/scripts/v8-benches, 10 runs each, alternating builds. AMD Ryzen 5 5600H, WSL2, based on 9871775a. Higher is better; median with range.

Suite Off On Δ
Richards 233 (228–236) 230 (221–231) −1.3%
Splay 895.5 (877–901) 911.5 (886–921) +1.8%

Both differences are within code-layout noise: Splay is faster with stats enabled, and Richards performs zero collections and about 8k allocations in total, so the counters can't account for a 1.3% change. Happy for someone with a quieter setup to re-run these.

Example: Splay

With --features gc-stats --debug-object, printing $boa.gc.stats() after the run:

Collections 18 (all 18 ran finalize + second mark)
GC time ~970 ms of ~3.1 s wall time (~31%)
mark 574 ms
trace_non_roots 177 ms
sweep 130 ms
remark 55 ms
finalize 44 ms

This lines up with the perf estimate in #5567 (~36% of samples), and gives a direct data point for the Phase 1 NEEDS_FINALIZE discussion: every collection on Splay paid for finalize and a second full mark.

Testing

  • cargo test -p boa_gc and cargo test -p boa_gc --features gc-stats
  • cargo clippy --all-targets for boa_gc and boa_cli, with and without the feature

Add a `gc-stats` Cargo feature to `boa_gc` (forwarded by `boa_engine`)
that records per-thread collector statistics:

- collection count, and how many collections also ran the finalize and
  second mark phases
- cumulative bytes and objects allocated and freed
- time spent in each collection phase (trace_non_roots, mark,
  finalize, remark, sweep, weak map pruning) and in total

They are exposed through `boa_gc::stats()`, which returns a `GcStats`
snapshot, and `boa_gc::reset_stats()`. Byte counts are shallow: only
the size of each `GcBox`/`EphemeronBox` is counted. The existing
`bytes_allocated` accounting and the collection threshold are
unchanged.

All new code is behind the feature, which is off by default, so builds
without it are unchanged and `Instant::now()` is never compiled for
wasm32-unknown-unknown.

Part of boa-dev#5567.
Add a `gc-stats` feature to `boa_cli` that forwards to
`boa_gc/gc-stats` and exposes the collector statistics on the debug
object. `$boa.gc.stats()` returns a plain object with counters and
per-phase timings in milliseconds; `$boa.gc.resetStats()` clears them.

Part of boa-dev#5567.
@tarushmohindru
tarushmohindru requested a review from a team as a code owner October 24, 2026 17:26
@github-actions github-actions Bot added Waiting On Review Waiting on reviews from the maintainers C-Dependencies Pull requests that update a dependency file C-CLI Issues and PRs related to the Boa command line interface. C-GC Issue related to garbage collection labels Oct 24, 2026
@github-actions github-actions Bot added this to the v0.23 milestone Oct 24, 2026
@github-actions

Copy link
Copy Markdown

Test262 conformance changes

Test result main count PR count difference
Total 53,578 53,578 0
Passed 51,450 51,450 0
Ignored 1,648 1,648 0
Failed 480 480 0
Panics 0 0 0
Conformance 96.03% 96.03% 0.00%

Tested main commit: 9871775a4999591e27bbb026b92530bf43caef52
Tested PR commit: 1b4c8189130fb77ceeb85b8f4dd9ff6d3cb4d787
Compare commits: 9871775...1b4c818

@codecov

codecov Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.09%. Comparing base (6ddc2b4) to head (1b4c818).
⚠️ Report is 1083 commits behind head on main.

Files with missing lines Patch % Lines
core/gc/src/lib.rs 78.57% 6 Missing ⚠️
cli/src/debug/gc.rs 0.00% 5 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #5613       +/-   ##
===========================================
+ Coverage   47.24%   63.09%   +15.85%     
===========================================
  Files         476      536       +60     
  Lines       46892    60553    +13661     
===========================================
+ Hits        22154    38208    +16054     
+ Misses      24738    22345     -2393     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jasonwilliams jasonwilliams left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this took a while to look at

LGTM

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-CLI Issues and PRs related to the Boa command line interface. C-Dependencies Pull requests that update a dependency file C-GC Issue related to garbage collection Waiting On Review Waiting on reviews from the maintainers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants