Repository navigation
feat: run walltime benchmarks in forks - #101
not-matthias wants to merge 8 commits into
Conversation
a33e439 to
4bd0611
Compare
Merging this PR will regress 4 benchmarks3 warnings, 1 note
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
[Medium impact] The stack appears safe to merge, with this assessment depending on PR #111’s changes to walltime execution. SummaryAdds fresh-process walltime measurements for Tinybench and Vitest 5, with three forks by default. The parent pools their samples into one CodSpeed result.
|
860d65c to
8038822
Compare
8038822 to
86bdbbb
Compare
Benchmarks in one process share allocator and JIT state, and rounds within one process are correlated, so a single process gives a biased view of a benchmark. Add the building blocks for integrations to run each walltime benchmark in several fresh processes (forks) and pool their rounds: - `Isolation.walltime(forks?)` picks the mode from the env: parent, fork (`CODSPEED_ISOLATED_BENCHMARK`), or one shared process when `CODSPEED_PROCESS_ISOLATION=false` - the fork count is `CODSPEED_WALLTIME_FORKS`, else the integration's `forks` option, else 3 - `runForks`/`runForksSync` re-run the benchmark command (keeping the V8 flags) once per fork and collect the samples each fork writes with `writeForkSamples`; a failing fork's exit code is passed on - `samplesToResult` builds tinybench-style statistics over the pooled samples Refs COD-3960
`withCodSpeed(bench, { forks })` sets the fork count of walltime runs, and
`CODSPEED_WALLTIME_FORKS` overrides it. The parent runs each task in its
forks and reports their pooled rounds; a fork runs only its task, hands its
samples over and prints no banner or summary. Simulation runs are unchanged.
Refs COD-3960
With Vitest 5, each walltime benchmark runs in fresh `vitest bench`
processes restricted to its file. The fork count resolves as
`CODSPEED_WALLTIME_FORKS`, the benchmark's or run's `forks` option,
`codspeedPlugin({ forks })`, then 3. The test timeout is scaled by the
env or plugin fork count, since every fork of a test runs within it.
Vitest's own report shows zeroed statistics for forked benchmarks; the
CodSpeed results hold the pooled rounds. Vitest 3/4 don't fork.
Closes COD-3960
86bdbbb to
e9af7a1
Compare
TLDR: Rounds within one process are correlated (JIT tier-up, heap sizing, allocator state), so walltime results depend on the process they ran in. Each walltime benchmark now runs in 3 fresh processes (forks) by default, and their rounds are pooled into one result (tinybench and Vitest 5).
Fork count, highest priority first:
CODSPEED_WALLTIME_FORKS=<n>bench(name, { forks }, fn)orbench.compare(..., { forks })withCodSpeed(bench, { forks }),codspeedPlugin({ forks })3CODSPEED_PROCESS_ISOLATION=falseruns everything in one process.How it works
execPath+execArgv+argv, so the runner's V8 flags survive) once per fork, withCODSPEED_ISOLATED_BENCHMARK=<uri>. The fork measures only that benchmark and writes its samples to a temp file. The parent pools them and writes the walltime result.Cost (
examples/with-typescript-esmtinybench, 9 benchmarks): 77 s with isolation off, 140 s with 1 fork, 412 s with 3 forks. Each fork pays process startup.Review notes
forksabove that count can still time out.BenchOptionstype doesn't includeforks, so the per-benchmark option needs a cast in TypeScript.Closes COD-3960