Skip to content

docs(perf): publish the binary-size and boot-time audit behind #652 - #894

Merged
mparrett merged 4 commits into
mainfrom
wt/size-boot-audit
Sep 19, 2026
Merged

mparrett merged 4 commits into
mainfrom
wt/size-boot-audit

Conversation

@mparrett

@mparrett mparrett commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

What

Publishes the binary-size and boot-time audit behind #652: a controlled comparison of v1.7.4 with main pinned at ed4ecc2, with six measurement/analysis tools and the raw timing and size data behind the tables.

Size and boot were measured on 2026-07-17 on darwin/arm64 with go1.26.3. The compute comparison was corrected and re-run on 2026-09-17 with go1.26.5: each round now measures both refs and alternates AB/BA order, rather than asking Hyperfine to run two command-sized blocks. The document dates both sets of measurements and keeps the historical endpoint explicit instead of implying that ed4ecc2 is current main.

Why it was measured

A comparison table from another machine reported "+40% startup / +24% binary". Those figures came from a single-run time and an unstripped build, so the audit re-ran both in a controlled setup on one machine. Noisy compute measurements now use paired, order-balanced A/B rounds.

Four results that outlived the table:

The startup regression was real and larger than claimed, and it was already fixed. In-process boot went 744 -> 5499 microseconds by v1.11.0, then 5499 -> 1145 in v1.11.1 once the ir.* pipeline became lazy. Boot tracks the core bundle almost exactly (694 KiB -> 5499 us, 228 KiB -> 1145 us), not the Go binary.

It never appeared on the perf page, and the reason is structural. BenchmarkInitFromLGB entered the ratchet in #355 on 2026-06-29 — one day after the v1.11.0 peak and the same day as the fix. The whole regression window had no boot metric. The dashboard's boot series effectively starts after the spike it would have caught.

The binary headline was an artifact. Stripped, which is what ships, the growth is 10.07 -> 12.64 MiB. The embedded bundle grew only 130 -> 242 KiB, so about 96% of the binary growth is outside the bundle; package attribution points to Go code. Per package: pkg/vm +642 KiB, pkg/rt +435 KiB, and a new 230 KiB go/ast/parser/printer cluster that pkg/rt/gogen.go links into every binary, wasm included, because it carries no build tag.

Compute is slower, with corrected paired estimates. Across 15 paired rounds, alternating AB/BA, ed4ecc2 is +12.8% on fib and +17.6% on tak by paired median versus v1.7.4. The exact round order, timings, and paired ratios are checked in as JSON.

The lever, with its cost

Tagging gogen.go //go:build bootstrap saves 696 KiB (5.4%) stripped and still boots and runs. It also breaks runtime *ir-compile*, whose lazy require reaches gogen transitively. The patch is included as gogen-bootstrap-gate.patch, and section 1 sets out the version that keeps both: decouple ir.lower-go from the pipeline's unconditional :require so only the :go target pulls gogen.

The gaps

The audit misread the ratchet here, and §4 now says so. It reported boot as gated on timing alone; in fact the deterministic allocs/bytes gate landed in #362 on 2026-06-30, two weeks before the audited ref, at a 2% budget tighter than the 5% timing one. The gate's real weakness is #883: machineIndependentBar takes minima across profiles captured at different commits.

Binary and bundle size remain ungated. The stripped binary grew +2.57 MiB and the bundle had already crept 228 -> 242 KiB by ed4ecc2, but nothing in cmd/bench-ratchet measures size today. scripts/nm-package-diff.py is the per-package attribution such a gate would need.

Reproducing

release-compare.sh, boot-e2e.sh, binary-size-walk.sh, and ab-compute.sh build throwaway worktrees and leave the caller's checkout alone. Start with release-compare.sh; only boot-e2e.sh needs Hyperfine. ab-compute.sh uses the checked-in Python paired runner and records every round order and B/A ratio.

@mparrett
mparrett marked this pull request as ready for review September 18, 2026 00:26
@mparrett
mparrett marked this pull request as draft September 18, 2026 00:36
@mparrett
mparrett marked this pull request as ready for review September 18, 2026 00:51
@mparrett

Copy link
Copy Markdown
Collaborator Author

Caveat: testing machine is hot

mparrett and others added 4 commits September 18, 2026 17:58
Independent, controlled re-measurement of the size/startup deltas between
v1.7.4 and main, with reusable tooling for the team.

Findings:
- shipped binary +2.57 MB (+25%); the headline 18.2 MB was unstripped.
  Attribution: pkg/vm+pkg/rt (~1.08 MB) + an unconditional go/ast toolchain
  (gogen, ~696 KB, gate-able with the included patch).
- boot regressed ~7.4x in-proc by v1.11.0 then fixed in v1.11.1 (lazy ir.*);
  boot tracks the core bundle, not the Go binary.
- it missed the perf page because InitFromLGB tracking (#355) landed the same
  day as the fix, after the regression window.
- fib/tak: real but modest (~+11% controlled), not the casual +17-19%.
- ratchet gates in-proc boot on the noisy ns-ratio, not the deterministic
  allocs/B its own comment relies on.
- whole-bundle DEFLATE (feat/lgb-compression-core) costs ~1.4 ms coldstart for
  ~160 KB — motivates random-access zip.

Scripts create their own throwaway worktrees; data + gogen patch included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The audit page predates the docs-frontmatter gate and would fail it. The
last-verified date is the measurement date rather than today, so the page
reports its own age instead of implying it is current.

The title said v1.7.4 -> main, which stops being true the moment main moves;
the body already names the ref, so the title now carries it too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
§4 said the ratchet gated boot timing but not allocations, and that #780 closed
that gap on 2026-09-02. Both halves are wrong.

The audited ref itself carries the gate: at ed4ecc2, writeOrCheck calls
compareDeterministic(machineIndependentBar(baseline), current, allocBudget) and
sets exit = 1 on any regression (cmd/bench-ratchet/main.go:412), covering
allocs/op and bytes/op for every benchmark in the baseline at a 2% budget --
tighter than the 5% timing budget. It landed in #362 on 2026-06-30, two weeks
before ed4ecc2. #780 changed neither compareDeterministic, allocBudget,
machineIndependentBar, nor the exit wiring.

The misreading was of compareAndReport, which handles timing only; the
deterministic check is a sibling call one level up.

Recommendation 1 asked for a gate that already existed, so it now names the
gate's actual weakness (#883, minima taken across profiles captured at different
commits) instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mparrett
mparrett merged commit 058fa5e into main Sep 19, 2026
13 checks passed
@mparrett
mparrett deleted the wt/size-boot-audit branch September 19, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants