refactor(bench): 📦 release the benchmark harness as monoprop-bench-tools - #227
Conversation
Turn the repository into a uv workspace and split the benchmark harness in two: the reusable half becomes a published package, the benchmarks stay here. - packages/monoprop-bench-tools: peak-memory measurement (memory.cpu, memory.gpu), the benchmarked model builders (models), and the artifact renderers (report, bmf), plus the monoprop-bench-report / monoprop-bench-bmf console scripts. Pure Python, built by hatchling, versioned off the same git tags as monoprop. - benches/ keeps conftest.py and the bench_* suite and imports the package. Benchmark names are Bencher's history key, so the suite must not move with a library release. - packages/bench-third-party: the cross-engine comparison scripts, moved out of benches/third_party and excluded from the workspace (narrower requires-python, a git dependency and linux-x86_64-only CUDA wheels). It now depends on the tools package instead of poking benches/ onto sys.path. Dependency groups follow the split: `test` stays free of workspace members so cibuildwheel can install it against a built wheel, `workspace-test` adds the new member and is what the root suite needs, and `bench` builds on that. deploy.yml gains a job that builds and publishes monoprop-bench-tools; it is a separate PyPI project, so it needs its own trusted-publisher entry. Assisted-by: GitHubCopilot:claude-opus-5
|
Docs preview: https://pr-227.monoprop-docs.pages.dev |
…uv-workspace # Conflicts: # justfile
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #227 +/- ##
=======================================
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. |
|
Good idea 👍 |
There was a problem hiding this comment.
Pull request overview
This PR restructures the repository into a uv workspace and extracts the reusable benchmark harness into a separately publishable Python distribution (monoprop-bench-tools), while keeping benches/ in-repo to preserve Bencher metric history continuity.
Changes:
- Introduces a
uvworkspace setup and dependency-group split (testvsworkspace-testvsbench) to keep wheel-testing isolated from workspace members. - Creates the new
packages/monoprop-bench-toolsdistribution containing memory tooling, model builders, and artifact renderers with console scripts. - Moves third-party comparison scripts into a standalone
packages/bench-third-partyproject with its own lockfile and updated imports.
Reviewed changes
Copilot reviewed 35 out of 57 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Adds workspace manifest members and a workspace-test group; locks the new monoprop-bench-tools editable member. |
| sonar-project.properties | Excludes packages/** from Sonar scope to preserve previous analysis behavior. |
| README.md | Documents workspace install flow and explains the new repository layout. |
| pyproject.toml | Defines [tool.uv.workspace], introduces workspace-test, updates pytest collection paths, and adjusts ruff per-file ignores for new package layout. |
| packages/monoprop-bench-tools/tests/test_report.py | Updates imports to reference monoprop_bench_tools.report. |
| packages/monoprop-bench-tools/tests/test_models.py | Updates imports to reference monoprop_bench_tools.models. |
| packages/monoprop-bench-tools/tests/test_memory.py | Updates imports to reference monoprop_bench_tools.memory.cpu. |
| packages/monoprop-bench-tools/tests/test_bmf.py | Updates imports to reference monoprop_bench_tools.bmf. |
| packages/monoprop-bench-tools/tests/conftest.py | Adds isolated pytest config/fixtures so the tools package can test standalone. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/report.py | Converts report renderer into a console-script entrypoint (monoprop-bench-report) and tightens CLI usage. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/models.py | Introduces reusable benchmark model builders and registry (MODELS). |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/memory/gpu.py | Moves GPU peak-memory measurement into the publishable tooling package and updates module references/docstrings. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/memory/cpu.py | Moves CPU peak-memory and PSS sampling utilities into the publishable tooling package and expands docstrings. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/memory/init.py | Adds package init describing CPU/GPU backends and import expectations. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/bmf.py | Converts BMF exporter into a console-script entrypoint (monoprop-bench-bmf) and updates usage/errors. |
| packages/monoprop-bench-tools/src/monoprop_bench_tools/init.py | Adds package top-level docstring and version exports. |
| packages/monoprop-bench-tools/README.md | Adds end-user README for the new PyPI-distributed tooling package. |
| packages/monoprop-bench-tools/pyproject.toml | Defines the new monoprop-bench-tools project metadata and console scripts; configures hatch-vcs versioning from repo tags. |
| packages/monoprop-bench-tools/LICENSE | Adds Apache-2.0 license file for the new distribution. |
| packages/bench-third-party/uv.lock | Re-resolves the standalone third-party project lockfile and adds an editable dependency on monoprop-bench-tools. |
| packages/bench-third-party/README.md | Updates documentation to refer to monoprop_bench_tools.memory.gpu and new invocation patterns. |
| packages/bench-third-party/pyproject.toml | Defines the standalone monoprop-bench-third-party project and consumes both monoprop packages from the checkout. |
| packages/bench-third-party/pauli_prop/settings.json | Adds committed settings for the third-party Pauli benchmark configuration. |
| packages/bench-third-party/pauli_prop/scaling_results.jsonl | Adds committed scaling results dataset used by plotting scripts. |
| packages/bench-third-party/pauli_prop/run_scaling.py | Adds sweep driver that spawns per-(backend,size) subprocesses with timeouts and captures failures. |
| packages/bench-third-party/pauli_prop/run_scaling.jl | Adds Julia scaling runner matching the Python record schema. |
| packages/bench-third-party/pauli_prop/run_one.py | Adds single-backend runner used as the subprocess work unit for scaling sweeps. |
| packages/bench-third-party/pauli_prop/run_model.py | Adds fixed-size multi-backend runner emitting per-step curves. |
| packages/bench-third-party/pauli_prop/run_model.jl | Adds Julia fixed-size runner merging results into the shared JSON file. |
| packages/bench-third-party/pauli_prop/results.json | Adds committed fixed-size results dataset used by plotting scripts. |
| packages/bench-third-party/pauli_prop/plot_speedup.py | Adds speed-up bar chart generator (monoprop baseline vs other backends). |
| packages/bench-third-party/pauli_prop/plot_scaling.py | Adds scaling-curve plotting and sidecar table/provenance generation. |
| packages/bench-third-party/pauli_prop/plot_results.py | Adds fixed-size per-step plotting for runtime/memory curves. |
| packages/bench-third-party/pauli_prop/model.py | Adds shared benchmark model definition (TFIM) used across backends. |
| packages/bench-third-party/pauli_prop/backends.py | Switches memory instrumentation imports to monoprop-bench-tools rather than sys.path hacks; updates metric docs. |
| packages/bench-third-party/majorana_prop/run_benchmarks.sh | Adds orchestration script to run monoprop + Julia benchmarks back-to-back. |
| packages/bench-third-party/majorana_prop/results.json | Adds committed results dataset for the majorana comparison benchmark. |
| packages/bench-third-party/majorana_prop/README.md | Adds documentation for the majorana comparison benchmark workflow. |
| packages/bench-third-party/majorana_prop/Project.toml | Adds Julia project deps for the majorana benchmark. |
| packages/bench-third-party/majorana_prop/plot_results.py | Adds plotting for majorana benchmark results, including a runtime-only figure. |
| packages/bench-third-party/majorana_prop/monoprop_hubbard1d_benchmark.py | Updates benchmark script to import memory instrumentation from monoprop-bench-tools. |
| packages/bench-third-party/majorana_prop/julia_hubbard1d_benchmark.jl | Adds Julia benchmark implementation and merges results/provenance into shared JSON. |
| packages/bench-third-party/bench_common.jl | Updates comment references to match the new monoprop_bench_tools.memory.cpu source of truth. |
| benches/third_party/pyproject.toml | Removes the previous third-party benchmark project definition (now replaced by packages/bench-third-party). |
| benches/README.md | Documents the split between benches/ (benchmarks) and monoprop-bench-tools (reusable harness) plus the standalone third-party project. |
| benches/conftest.py | Updates imports to consume builders/memory tooling from monoprop-bench-tools and clarifies the artifact schema boundary. |
| benches/bench_random.py | Updates to import barriered from the new tools package. |
| benches/bench_models.py | Updates to import model registry/build helpers from the new tools package and updates doc references. |
| AGENTS.md | Documents the new workspace layout and the cross-package schema seam between bench writer and renderers. |
| justfile | Updates test groups to workspace-test and switches report/BMF invocations to the new console scripts. |
| docs/content/docs/testing.mdx | Documents that uv run pytest now collects both root and tools-member test suites and how to install them. |
| docs/content/docs/benchmarks.mdx | Updates paths and commands to match the new packages/bench-third-party location and console scripts. |
| .gitignore | Ignores hatch-vcs/setuptools-scm generated version files for workspace members and adds logs/. |
| .github/workflows/test.yml | Installs workspace-test group in CI so both test suites can be collected/imported. |
| .github/workflows/qa-analysis.yml | Installs workspace-test group for QA analysis runs. |
| .github/workflows/deploy.yml | Adds build+upload jobs for monoprop-bench-tools and wires PR-change detection for its pyproject.toml. |
| .github/ISSUE_TEMPLATE/performance_issue.yml | Updates suggested repro steps to the new uv sync + just bench-smoke flow. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
robertodr
left a comment
There was a problem hiding this comment.
Overall LGTM! Thank you @Panadestein I think we'll gain very valuable experience with uv workspaces. I have some comments on the extras for the other workspace packages.
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>
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>
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>
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>
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>
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>
…m/Algorithmiq/monoprop into refactor/bench-tools-uv-workspace
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>
Shortens the GPU install to one line, as asked for in review:
pip install "monoprop-bench-tools[gpu-cuda12]"
No `[tool.uv] conflicts` pair to go with them. Declaring one does stop the
nonsensical "both extras at once", but uv validates the conflict set eagerly, so
it also makes `uv sync --all-extras` fail for the *whole* workspace -- the form
used by the devcontainer, the VS Code build tasks, and test/qa/bench/setup CI.
Measured either way: declared at the workspace root or in the member, both break
it. Without the pair, root `--all-extras` resolves clean and never pulls CuPy,
while `--extra gpu-cuda12` installs exactly one build.
The lockfile grows by cupy-cuda12x, cupy-cuda13x and cuda-pathfinder (96 -> 99
entries). Nothing installs them unless the extra is asked for.
Assisted-by: GitHubCopilot:claude-opus-5
…m/Algorithmiq/monoprop into refactor/bench-tools-uv-workspace
Co-authored-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com> Signed-off-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 35 out of 57 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/monoprop-bench-tools/pyproject.toml:40
- The PR description says there is no GPU extra on
monoprop-bench-toolsto avoid pulling CuPy (andcuda-pathfinder) into the root lock, but the package now definesgpu-cuda12/gpu-cuda13extras (anduv.lockincludescupy-cuda12x,cupy-cuda13x,cuda-pathfinder). Please align the implementation with the stated design decision: either remove these extras (and related docs) or update the PR description/rationale to reflect that the extras (and lock growth) are intentional.
|
🤖 _AI text below_ 🤖 Follow-up to #227. ## The diagnosis (confirmed) `monoprop_bench_tools` declares the `Typing :: Typed` classifier and is fully annotated, but it shipped no PEP 561 `py.typed` marker. Since it resolves as an *installed library* (its source tree lives under `packages/`, outside the `[tool.pyright] include` set), pyright/Pylance treat it as untyped and emit `reportMissingTypeStubs` on every import in `benches/conftest.py`. `monoprop` itself is unaffected because nanobind's stubgen already generates a marker (`src/monoprop/bindings/CMakeLists.txt`, `MARKER_FILE`). Reproduced and verified with pyright 1.1.408 against the workspace environment: Before: ``` benches/conftest.py:44:6 - warning: Stub file not found for "monoprop_bench_tools.memory.cpu" (reportMissingTypeStubs) benches/conftest.py:50:6 - warning: Stub file not found for "monoprop_bench_tools.models" (reportMissingTypeStubs) benches/conftest.py:62:10 - warning: Stub file not found for "monoprop_bench_tools.models" (reportMissingTypeStubs) ``` After: 0 warnings. ## The change One empty file: `packages/monoprop-bench-tools/src/monoprop_bench_tools/py.typed`. Also verified the marker actually reaches consumers of the published distribution — `uv build --package monoprop-bench-tools --wheel` produces a wheel containing `monoprop_bench_tools/py.typed`, so hatchling picks it up without any extra `[tool.hatch.build]` include rule.



🤖 AI text below 🤖
Turns the repository into a uv workspace and splits the benchmark harness in two: the reusable half becomes a package we can publish, the benchmarks stay here.
What moved
benches/_memory_cpu.pymonoprop_bench_tools.memory.cpubenches/_memory_gpu.pymonoprop_bench_tools.memory.gpubenches/_builders.pymonoprop_bench_tools.modelsbenches/report.pymonoprop_bench_tools.report→monoprop-bench-reportbenches/bmf.pymonoprop_bench_tools.bmf→monoprop-bench-bmftests/test_bench_*.pypackages/monoprop-bench-tools/tests/benches/third_party/packages/bench-third-party/All moves are
git mv, sogit log --followstill works.Design decisions worth reviewing
benches/does not move. Bencher keys its metric history on the benchmark name, so moving or renaming abench_*test orphans its tracked series and resets the thresholds' sample windows. The suite therefore cannot version with a library release, which is precisely the line between "harness" and "benchmarks".monoprop-bench-toolscontains no benchmarks.The bencher.dev tracking stays in the repo. Only the renderer (
bmf.py) is tooling and moved.bench_main.ymlcarriesBENCHER_API_KEY,vars.BENCHER_PROJECT, the--branch/--testbedidentity and the four threshold blocks — that is this repository's CI identity, and a published package cannot own a secret. The workflow itself is unchanged;just bench-bmfnow shells out to the console script.Three dependency groups instead of two.
test— monoprop's suite only, deliberately free of workspace members. cibuildwheel installs it against a built wheel viatest-groups = ["test"], where amonoprop-bench-toolsrequirement would resolve from PyPI (nonexistent) and drag monoprop back in from source.workspace-test—test+ the member. Whatuv run pytestat the root needs.bench—workspace-test+pytest-benchmark.bench-third-partyisexcluded from the workspace. It pins a narrowerrequires-python, a git dependency and linux-x86_64-only CUDA wheels; folding it in would drag all of that into the root lock. It stays a standalone uv project with its own lockfile (cd packages/bench-third-party && uv sync). It now depends onmonoprop-bench-toolsproperly instead of pokingbenches/ontosys.path.No
gpuextra on the tools package. Adding one putcupy-cuda12x+cuda-pathfinderinto the root lock. CuPy is installed separately;memory.gpualready degrades toMethod.UNAVAILABLEwithout it.Publishing
deploy.ymlgainsbuild-bench-tools(uv build --package monoprop-bench-tools— pure Python, no cibuildwheel matrix) and a separateupload_pypi_bench_toolsjob. Separate because it is a separate PyPI project, and because a failure there must not hold back the library's own upload. hatch-vcs reads the same git tags viaraw-options = { root = "../.." }, so the two distributions share a version line; verified that the wheel still builds from the sdist, where there is no git.Important
Before the next release someone has to register a trusted publisher for
monoprop-bench-toolson PyPI (this workflow file, thepypienvironment), orupload_pypi_bench_toolswill fail on its first run.Validation
uv lock --check,uv sync --all-groups --all-extraspytest -m "not mpi"→ 617 passed (both suites)just bench-smokeandjust bench-bmf smokeend to end through the console scriptspackages/bench-third-party/uv.lockre-resolvedprek run --all-filescleanDeliberate non-changes
packages/**is excluded from Sonar scope, preserving current behaviour. Bringing it in is a separate call.benches/results/*.jsonis untouched, so Bencher continuity holds.One seam this creates
benches/conftest.pywrites the results artifact schema andmonoprop_bench_tools.report/.bmfread it — now across a package boundary. Called out in both docstrings and inAGENTS.md: a change to the recorded sections has to land on both sides.Docs updated in the same change:
AGENTS.md(new "Workspace layout" section),README.md,docs/content/docs/benchmarks.mdx,docs/content/docs/testing.mdx,benches/README.md.