Repository navigation
perf: pipeline's +3.95% at #8084 is unattributed — it is NOT the callee rooting (IR is byte-identical) #8243
Description
Splitting this out of #8159, which is closed by #8240: the narrowing question is answered, the 3.9% is not.
What is established
pipeline retired +3.95% instructions at 53d63aad2 (#8084) versus 8b1b4b909 (#8157) — measured in #8159, run ranges non-overlapping, 2x the noise floor, every other row flat.
#8159 attributed that to fix(codegen): root the callee across argument evaluation in three call arms. That is falsified. Three independent confirmations on 07c8040bf:
- A codegen change to exactly those arms (perf(codegen): compute the callee-rooting window instead of hardcoding it (#8159) #8240) leaves the emitted IR for
gc-handoff/apps/pipeline.tsbyte-identical —cmpreturns 0, not "within noise". - Both
js_closure_call1sites in that IR are preceded bycall i64 @js_closure_unbox_callee_checked(...), which onlylower_dynamic_closure_call(lower_call/console_promise.rs) emits. That is the GC: evacuating minor drops an old-to-young field[1] edge, crashing with 'value is not a function' #7154 lowering, which has rooted its callee and re-read its arguments below the unbox since long before gc: diagnostics, two rooting fixes, and the ungated corpus/lowering cell (#7803 investigation) #8084. js_new_function_constructandjs_closure_call_apply_with_spreadappear in the module only asdeclarelines. There is no call to either.
Corpus-wide, #8240 measures pipeline +0.02%, interp −0.04%, iso_miss −0.05%, asyncpipe +0.11%, shapes −0.18% — identical runtime archives on both arms, per-arm cache dirs, PERRY_NO_AUTO_OPTIMIZE=1, min-of-5, stdout sha-identical.
So the commit attribution stands and the hunk attribution does not. The cost is in #8084's other ~2,500 lines.
Search space, ranked
Most of the remainder is GC runtime, which a program allocating ~1.4M objects exercises constantly:
gc/roots/stack_maps.rs+_decode.rs+_sections.rs— ~1,660 lines changed; runs on every root scangc/copying.rs(−306) +gc/copying_pointer_set.rs(+248) — the copying minor's pointer set, restructuredgc_map.rs(+355, codegen) — bigger/differently-shaped maps cost scan timegc/pin.rs(+209),gc/tenuring.rs(+41)object/this_binding.rs,object/native_call_method.rs
Sharpest suspect, hypothesis not measurement: js_implicit_this_set. It is pipeline's hottest FFI function — the IR has 4 call sites against 2 closure-call sites (a save and a restore per call), so ~2.9M dynamic calls per run (400 rounds x 900 records x 3 stages, plus idf). #8084 turned it from a bare TLS replace into this_set_check(value, …); replace; this_set_check(previous, …), and each check opens with a OnceLock::get_or_init — an atomic load plus a branch on the fast path, paid twice per call, for a diagnostic (PERRY_GC_THIS_SET_CHECK) that is default-off.
Back-of-envelope that is ~1%, not 3.9%, so at most part of it. But a default-off diagnostic on the hottest path is the shape CLAUDE.md's GC-knob policy exists to prevent, and it is cheap to test: one runtime rebuild, no codegen change. I had that experiment building when I stopped; it is not measured.
Given the IR result, bisect within #8084 by file rather than re-measuring the commit — the answer is known not to be in the part everyone assumed.
Two main-side reds found on the way
Both reproduce on clean 07c8040bf with no PR applied (both arms of the #8240 A/B report them identically). Both were invisible until #8207, because gc-root-dominance aborted earlier at --audit-poll-capable and never reached the corpus steps:
- curated-native is red. One
stalehazard against--max-stale 0:test_gap_class_forward_capture_6523::perry_closure_test_gap_class_forward_capture_6523_ts__7,unmasked->js_box_set, MOVING viajs_object_get_field_by_name_f64. And seeded violations 39/40 caught, 1 MISSED, where the workflow requires all 40 — that second one is the "can the checker still fail" arm, so it matters more than the first. - dep-native reads
unrooted 2, not the3the workflow budgets. A ratchet only ratchets if it tracks the actual value; one new unrooted site would currently land inside budget and go green. Not tightened in perf(codegen): compute the callee-rooting window instead of hardcoding it (#8159) #8240 on purpose — the number is LLVM-version dependent and was measured with homebrewopt, not CI's, so lowering a budget that cannot be verified in CI is how the gate goes red for the next person. Worth CI measuring and ratcheting.
dep-native itself is green and non-vacuous on clean main: 12,957 functions / 81 modules, 49,114 safepoints, seeded 40/40 caught, --self-test OK.
Activity
perf(runtime): remove the expired implicit-this diagnostic from the h…