Skip to content

gc: 12_large_live_set is 13.6% slower at 0.5.1346 than 0.5.1280 with every collector counter flat #7610

Description

@proggeramlug

Surfaced by the #7554 ratchet repair (#7609), which re-pinned the baseline on the
pinned quiet host. This is the one cell that moved and is not explained by any
merged, documented decision, so it is being filed rather than absorbed into the pin.

The measurement

Same host (perry-macos, Mac mini M1, 8 GB), same toolchain (rustc/cargo 1.97.1,
Apple clang 21.0.0), same harness protocol (--repeats 7, warmup 1,
PERRY_NO_AUTO_OPTIMIZE=1, prebuilt static archives), median of 7:

12_large_live_set.wall_ms
pinned baseline 5e236e6e2 (0.5.1280, 2026-08-05) 3,056 ms — samples 3056.2, 3061.0, 3058.9, 3047.6, 3058.2, 3054.1, 3048.9
main 26b9c9d59 (0.5.1346, 2026-08-07) 3,471 ms — samples 3471.7, 3472.7, 3466.7, 3466.3, 3471.3, 3475.5, 3467.5

+13.58%. The two 7-sample clusters do not overlap (3,047–3,061 vs
3,466–3,476) and within-session spread is 0.27%, so this is not scheduler noise.
The pinned_host band on wall_ms is 10%, derived from a worst cross-session
median spread of 0.751%.

Why it is worth a look

Over the same window other probes got faster, so this is not a global
slowdown:

probe wall_ms 0.5.1280 → 0.5.1346
11_collect_at_depth 110.4 → 79.0 (−28.4%)
06_string_retention 83.4 → 75.4 (−9.6%)
12_large_live_set 3,056 → 3,471 (+13.6%)

And #7596 ("live-proportional collection budgets at both generations") reported
−7.4% wall_ms on this exact cell in its own both-arms A/B. So by that PR's own
evidence the regression is not #7596 — something else in 0.5.1280..0.5.1346 made
the largest-live-set probe 13.6% slower.

Retention and the collector counters on this probe are essentially unchanged over
the same window (heap_total_bytes +0.00%, promoted_objects +0.00%,
freed_bytes +0.00%, copied_objects −0.01%), which is what makes the wall-time
move odd: the collector appears to be doing the same work, more slowly.

Scope

wall_ms is gated under the pinned_host profile only — shared_ci marks it
non-gating because a shared runner cannot carry a band that tight. So this does
not block CI
, and #7609 pins it so the other 143 cells can gate again. It is
filed so that pinning is a recorded decision rather than a silent one.

Suggested method

Bisect wall_ms on this one probe across 0.5.1280..0.5.1346 on the pinned host:

PERRY_RUNTIME_DIR=... PERRY_NO_AUTO_OPTIMIZE=1 \
python3 benchmarks/gc_ratchet/gc_ratchet.py measure \
  --perry target/release/perry --repeats 7 --output /tmp/m.json

Roughly fifteen GC-affecting changes landed in that window. PERRY_GC_DIAG=1
trace diffs between the endpoints should show whether the extra time is inside
collections (more/longer cycles) or outside them (mutator slowdown) — the flat
counters suggest the latter, which would point away from the pacing work and
toward allocation-path or barrier changes.

Acceptance

The +13.58% is attributed to a specific commit and either fixed or accepted with
a reason recorded, or it is shown to be a measurement artifact and the protocol
corrected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions