Add tak instruction-count benchmarks for CLI startup - #8237
Draft
isaacroldan wants to merge 1 commit into
Draft
Conversation
Wall-clock benchmarking on a shared CI runner has roughly the same noise floor as the startup regressions the CLI accumulates, so a threshold tight enough to catch one fires constantly. tak measures retired instruction counts with cachegrind instead: on this repo they reproduce to ~0.0003% run to run, and the history lives in git notes rather than behind a service. Adds tak.toml declaring three hermetic benchmarks against the bundled CLI, a setup action that pins tak by version and sha256, a workflow recording every main commit into refs/notes/tak, and a PR workflow that compares against the merge base and posts the numbers. The PR gate is off until main has a baseline series to compare against. Every benchmark runs node with --predictable; without it V8's hash seed randomisation, time-based tier-up and background marking move the count by ~0.19%, which leaves too little headroom under a 1% gate. Co-authored-by: Isaac Roldan <isaac.roldan@shopify.com>
Contributor
Instruction countsThe comparison never ran — an earlier step failed.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WHY are these changes introduced?
Startup cost is the first thing a CLI user feels, and it is the thing this repo has the least visibility into over time.
docs/cli/performance.mdexplains how to profile a single invocation, but nothing tells us that a dependency added last Tuesday made every invocation 4% slower.The usual reason that gap stays open is that wall-clock benchmarking on a shared CI runner has roughly the same noise floor as the regressions worth catching, so any threshold either cries wolf or catches nothing. tak takes a different measurement: retired instruction counts, read out of valgrind's cachegrind, which are deterministic. The history lives in this repository as git notes under
refs/notes/tak— no dashboard, no service, no account.WHAT is this pull request doing?
tak.tomldeclares three benchmarks against the bundled CLI (pnpm nx bundle cli), which is what ships to npm:version(the startup control),help(manifest load and render), andapp-dev-help(loads an actual command class). Each is commented with what it measures and why..github/actions/setup-takinstalls valgrind and tak, pinned by version and sha256. The instrument is part of the experiment: changing tak can put a step in the series that looks like a change in the CLI..github/workflows/perf.ymlmeasures the tip of every push tomainand appends it torefs/notes/tak. It is the only thing that writes to the shared history..github/workflows/perf-pr.ymlmeasures a PR, compares against the merge base, and posts a sticky comment. Measurement and reporting are split into two jobs so the write token is never in scope while PR code runs.pnpm perf/pnpm perf:recordso local and CI runs invoke the same command.docs/cli/performance.mdgains a section on running and extending it.Two decisions worth reviewing
Every benchmark runs
node --predictable, and that is load-bearing. V8 randomises its string hash seed per process, tiers functions up on a time-based budget, and marks the heap on background threads. Measured here onshopify --version:nodenode --predictable570x tighter, which is the difference between a 1% gate that fires on noise and one that fires on a change. The tradeoff is that this is not the V8 configuration a user runs: the numbers are a relative signal, valid against themselves, and work V8 would do on a background thread is counted on the main thread. An optimization that moves work off the main thread is a real win that would read as flat here.
The PR gate is off (
TAK_GATE: '0'). A gate needs a baseline series, andmainhas to accumulate one first; until then every comparison comes back empty, and an empty comparison is not a pass. The comment and job summary are posted from day one, so the numbers are visible immediately. Flip it to'1'oncemainhas a few weeks of points and the series looks flat.Hermeticity was verified, not assumed
Each benchmark was run inside a network namespace with no network at all and produced the same instruction count:
versionhelpapp-dev-helpshopify commandswas measured and rejected: 12,027,416,226 instructions with a network against 11,570,376,673 without, a 3.9% swing. It would have been the widest manifest walk available, but something on that path reaches the network.One more thing the measurements turned up:
bin/run.jscallsmodule.enableCompileCache(), so the first invocation after a rebuild costs 2,499,297,579 instructions against 1,543,554,209 warm — a 62% difference. tak's default of three warmup runs covers it, but nothing should lowerwarmupintak.toml.Note
tak is explicitly pre-v1 and its author labels the docs as unreviewed. Its CLI, config format and storage format may change incompatibly. That is the main argument against adopting it now; the counter-argument is that everything it produces is JSON lines in a git ref this repo owns, so the data survives the tool.
How to test your changes?
Requires Linux and valgrind — instruction counting is unavailable on Apple Silicon and Windows.
sudo apt-get install -y valgrind # install tak 0.0.5, pinned in .github/actions/setup-tak/action.yml pnpm perfExpect roughly:
Absolute numbers will differ on your machine; the run-to-run spread should not exceed ~0.03%.
Checklist
patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset addRequested by Isaac Roldan isaac.roldan@shopify.com
Slack thread: https://shopify.slack.com/archives/C0AG0L37Q4C/p1785681072538939
AI Confidence Score: 85% — every claim in this description is a measurement taken in a sandbox with the CLI built from this commit, and
pnpm perfwas run end to end. The workflows themselves are unrun: they follow the patterns intests-pr.ymland tak's own docs, and their YAML parses, but GitHub Actions is not exercised until this branch runs.