Skip to content

tracking: close the remaining 7 losing rows vs Node (12/19 won, geomean 0.7775x) #8410

Description

@proggeramlug

Purpose

Tracking issue for closing the remaining gap to Node on the 19-row benchmark corpus. Perry
currently beats Node on 12 of 19 rows with a geomean of 0.7775x. This enumerates the
seven rows that still lose, each with its own ticket, evidence and owner-ready repro.

Measured on 8bfdac447 (2026-08-19 sweep, quiet M1 mini, verdict CLEAN, load 1.42 -> 2.08,
best-of-five interleaved, byte-exact output re-checked on every run).

Current standing

value
Perry beats Node 12/19
geomean Perry/Node 0.7775x
geomean Perry/scriptc 0.359x
geomean Perry/Porffor 0.271x
peak RSS vs Node lower on all 19 rows

The seven remaining rows

row P/Node instr ratio dominant cost ticket
cycles 1.01 2.51 init_typed_shape_layout 20.1% #8405
shapes 1.06 1.25 try_read_tracked_gc_header + shape_descriptor_by_id = 100% #8406
asyncpipe 1.12 1.71 not CPU-bound — event-loop/timer latency #8409
churn 1.16 0.99 memory stalls; lowest IPC in corpus (13.35) #8408
pipeline 1.26 1.88 libm fmod 7.3%, plus user-code method dispatch #8407
interp 1.55 1.60 layout bookkeeping ~20.8% #8405
iso_miss 2.02 1.97 string concat 17.9% (#8394), layout bookkeeping #8394, #8405

The structural finding

Splitting all 19 rows by instruction ratio is unambiguous:

  • every row Perry wins has instructions/Node <= 1.07, mostly far below
    (fib40 0.22, churn_read 0.27, tree_wide 0.37)
  • every row Perry loses has >= 1.25, except churn

Perry's codegen quality is not the problem. Where it emits comparable work it wins
comfortably. It loses precisely where it executes more work. That makes each remaining row a
question of "what work can be deleted", which is why every ticket above names a specific
frame and a percentage rather than a vague direction.

churn is the sole exception and therefore the most interesting: 0.99 instruction ratio and
still 1.16x slower. That one is locality, not work.

Ordering suggestion

Method notes for anyone picking these up

Every ticket carries the same build/measure/profile setup and the same constraints. Two that
have cost real time on this corpus and are worth repeating here:

  • Build the -static wrapper crates or you link a stale runtime and both A/B arms behave
    identically — a vacuous "no change".
  • A compelling diff read is a hypothesis, not a result. fix(async_hooks): track scheduler resource lifecycles #8328 looked obviously guilty on
    this exact corpus and measured +0.2%.

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