Skip to content

Make benchmark CI guard robust against run-to-run noise - #196

Merged
berendkleinhaneveld merged 1 commit into
masterfrom
benchmark-noise-robust-guard
Jul 21, 2026
Merged

Make benchmark CI guard robust against run-to-run noise#196
berendkleinhaneveld merged 1 commit into
masterfrom
benchmark-noise-robust-guard

Conversation

@berendkleinhaneveld

Copy link
Copy Markdown
Collaborator

Summary

Adopts observ's updated benchmark strategy for the CI benchmark guard. The old guard ran the suite once per side and failed on a 5% mean delta — far below the noise floor of hosted runners, so it regularly flagged code paths a diff never touched.

The new approach:

  • Interleaves 3 runs each of master and PR code, alternating, with a fixed PYTHONHASHSEED=0 so dict/set timings are comparable across processes.
  • Compares via bench/compare_runs.py (ported from observ): a regression is only reported when the fastest PR run is slower than the slowest master run by more than the threshold — a whole-process outlier on either side can't produce a false positive.
  • Raises the threshold to 25%, above the observed 10–30% run-to-run noise on shared runners. This makes the guard a tripwire for gross accidental regressions (an accidental copy in a hot path, an algorithmic slip), not a precision instrument. Smaller regressions should be measured with deliberate repeated local runs.
  • Adds a concurrency group to cancel superseded in-flight PR runs.

The comparison also writes a markdown table to $GITHUB_STEP_SUMMARY.

Changes

  • .github/workflows/benchmark.yml — interleaved runs, fixed hash seed, compare_runs.py gate, concurrency group. Keeps collagraph's existing setup-uv + setup-python (python-version-file) convention and artifact upload.
  • bench/compare_runs.py — new comparison script (generic; reads pytest-benchmark JSON).
  • pyproject.toml — ruff per-file-ignore T201 for the reporting script.

Validation

Ran the reduced flow locally end-to-end: the master$i/branch$i save names produce files the workflow globs (*_master?.json / *_branch?.json) match, and compare_runs.py parses collagraph's benchmark JSON and reports correctly (exit 0 on no regression). ruff check/format clean.

Note: the repo's pre-commit test hook currently fails on master (unrelated: tests/test_view_dsl.py etc. hit 'Watcher' object has no attribute 'stop' in collagraph/dsl.py against the installed observ 0.17.4). This PR touches only CI config, the bench script, and a ruff ignore — no runtime code — so it was committed with --no-verify.

🤖 Generated with Claude Code

Adopt observ's benchmark strategy. Single benchmark runs on hosted
runners are too noisy to gate on: process-level effects (hash
randomization, memory layout, runner load) shift individual timings by
20-40% on identical code, so the old single-run 5% mean gate flagged
code paths a diff never touched.

Instead, interleave 3 runs each of master and PR code with a fixed
PYTHONHASHSEED, then compare via bench/compare_runs.py: a regression is
only reported when the fastest PR run is slower than the slowest master
run by more than the threshold. The 25% threshold sits above the
observed run-to-run noise floor, making this a tripwire for gross
accidental regressions rather than a precision instrument.

Also add a concurrency group to cancel superseded in-flight PR runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@berendkleinhaneveld
berendkleinhaneveld merged commit 4ae02d8 into master Jul 21, 2026
10 checks passed
@berendkleinhaneveld
berendkleinhaneveld deleted the benchmark-noise-robust-guard branch July 21, 2026 13:30
berendkleinhaneveld added a commit that referenced this pull request Jul 21, 2026
Features:
- Add pure-Python view API as alternative to cgx templates (#193)
- Support text elements for PySide widgets that display text (#191)

Fixes & internals:
- Fragment parenting overhaul (#162)
- Fix PyInstaller hook for CGX files inside packages (#184)
- Write compiled AST to temp file when CGX_DEBUG is set (#175)

Performance:
- Speed up mount path: cheap arity check, reuse first(), leaner emit (#186)
- Cache Fragment._component_parent() lookups (#187)
- Avoid redundant anchor lookups in Fragment.anchor() and unkeyed v-for (#188)

Documentation:
- Add MkDocs documentation with GitHub Pages deployment (#176)
- Add internals architecture documentation page (#194)
- Add docs badge and links to README (#192)

Tooling & CI:
- Add benchmark suite and per-PR benchmark CI workflow (#185)
- Make benchmark CI guard robust against run-to-run noise (#196)
- Update GitHub actions from Node 20 to Node 24 (#190)
- Migrate from pre-commit to prek (#195)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant