fix(gc): subtract live from-space bytes, not the block high-water, in a copied minor (#7901) - #7943
Conversation
📝 WalkthroughWalkthroughChangesGC live from-space accounting
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant NonMovingSweep
participant ArenaCensus
participant CopiedMinor
participant HeapAccounting
NonMovingSweep->>ArenaCensus: record total and live from-space bytes
CopiedMinor->>ArenaCensus: read live from-space bytes
CopiedMinor->>HeapAccounting: subtract live from-space and add survivors
HeapAccounting->>ArenaCensus: record copied-minor census
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
… a copied minor A non-moving sweep publishes an exact aggregate live census that excludes the dead objects left as holes beside a survivor, but leaves those holes inside the block offsets copying_from_space_in_use_bytes() sums. The next copied minor subtracted that high-water from the exact census, charging the same garbage twice; saturating_sub then hid the negative result by erasing unrelated old-generation occupancy from heapUsed and major-GC pacing. The sweep now publishes the live from-space share alongside the total, the census stores it with the from-space high-water at the same instant, and the copied minor subtracts the derived live figure.
ce1cb9e to
7a22d3f
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
changelog.d/7943-live-from-space-census.md (1)
1-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReduce this fragment to one release-note entry.
Keep the shipped behavior: copied minor GC now preserves accurate live-byte accounting after non-moving sweeps.
Remove internal formulas, symbol names, issue history, and unrelated comment-cleanup details. Based on learnings, changelog fragments must describe final shipped behavior as one coherent release-note entry.
🤖 Prompt for 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. In `@changelog.d/7943-live-from-space-census.md` around lines 1 - 49, Rewrite the changelog entry as one concise release note focused on the shipped behavior: copied minor GC now preserves accurate live-byte and heap accounting after non-moving sweeps. Remove implementation formulas, internal symbol names, issue references, regression-test details, assertions, and unrelated comment-cleanup information.Source: Learnings
🔇 Additional comments (7)
crates/perry-runtime/src/arena/stats.rs (1)
14-20: LGTM!Also applies to: 31-32, 45-73, 75-103
crates/perry-runtime/src/arena/mod.rs (1)
95-99: LGTM!Also applies to: 127-127
crates/perry-runtime/src/arena/reset.rs (1)
91-101: LGTM!crates/perry-runtime/src/gc/oldgen.rs (1)
138-143: LGTM!Also applies to: 771-786, 1088-1094, 1273-1273, 1339-1341, 1374-1375, 1510-1521
crates/perry-runtime/src/gc/cycle.rs (1)
990-992: LGTM!Also applies to: 1944-1954
crates/perry-runtime/src/gc/copying.rs (1)
1371-1373: LGTM!Also applies to: 1789-1792, 1813-1842
crates/perry-runtime/src/gc/tests/heap_accounting.rs (1)
108-216: 🩺 Stability & Availability
⚠️ Unverified finding
Sandbox verification was unavailable.Run this regression test serially.
Use
RUST_TEST_THREADS=1when validating this test becauseperry-runtimetests are not parallel-safe.As per coding guidelines,
crates/perry-runtime/**/*.rs: “perry-runtime's tests are not parallel-safe — run themRUST_TEST_THREADS=1.”
🤖 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.
Nitpick comments:
In `@changelog.d/7943-live-from-space-census.md`:
- Around line 1-49: Rewrite the changelog entry as one concise release note
focused on the shipped behavior: copied minor GC now preserves accurate
live-byte and heap accounting after non-moving sweeps. Remove implementation
formulas, internal symbol names, issue references, regression-test details,
assertions, and unrelated comment-cleanup information.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 98c2a7c4-b25f-4daf-a605-e54e29385dbc
📒 Files selected for processing (8)
changelog.d/7943-live-from-space-census.mdcrates/perry-runtime/src/arena/mod.rscrates/perry-runtime/src/arena/reset.rscrates/perry-runtime/src/arena/stats.rscrates/perry-runtime/src/gc/copying.rscrates/perry-runtime/src/gc/cycle.rscrates/perry-runtime/src/gc/oldgen.rscrates/perry-runtime/src/gc/tests/heap_accounting.rs
Closes #7901.
A full or non-moving sweep publishes
sweep.arena_live_bytes, an object-walkcensus that excludes the dead objects left as holes beside a survivor. It
cannot reset those survivors' blocks, so the holes stay inside the block offsets
copying_from_space_in_use_bytes()sums. The next copied minor computedwhich removes those holes a second time.
saturating_subthen hides thearithmetic failure: when the young high-water exceeds unrelated old live bytes it
erases old-generation occupancy from
heapUsedand from major-GC pacingaltogether, and the error persists into the next census.
Fix
The sweep publishes the live from-space share alongside the total
(
SweepTraceStats::arena_live_from_space_bytes, accumulated inArenaSweepObjectsState::keep_live_object— the one funnel thecensus-publishing sweep routes live objects through, gated on a block-index test
against Eden plus the active survivor).
record_arena_live_censusstores it withthe from-space high-water at the same instant, and
arena::arena_live_from_space_bytes()derives the current from-spacecontribution as
census.from_space_live + (high_water_now − census.high_water),clamped to the current high-water. The copied minor subtracts that.
A copied minor publishes
None— "from-space is compacted by construction":after the flip Eden is empty and the new active survivor holds only the copies,
so live equals high-water and the old and new derivations agree. That is why
copying_minors_preserve_prior_promotions_in_the_live_censusis unchanged.Two
debug_asserts guard the subtraction: live from-space bytes cannot exceedthe from-space high-water, nor the whole live census. A high-water subtraction
can no longer silently consume unrelated generations.
Test
heap_accounting::copied_minor_after_a_non_moving_sweep_does_not_subtract_dead_holes_twiceseeds an old live cohort, fills Eden with garbage plus one rooted survivor, runs
a non-moving full sweep, then a copied minor. It asserts
live from-space bytes by at least half a block, or the two formulas coincide
and a green run would prove nothing;
this exact state;
heapUsed, and pacing reads the samecorrected number.
Collateral
gc/cycle.rsandgc/oldgen.rswere both within 6 lines of the 2000-line gate.Reclaimed by collapsing an allocate-black paragraph duplicated verbatim in
GcCycleState::new_fullandnew_minor_fallback, and by deleting an 18-linedescription in the legacy
sweep_arena_objectsof a "two-phase probe-then-track"strategy the code no longer implements — the very next line already contradicted
it.
Summary by CodeRabbit
Bug Fixes
Tests