Summary
pipeline is the only corpus row that got slower across 2026-08-15's twenty merges: +0.28% instructions on main @ d6d7d0efe versus 83b6b8c69. Every other row is flat or faster, several enormously.
The number is small but it is 2× the measured noise floor (±0.15%, established by compiling main twice into separate cache/out dirs and confirming all 22 binaries byte-identical), and the run ranges do not overlap: base 3.7881–3.7936 G, main 3.8015–3.8053 G. Peak RSS is unchanged.
It is a give-back, not a shortfall
Building the intervening merge points attributes it to a single step:
| arm |
pipeline instructions |
Δ |
83b6b8c69 (session start) |
3.7881 G |
— |
8b1b4b909 (#8157 merge) |
3.6547 G |
−3.52% |
53d63aad2 (#8084 merge) |
3.8003 G |
+3.95% |
d6d7d0efe (today's main) |
3.7988 G |
−0.00% |
#8157 delivered its full claimed −3.52% here. The next step gave all of it back and a little more.
Every other row moves by ≤0.03% across that same at8157 → at8084 step, so this is one localized change, not drift.
Attribution
The window is {#8158, #8084}. #8158 is a 7-line addition to BUILD_CACHE_ENV_VARS and cannot change emitted code, which leaves #8084 — specifically fix(codegen): root the callee across argument evaluation in three call arms, touching new_dynamic.rs, call_spread.rs and early_branches.rs. pipeline is spread- and call-heavy, so the mechanism fits: each rooted callee adds an open_rooted_group / adopt / reread / release sequence around a call site.
This is not a request to revert
#8084 fixes a real moving-GC rooting bug — a callee held in a bare register across argument evaluation is a pre-move address, and the dependency-scale corpus found 16 sites of that shape. Correctness wins over 3.9% on one row, and #8084 should stay.
Filing it because nobody wrote the cost down. A correctness fix that silently consumes an entire optimisation's win on a row is exactly the thing that later gets rediscovered as an unexplained regression, and #8157's pipeline win currently looks like it never happened.
Worth looking at
The rooting sequence is emitted per call site. Whether it can be narrowed — e.g. skipping the reread when nothing between adopt and use can allocate, which is a property the tree already computes elsewhere for loop polls (loop_purity::loop_may_allocate) — is the obvious question. That would keep the soundness property while paying for it only where a collection is actually reachable.
Measurement protocol: /usr/bin/time -l, min-of-5, arms interleaved round-robin with order reshuffled each round, per-arm PERRY_RUNTIME_DIR and PERRY_CACHE_DIR, PERRY_NO_AUTO_OPTIMIZE=1, all arms' libperry_runtime.a cmp-verified to differ, stdout sha256 identical across arms.
Refs #8084, #8157.
Summary
pipelineis the only corpus row that got slower across 2026-08-15's twenty merges: +0.28% instructions onmain@d6d7d0efeversus83b6b8c69. Every other row is flat or faster, several enormously.The number is small but it is 2× the measured noise floor (±0.15%, established by compiling
maintwice into separate cache/out dirs and confirming all 22 binaries byte-identical), and the run ranges do not overlap: base 3.7881–3.7936 G, main 3.8015–3.8053 G. Peak RSS is unchanged.It is a give-back, not a shortfall
Building the intervening merge points attributes it to a single step:
pipelineinstructions83b6b8c69(session start)8b1b4b909(#8157 merge)53d63aad2(#8084 merge)d6d7d0efe(today's main)#8157 delivered its full claimed −3.52% here. The next step gave all of it back and a little more.
Every other row moves by ≤0.03% across that same
at8157 → at8084step, so this is one localized change, not drift.Attribution
The window is {#8158, #8084}. #8158 is a 7-line addition to
BUILD_CACHE_ENV_VARSand cannot change emitted code, which leaves #8084 — specificallyfix(codegen): root the callee across argument evaluation in three call arms, touchingnew_dynamic.rs,call_spread.rsandearly_branches.rs.pipelineis spread- and call-heavy, so the mechanism fits: each rooted callee adds anopen_rooted_group/adopt/reread/releasesequence around a call site.This is not a request to revert
#8084 fixes a real moving-GC rooting bug — a callee held in a bare register across argument evaluation is a pre-move address, and the dependency-scale corpus found 16 sites of that shape. Correctness wins over 3.9% on one row, and #8084 should stay.
Filing it because nobody wrote the cost down. A correctness fix that silently consumes an entire optimisation's win on a row is exactly the thing that later gets rediscovered as an unexplained regression, and #8157's
pipelinewin currently looks like it never happened.Worth looking at
The rooting sequence is emitted per call site. Whether it can be narrowed — e.g. skipping the reread when nothing between adopt and use can allocate, which is a property the tree already computes elsewhere for loop polls (
loop_purity::loop_may_allocate) — is the obvious question. That would keep the soundness property while paying for it only where a collection is actually reachable.Measurement protocol:
/usr/bin/time -l, min-of-5, arms interleaved round-robin with order reshuffled each round, per-armPERRY_RUNTIME_DIRandPERRY_CACHE_DIR,PERRY_NO_AUTO_OPTIMIZE=1, all arms'libperry_runtime.acmp-verified to differ, stdout sha256 identical across arms.Refs #8084, #8157.