Repository navigation
Conversation
…very variant Summary: `bundling_speed` needed an app passed on the command line, so its results depended on which app was available and couldn't be reproduced by others without it. It also wrote the build's output to a log file, so Metro's `Terminal` behaved as it does when its output is redirected to a file, where `stream.bytesWritten` is missing. - `bundling_speed` takes no targets. It cold-builds, in prod and dev, an app of 5,000 generated CommonJS modules (a binary tree of `require`s rooted at `m0.js`), so anyone gets the same target. The app is generated in `<tmpdir>/metro-benchmark-patches-app`, with a `babel.config.js` that re-exports Metro's Babel config (Metro's polyfills are Flow source), an empty `.watchmanconfig`, and a `metro.config.js` that resolves `asyncRequire` with `metro:runtime/...`. - Benchmarks export `setUp()`, called once after `dist/` is cleared and before the warmup runs. - `patches/base.patch`, if present, is applied to every variant, including unpatched, and is not a variant itself. Other patches are diffs on top of it. E.g. a base patch that makes Metro print in bursts measures a patch's effect under that output. - Builds write stdout and stderr to pipes, like in most CI setups, and the log is written after the build. A failing command's error includes its stderr. Changelog: [Internal] Test Plan: - `yarn jest scripts/benchmark-patches` - `yarn eslint` and `yarn prettier --check` on `scripts/benchmark-patches` sources - `node scripts/benchmark-patches/benchmark-patches.js bundling_speed --runs=10` with a `base.patch` that logs 3 lines per transformed module in `metro build`, and a patch with the Terminal changes for bursts of external writes.
Metro review: Looks goodRisk: low · Commit: This makes No findings. Verified
Not run: The #2170 table was not reproduced: this Mac has no GNU time at /usr/bin/time, so runs used a wall-clock stand-in and CPU time was not measured. Head and base were not benchmarked, because the PR changes only benchmark tooling, not Metro's runtime code. Automated review by Claude. Advisory only: it never approves or blocks, and a maintainer makes the call. |
…t --build-command's directory - `base.patch` gets a dry run before it's applied, like variant patches, so one that doesn't apply cleanly fails without leaving the checkout partly patched. - The help states that `--build-command` runs from the generated app's directory, so paths in it must be absolute.
Summary
bundling_speedneeds an app passed on the command line, so its results depend on which app is available and can't be reproduced by others without it. It also writes the build's output to a log file, so Metro'sTerminalbehaves as it does when its output is redirected to a file, wherestream.bytesWrittenis missing.bundling_speedtakes no targets. It cold-builds, in prod and dev, an app of 5,000 generated CommonJS modules (a binary tree ofrequires rooted atm0.js), so anyone gets the same target. The app is generated in<tmpdir>/metro-benchmark-patches-app, with ababel.config.jsthat re-exports Metro's Babel config (Metro's polyfills are Flow source), an empty.watchmanconfig, and ametro.config.jsthat resolvesasyncRequirewithmetro:runtime/....setUp(), called once afterdist/is cleared and before the warmup runs.patches/base.patch, if present, is applied to every variant, including unpatched, and is not a variant itself. Other patches are diffs on top of it. Like variant patches, it gets a dry run first, so one that doesn't apply cleanly fails without leaving the checkout partly patched. E.g. a base patch that makes Metro print in bursts measures a patch's effect under that output.--build-commandruns from the generated app's directory, so paths in it must be absolute.This was used to measure #2170 (results below).
Changelog: [Internal]
Test plan
yarn jest scripts/benchmark-patchesyarn eslintandyarn prettier --checkonscripts/benchmark-patchessourcesBenchmark of #2170
node scripts/benchmark-patches/benchmark-patches.js bundling_speed --runs=10, with abase.patchthat makesmetro buildlog 3 lines per transformed module (30,000 lines per build, interleaved with progress updates), and theTerminal.jsandTerminalReporter.jschanges of #2170 as the variant patch. Measured on this PR's base, e7abf93, with #2170's files as of afd65a3:Values are mean ± sample sd over 10 runs per variant. t is Welch's t vs unpatched.
The saving is a roughly flat 2-3s per build, not faster bundling: the process no longer waits for status timers before exiting (on
main, the trailinglodash.throttletimer, up to 3.5s after the last status line in non-interactive output). The generated app builds in about 5s, so the percentages are large. Longer builds, like real apps, save about the same seconds, which is a much smaller share of their wall time. CPU time doesn't change significantly, and bundles are byte-identical.base.patch
Benchmark on an internal app
bundling_speedas onmain, which takes an app as a target (5 runs per variant), on an internal app, built cold with Metro from source, withDEBUG=Metro:*, a patch that logs 3 lines per transformed module in the main process, and output piped. Its Metro didn't include #2162 yet, somain-terminaladds #2162, andterminal-external-write-burstsadds #2162 and #2170: #2170's effect is the difference between the two.Values are mean ± sample sd. t is Welch's t vs unpatched; at 5 runs, |t| < 2.3 is not significant (p > 0.05).
No wall time or CPU change is significant, and bundles are byte-identical. This app's build command already flushes its terminal when the build finishes, so there's no exit wait to save; the burst handling adds no measurable cost on a large app under heavy logging.