feat(benches): 📈 track benchmarks with Bencher - #223
Merged
Conversation
Adds the first slice of continuous benchmarking: every commit on `main` runs the internal suite and uploads the results to Bencher, which graphs them over time and alerts when a metric drifts outside its threshold. Bencher accepts one adapter per upload, so `benches/bmf.py` merges both run artifacts into a single Bencher Metric Format report; the stock `python_pytest` adapter would keep the timings and drop the memory and operator metrics. Four measures are tracked: `latency`, `peak-memory`, `resting-memory`, and `terms`. The last is deterministic for a fixed seed and problem size, so it is held to an exact match rather than a statistical bound. `bench-ci` keeps the `bench` default sizes rather than introducing a second set to keep in sync -- they run in under a minute and leave the heavier operations well above the runner noise floor. Alerts on `main` are recorded but do not fail the build: the timing measures need history on a shared runner before their noise floor is known. Gating belongs on pull requests, where a base-vs-head comparison on one runner cancels out machine-to-machine variance. Assisted-by: GitHubCopilot:claude-opus-4.5
Panadestein
requested review from
adamglos92,
diagonal-hamiltonian,
fpietra,
ludmilaasb and
robertodr
as code owners
August 12, 2026 15:10
|
Docs preview: https://pr-223.monoprop-docs.pages.dev |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #223 +/- ##
=======================================
Coverage 97.70% 97.70%
=======================================
Files 14 14
Lines 742 742
Branches 98 98
=======================================
Hits 725 725
Misses 12 12
Partials 5 5
Flags with carried forward coverage won't be shown. Click here to find out more. |
robertodr
reviewed
Aug 13, 2026
Co-authored-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com> Signed-off-by: Ramón L. Panadés-Barrueta <rpana92@gmail.com>
robertodr
approved these changes
Aug 13, 2026
robertodr
enabled auto-merge (squash)
August 13, 2026 09:43
|
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.



🤖 AI text below 🤖
First slice of continuous benchmarking with Bencher: every commit on
mainruns the internal suite and uploads the results, which Bencher graphs over time and alerts on when a metric drifts outside its threshold.This is deliberately the smallest end-to-end slice — it proves the pipeline before any PR gating is layered on.
What's here
benches/bmf.pyjust bench-ci LABELjust bench-bmf LABEL.github/workflows/bench_main.ymlmain, thenbencher runtests/test_bench_bmf.pyWhy a custom exporter
Bencher accepts one
--adapterper upload. The stockpython_pytestadapter would keep the timings and silently drop everything else, sobmf.pymerges both artifacts —pytest-benchmark's JSON and the/procmemory sampler's — into a single report. Four measures are tracked:latencypytest-benchmarkmean ±1σpeak-memoryresting-memorytermstermsis deterministic for a fixed seed and problem size, so any change at all is a real change in what the propagator computes — it gets an exact-match threshold rather than a statistical bound, which makes it the sharpest of the four.Unlike
just benchandjust bench-smoke,bench-cidoes not renderREPORT.md; the BMF report is the artifact that matters here.Benchmark sizing
bench-cireuses the documentedbenchdefault sizes rather than introducing a second set of magic numbers to keep in sync. Measured locally at ~56 s, with the heavier Schrödinger operations landing in the 50 ms – 1 s range — comfortably above the runner noise floor. It bumps--bench-roundsto 5 (CI reports the mean) and drops theslowfixed models, which belong in a nightly job.Alerts do not fail the build (yet)
--error-on-alertis intentionally absent. The timing measures need history on a shared runner before their noise floor is known, and a redmainfrom GitHub runner variance would train everyone to ignore the signal. Gating belongs on pull requests, where base and head are benchmarked on the same runner and machine-to-machine variance cancels out.Maintainer setup required
The workflow is a no-op on forks (it checks
github.repository) and will fail onmainuntil:BENCHER_API_KEYis added as a repository secret.BENCHER_PROJECTrepository variable if the project slug isn'tmonoprop.One caveat worth flagging
Benchmark names are Bencher's history key. Renaming or moving a
bench_*test orphans its tracked series — noted inAGENTS.mdnext to thebenches/report.py/benches/bmf.pyentry so it isn't rediscovered the hard way.Follow-ups (out of scope here)
bench_pr.yml(relative CB),bench_pr_closed.yml(bencher archive), and the fork-PRpull_request/workflow_runpair--error-on-alertonce a noise baseline exists — starting withterms, thenlatencyslowmodels and an MPI testbedValidation
just bench-smokeandjust bench-ci ci-linuxboth run clean; BMF output verified against the real artifacts of eachprek runclean, including the workflow schema hook