Add CI performance benchmark suite
Summary
Add a reproducible two-tier performance benchmark suite for detecting
regressions in pull requests.
- Tier 1 runs pinned lmbench workloads for syscall, process, and
filesystem latency. - Tier 2 measures Python startup, Git status, ripgrep, zstd, and Make
against a deterministic committed corpus. - Results include medians and raw samples in structured JSON.
- Baseline columns are prepared for elfuse, QEMU-based native Linux,
and OrbStack.
CI integration
Add a benchmark leg to the self-hosted Apple Silicon runtime matrix.
The leg runs exclusively on the host to avoid interference from sibling
jobs, compares results in report-only mode, and uploads the JSON artifact.
Missing baseline metrics are treated as failures, preventing broken or
timed-out benchmarks from silently passing. Benchmark preparation and
cleanup commands are also bounded by timeouts.
The checked-in baseline has not yet been captured on the designated
self-hosted CI machine. It will be refreshed in a follow-up after the
benchmark leg is deployed and runner variance has been characterized.
Comparison therefore remains report-only for now.
Validation
- Full cold run: approximately 10m 19s
- Cached CI-equivalent run: approximately 9m 20s
- Baseline match exits successfully
- An injected 2x regression exits non-zero
- A missing baseline metric exits non-zero
- Benchmark output contains 9 lmbench and 6 application metrics
Closes #195
Summary by cubic
Adds a two-tier performance benchmark suite with a deterministic workload to catch syscall, process-startup, and app-level regressions. Runs on the self-hosted Apple Silicon runner under an exclusive host lock and posts a sanitized PR comment with benchmark deltas. (Issue #195)
-
New Features
tests/bench-suite.sh: Tier 1lmbench(lat_syscall/lat_proc/lat_fs) and Tier 2 app workloads (git status,rg,make,zstd) with warmups; guest-side timing forqemu-aarch64viatests/bench-timeit.c; writes medians+samples tobuild/bench-results*.json.- Deterministic
tests/bench-corpusfor stable Tier 2 inputs; excluded from formatting to preserve baselines. Fixtures fetch app tools and cross-compile pinnedlmbench. - Baselines in
tests/bench-baseline.jsonforelfuse-aarch64,qemu-aarch64, andorbstack.scripts/bench-compare.pyflags regressions (tunable viaBENCH_REGRESSION_THRESHOLD) and treats missing metrics as NEW by default;scripts/bench-promote.pyrefreshes baselines. - CI:
make bench/make bench-ci;BENCH_ENVselectselfuse-aarch64(default) |qemu-aarch64|orbstack|native. Benchmark leg isolates measurements withscripts/ci-host-lock.sh..github/workflows/bench-report.ymlusesscripts/bench-report.pyto publish a sanitized advisory PR comment from the uploaded report artifact. Docs indocs/testing.md.
-
Migration
- Run:
make bench(orBENCH_ENV=qemu-aarch64 make bench-ci). - Compare:
scripts/bench-compare.py --report-only. - Refresh baselines: run
make bench-ciper env, thenscripts/bench-promote.py; commit the updatedtests/bench-baseline.json.
- Run: