Skip to content

chore: update the benchmark scripts and documentation - #148

Open
ludmilaasb wants to merge 109 commits into
mainfrom
chore/update-benchmarks
Open

chore: update the benchmark scripts and documentation#148
ludmilaasb wants to merge 109 commits into
mainfrom
chore/update-benchmarks

Conversation

@ludmilaasb

@ludmilaasb ludmilaasb commented Jul 24, 2026

Copy link
Copy Markdown
Member

By opening this PR I confirm that I have read CONTRIBUTING.md and I agree to the terms of the Contributor License Agreement.

Summary

This PR updates the 3rd party benchmark scripts. The SPECS are the same, the number of quibits is increased for Pauli Propagation and the scripts for comparing with MajoranaPropagation.jl were improved and simplified.

Changes

  • Benchmarks page updated
  • Majorana scripted comparison refactored
  • Activated multi-threading for PauliPropagation.jl

Checklist

  • Tests added or updated to cover the changes
  • Documentation updated (docstrings, docs/, CONTRIBUTING.md) if needed
  • CHANGELOG / release notes updated if applicable

AI/LLM disclosure

  • I did not use LLM tooling, or used it only privately for ideation
  • I used the following tool to help write this PR description:
  • I used the following tool to generate or modify code: Claude Code Sonnet 5

diagonal-hamiltonian and others added 30 commits July 18, 2026 11:44
…untime

Re-homes the performance work from perf/align-with-paper onto the current
public interface (#40). The diff vs main is performance-only; the propagator
Python/C++ interface is unchanged.

What lands:
- Rebuilt evolution/layer-build engine (detail/evolution/layer_build/*,
  CosineRecompute, LayerBuilder) aligning the build path with the paper, plus
  the operator store rework (detail/operator/{MPOperator,OperatorIndex,
  InvertedIndex}) and cosine-recompute graph encoding, replacing the old
  masked_execution_plan / MPGraphEncodingCompression / EvolutionMajorana.
- Operator sharding runtime (detail/shard/{CpuTopology,ShardGroup},
  detail/mpi/*): one single-threaded shard per physical core is the default
  parallelism (shards=0 => auto), composing MPI ranks and shards into one flat
  hybrid world; query (two-pass) is the sole cross-rank exchange protocol.
- In-repo std::thread pool (run_static) replacing oneTBB; drop the oneTBB
  dependency from CMake, packaging, and the Config export.
- Additive-only public surface: basis/shards ctor kwargs (defaulted),
  evolved_operator_terms, __deepcopy__ — main's interface otherwise untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the C++ unit suite to the ported engine internals (OperatorIndex /
MPOperator / cosine-recompute, the shard runtime, the align mpi:: transport).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two engine-behavior adaptations, no interface changes:
- Sharding is now the default parallelism, so white-box tests that inspect raw
  per-partition internals (graph_data()) opt out via a new @pytest.mark.unsharded
  marker (autouse fixture sets monoprop_SHARDS=off before construction).
- upper_atol in the rebuilt build path RESCUES over-cutoff partner terms (it can
  only add terms, never drop). At cutoff 6 the LiH molecule has no over-cutoff
  partners, so exercise the rescue at cutoff 2 where it observably changes the size.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oops

Every parallel_for_*/parallel_reduce_* wrapper and the layer-build chunk
helpers (for_each_chunk / append_*_in_order) took a serial-fallback branch
on the default shard runtime — each shard master sets gate_serial_override,
so effective_parallelism() reports 1 and the pool threads never start. Only
the non-default SHARDS=off path ever engaged them.

Rewrite all ~46 call sites (13 files) as the plain serial loop each wrapper's
fallback already ran, so results are bit-identical on the default path. The
in-repo thread pool (Threading.h/.cpp) and Parallel.h still exist after this
commit; they lose their last callers and are deleted next.

Bit-exactness: reductions were already chunk-order-deterministic, so the
serial folds reproduce them exactly. FP association differs ONLY on the
demoted paths (SHARDS=off, explicit shards=1 off a master, pure-MPI unbound
ranks): inner_product, accumulate_cos_*, and the endpoint-contrib folds get
serial association there; those paths' tests are tolerance-based.

Also collapses the now-single-table OperatorIndex bulk_insert (deletes the
counting-sort branch), the InvertedIndex row-block-parallel fill + its
persistent staging members, and folds the single cosine block set in the
layer-build scan directly into the result.

Validated: MPI-OFF C++ unit tests 102/102 "No errors detected".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ue tests

The rescue invariant is independent of the shard/thread count (each shard
runs its partition serially), so the thread-mode axis is meaningless. Drop
the ScopedParallelismCap guard and the thread_mode_values() axis: 4 tests
per (fixture, comm) instead of 8. Removes this suite's dependency on
Threading.h ahead of deleting the pool. snapshot_invariance.cpp: reword the
comment off the now-gone parallel_reduce_indices.

Validated: MPI-OFF C++ unit tests 98/98 "No errors detected" (was 102).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e only parallelism

The pool primitive (run_static), the parallel_for_*/parallel_reduce_* wrappers,
the gate_serial_override TLS, ScopedParallelismCap, and the layer-build chunk
helpers now have no callers (all rewritten to serial loops). Delete them:

  - src/monoprop/Threading.{h,cpp}
  - src/monoprop/detail/evolution/layer_build/Parallel.h

and every #include of them, plus the two dead detail:: wrappers in
EvolutionHelpers.h, the gate_serial_override write in ShardGroup, the
init_from_env() calls in MPICompat and the nanobind module init, and
Threading.cpp from the library sources.

monoprop_NUM_THREADS is unaffected: resolve_shard_count_ reads
config::get().num_threads directly, never the (now-gone) pool. std::thread is
still used by ShardGroup and the ShmComm/HybridComm barriers, so Threads::Threads
stays linked. Breaking (!) because installed public headers/symbols (Threading.h,
run_static_impl, init_from_env, ScopedParallelismCap, current_max_parallelism)
are removed.

Validated: MPI-OFF C++ unit tests 98/98 "No errors detected".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
busy_ns/tasks and the capture()/TaskScope machinery existed to attribute
parallel-task time to a dispatch region across pool worker threads. With the
pool gone and each shard running its region serially, they have no producers.
Drop capture(), TaskScope, profiling_current(), RegionAcc::busy_ns/tasks, and
ScopedRegion's prev_ save/restore. The monoprop_PHASE dump is now
wall_ms + calls per region.

Validated: MPI-OFF C++ unit tests 98/98 "No errors detected".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y shim

CpuTopology.h is now the ONE platform-specific file: its whole body (the /sys
parse, L3-domain interleave placement, pthread_setaffinity_np) sits under
`#if defined(__linux__)` with a `using CpuSet = cpu_set_t;`, and a portable
`#else` provides an empty CpuSet plus no-op enumerate/shard_cpusets/pin — so no
Linux type or header leaks out (ShardGroup now holds std::vector<CpuSet>). The
portable shard-count fallback (hardware_concurrency()/2) is unchanged; macOS
additionally reports its physical-core count via sysctl for accurate auto
sharding even though it cannot pin.

Two correctness/portability fixes a topology package (hwloc) would have given —
done in ~15 lines instead of a bundled C dependency:
  - enumerate_physical_cores() intersects with sched_getaffinity(): a
    cgroup-restricted / partial Slurm allocation now reports and pins only ITS
    cores, instead of enumerating all 112 and oversubscribing / pinning outside
    the mask (previously masked only because the sbatch scripts set NUM_THREADS).
  - monoprop_SHARD_PINNING moves into EnvConfig (config::get().shard_pinning),
    parsed once with the shared parse_flag; semantics identical.

hwloc was evaluated and rejected: it replaces only the ~75-line /sys parse and
the 3-line pin call (the ~80-line placement policy survives on top of it),
cannot pin threads on macOS regardless, and would re-add a bundled autotools C
dependency right after TBB/quill were dropped.

Validated: MPI-OFF C++ unit tests 98/98 "No errors detected".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TBB is neither used nor a build dependency. Remove the leftover mentions the
engine's TBB removal never swept: the libtbb-dev / brew tbb installs in CI
(test.yml, docpages.yml, copilot-setup-steps.yml), the README and AGENTS.md
dependency lines, and a stale benches comment. No build/behaviour change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parallelism.mdx claimed monoprop used oneTBB with a monoprop_NUM_THREADS worker
count. Rewrite it around the real model: one serial shard per physical core by
default, composing with MPI into an R×S world. Document all five runtime env
vars (NUM_THREADS, SHARDS, SHARD_PINNING, PHASE_TIMERS, RECOMPUTE_CACHE_MAX_MB),
the measured 6-9x (Pauli) / ~2x (Hubbard) win over the former pool, the
non-Linux/partial-allocation fallbacks, and why there is no hwloc dependency.
Fix the "oneTBB worker count" line in benchmarks.mdx and the sharding-controls
link blurb in building.mdx.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a `topology` field to KickedIsingConfig with a `_topology_edges` helper:
"heavy-hex" (default, byte-identical to today's 127q map) or "chain" (1D
nearest-neighbour), so the qubit count can be swept for scaling studies.

Record for fixed-model runs the same non-timing quantities the random benches
capture (term count, operator/graph storage, resting PSS) keyed by model name,
plus `membase` (resting PSS before the build) so the operator's persistent
footprint can be isolated as memrest - membase.

Fall back to serial when mpi4py is present but cannot dlopen libmpi (the ABI
wheel on a serial node), not only when it is absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
operator_memory_bytes()/graph_memory_bytes() require an unsharded propagator
and raise once the operator shards under multi-thread parallelism, which failed
the fixed-model point (and tripped the sweep's ratchet). The byte count is
thread-count-independent, so the serial run captures it; skip it when sharded
rather than fail, keeping time/PSS/term-count recording intact for every point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-width cap

Expose a per-component operator memory breakdown plus popcount / support-window /
diagonal-count histograms and the inline width via MonomialPropagator and the
Python bindings, to attribute per-term byte cost in the scaling study.

Split OperatorIndex's single inline-width constant into kDefaultInlinePositions=11
(byte-identical default for Schrödinger/opaque-cutoff rows) and kMaxInlinePositions=32,
and derive packed_inline_width_ from the cutoff (2*cutoff for a Pauli support bound) so
cutoff-bounded terms stay inline instead of spilling to the mutex-guarded overflow arena.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…local-symplectic

Fold the sweepable pauli-chain bench topology (per-model stats, sharded storage
accounting) and the operator memory/popcount diagnostics onto the JW-free
native-Pauli fix branch so it can drive its own memory+speed A/B.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…frame

Route PauliPropagator onto the engine's native Basis::Pauli path instead of the
Jordan-Wigner Majorana image. JW packed a weight-1 X_q as a Majorana monomial of
popcount 2q+1 = O(N), so operator memory grew with the qubit count at fixed cutoff.
The local packing (X_q->slot 2q, Y_q->slot 2q+1, Z_q->{2q,2q+1}) gives popcount
<= 2*weight, independent of N (verified: X on the top qubit is popcount 1 at every N).

- dispatch generator + _init_simulator: thread a `basis` argument through to the core
  (the binding already accepted it); PauliPropagator passes basis="pauli".
- conversion_utils: _pauli_to_local_slots / _local_slots_to_pauli (encode/decode,
  mirroring slots_of_string / letter_from_bitset in the C++ tests).
- PauliOperator.get_local_operator(): pack terms into local slots with real coeffs.
- circuit._gate_layers: native branch emits (local slots, real g) directly -- no
  jw_coeff, no antihermitian normalization (the Pauli rotation kernel handles phase).
- PauliPropagator: ingest via get_local_operator, cutoff_type="support", no basis_change;
  evolved_operator() now decodes to a PauliOperator (was a raw index dict).

No C++ engine changes: the native path is already implemented and validated
(tests/cpp/pauli_build_layer_tests.cpp T6/T7). Full Python suite green (365 passed);
the qiskit-reference evolution test matches at 1e-6.

BREAKING CHANGE: PauliPropagator.evolved_operator() returns a PauliOperator (Pauli-keyed)
instead of a dict keyed by Jordan-Wigner Majorana index tuples.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route PauliPropagator onto the engine's native local-symplectic (Basis::Pauli) path instead of Jordan-Wigner Majorana storage. Fixes the O(N) memory growth (JW popcount artifact): operator store is now N-flat (~54.7 B/term, 0 overflow) with popcount O(cutoff). Arch-native compute A/B (job 49844575) vs a same-build JW shim: energies bit-identical, term counts identical, build_graph 1.98x-7.30x faster single-thread. C++ arbiter tests (pauli_build_layer_* T6/T7, pauli_algebra_*, shard_equivalence_*) green. Python-only change; no C++ algebra touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The per-layer fold cache retained a (sum of mask_words * 8B) buffer per functional and
was gated by monoprop_RECOMPUTE_CACHE_MAX_MB. A functional-path A/B (2026-07-20) showed
it bought <=5% per eval -- and LOST for large operators, its buffer going cold faster
than the L1-blocked recompute rebuilds it -- while costing 0.3-1.0 GB per 1.7M-term
operator and creating a silent mid-sweep regime change in scaling benchmarks. Time-only
break-even was 22-70 evals: trading GB of memory for a shrinking (then negative) speedup
is backwards for a scaling-focused library.

build_cos_callbacks now always takes the recompute (LazyFold) path. make_fold_cache /
scale_cos_cached / fold_to_cos_mask survive only as the one-shot pare materializer and
the C++ recompute-equivalence-test oracle (no retained buffer, no scale cost).

Validated: C++ suite 106/106 cases, 1,413,155 assertions pass (incl.
*cache_equals_recompute*); Python results bit-identical to pre-change; the cache-vs-
recompute peak-RSS gap collapses from +600-950 MB to +/-1 MB; pytest functional/exact
slice 33 passed, 1 skipped.

BREAKING CHANGE: the monoprop_RECOMPUTE_CACHE_MAX_MB environment variable is removed;
cosine folds are always recomputed on the fly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Matteo AC Rossi <9745862+matteoacrossi@users.noreply.github.com>
Attacks the anticommutation fold, measured at ~60-70% of per-gate cost, using
the bimodal gate-participation structure (most gates anticommute with almost
nothing yet the fold streamed all K/64 operator words regardless).

- Zero-postings early-out: a generator whose inverted-index fold columns hold
  no postings provably anticommutes with nothing (even |G|; Pauli is always
  even in this path), so pass 1 + pass 2 are skipped entirely. A dense column
  always holds >=1 posting, so the emptiness test is O(|G|) sparse-size reads.
  Fires on ~70% (hubbard) / ~64% (pauli) of per-shard gate scans, removing that
  share of fold busy-CPU at high shard counts. The g_odd guard is load-bearing:
  an odd Majorana generator anticommutes with the odd-weight terms it is
  disjoint from, so zero overlap does not imply commutation there.
- Lazy sparse-pivot expansion: a sparse pivot column is scatter-expanded only
  for fold blocks that produced a nonzero overlap word; empty blocks (the common
  case on low-participation gates) no longer pay the expansion stream. Dense
  pivots stay folded inline (deferring them regressed hubbard +7.6%).
- combine_columns_block seeds its scratch from the first dense column by memcpy
  (XOR-commutative) instead of memset + XOR-all, saving one pass over the block.

New monoprop_FOLD_STATS env knob (default OFF, zero-overhead when disabled,
RegionProfiler atexit dump): per-gate {all-sparse?, sum postings, K/64, n_anti,
structural rejects} + a log2 postings/(K/64) histogram. The sizing data it
produced ruled out two further proposals (candidate-merge discovery and a
bit-sliced structural prefilter) as sub-single-digit on the real workloads.

All changes bit-identical (verified: full C++ suite + real-MPI R=2 green;
AB probe byte-for-byte vs baseline, hex-float 0x1.2a7a10767e528p+0 preserved).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove ~150 lines of copy-pasted Pauli oracle code duplicated between
pauli_algebra_tests.cpp and pauli_build_layer_tests.cpp into a shared
PauliTestOracle.h (native/JW encoding, dense Pauli-matrix brute force,
string helpers). Factor the ShmComm/HybridComm thread-spawn harness into
ThreadHarness.h (run_comm_threads), and hoist the duplicated near() float
comparison and LihFixture into TestUtilities.h; slots_of_string, the near()
constant, and RandomExactFixture now come from the shared headers across the
equivalence suites.

Merge the two single-case files into their neighbours: utilities.cpp
(even/odd-bit helpers) -> mpfunctions.cpp, snapshot_invariance.cpp -> the
recompute-equivalence file that exercises the same machinery.

Rewrite the stale tests/cpp/README.md (wrong binary name, deleted-file list).

Behaviour-preserving: C++ 94/94 serial + MPI green, no test cases removed
beyond the two folded ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove validators with zero callers anywhere in the codebase (verified by
repo-wide grep, incl. bindings and Python): determine_evolution_mode,
validate_evolution_parameters, validate_graph_state_for_mode, validate_params,
validate_propagation_params, validate_propagation_contraction,
validate_param_map_gen_coeffs_majoranas_match, the EvolutionMode enum, and the
private has_complete_evolution_parameters helper. The live surface
(validate_coefficient_lengths, validate_gate_indices, validate_parameters_length,
validate_functional_call, validate_expected_graph_layers, validate_equal_sizes)
is untouched.

No behaviour change: the deleted symbols had no callers, so nothing in the hot
path is affected. Library relinks clean; C++ + Python suites green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add direct unit coverage for structures that were only exercised indirectly
through the engine end-to-end:

- bitset_tests.cpp: Bitset ctor top-mask, cross-word count_and/parity_and,
  multi-word shift and find_first/find_next, position-sensitive hash, plus a
  randomized differential fuzz against std::bitset.
- majorana_cutoff_tests.cpp: length/support cutoff (incl. logical_num_modes
  masking on single- and multi-word paths), CutoffEvaluator dispatch +
  popcount fast path + max_positions_bound, interleave_phase vs its masked-
  parity form, encode/decode_coeff round-trip and non-Hermitian throw.
- validation_tests.cpp: the live parameter validators (accept + reject paths).
- mpi_utils_tests.cpp: find_rank determinism/range/hash-mod and the Majorana
  word (de)serialization round-trip.
- evolution_detail_tests.cpp: MatchedEpochSet O(1)-clear / tail-grow / u32 wrap
  and the CutoffContext atol/upper-atol gating predicates.
- row_accessor_tests.cpp: dense-vector vs OperatorIndex backend differential
  for materialize_row/assign_row/row_popcount/for_each_row_position.
- ctor_validation_tests.cpp: MonomialPropagator ctor guards (logical_num_modes,
  Pauli+cutoff/basis_change, atol ordering, operator index range),
  propagate()-on-nonempty-graph, and MPGraph::get_layer bounds.

40 new cases; full suite 134 serial + MPI green. Validation.cpp coverage
28% -> 95%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The monoprop_WIDE_TERM_INDEX=ON configuration (64-bit TermIndex) was never
built anywhere, so the wide `#if defined(monoprop_WIDE_TERM_INDEX)` branches in
operator_index_tests / large_cosine_storage_tests were dead in CI. Add:

- CMakePresets: release-gcc-wide configure/build/test presets.
- justfile: `test-cpp-wide` (build + serial ctest under wide) and a
  `coverage-cpp` convenience recipe encoding the gcovr invocation.
- CI: a `cpp-wide` job (gcc-14, Release + WIDE_TERM_INDEX=ON, serial ctest) so
  the wide branches are compiled and run on every push.

Verified locally: wide build is green (serial 128/128) and the wide-only
term-index-width case executes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… backbone

Make the code's names and types state the essence: one monomial container, two
algebra models, and a propagation backbone that is generic over the algebra.

Clean break — old names are removed outright, no back-compat aliases. Bit-exact
and perf-neutral: each policy method wraps the existing kernel, and the runtime
Basis is bound to a compile-time model exactly once via with_algebra, replacing
the compile-time IsPauli flag and every scattered `if (basis == Basis::Pauli)`.

- core/Monomial.h: split the monomial vocabulary out of TypeAliases.h.
  MajoranaSet<N> -> Monomial<N> (Bitset<2N>: a Majorana product, or its
  Jordan-Wigner-image Pauli string); MajoranaVector -> MonomialList;
  MajoranaOperator (C++ map alias) -> MonomialMap; MPHash/MPEqual/majorana_hash
  -> MonomialHash/MonomialEqual/monomial_hash. The Python class MajoranaOperator
  is unchanged.
- algebra/: MajoranaAlgebra.h and PauliAlgebra.h move here as true siblings over
  a new AlgebraCommon.h (shared structural primitives); PauliAlgebra no longer
  includes MajoranaAlgebra.
- algebra/Algebra.h: the Algebra concept, the MajoranaAlgebra/PauliAlgebra policy
  models, the with_algebra(Basis, fn) dispatcher, and point-dispatch helpers for
  the cold sites that carry a runtime Basis.
- backbone: fused_find_and_collect and the cosine fold are templated on the
  algebra policy; every basis branch outside the policy is gone, including the
  last two in MPOperator (HF scoring via algebra_score_hf, coeff codec via
  algebra_encode_coeff).
- tests: reference-only helpers moved to tests/cpp/AlgebraReference.h.
- docs: AGENTS.md core-abstractions section + an essence doc on core/Monomial.h.

BREAKING CHANGE: the C++ core type names change (MajoranaSet -> Monomial and
friends) and the two algebra headers move under algebra/. Out-of-tree subclasses
such as MonomialPropagatorExtra must update to the renamed types and paths.

Verified on host bebe (gcc-14): C++ 127/127, MPI 135/135 (+ 4-rank clean),
wide-index 128/128, Python 447 passed / 8 skipped; exact-value suites bit-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Matteo AC Rossi <9745862+matteoacrossi@users.noreply.github.com>
Comment thread benches/third_party/pauli_prop/run_monoprop.py Outdated
@ludmilaasb ludmilaasb closed this Jul 28, 2026
@ludmilaasb ludmilaasb reopened this Jul 28, 2026
Base automatically changed from perf/align-with-paper to main July 28, 2026 13:48
@ludmilaasb

Copy link
Copy Markdown
Member Author

Ok, the merging got messed up. Fixing it

Comment thread benches/third_party/majorana_prop/monoprop_hubbard1d_benchmark.py Outdated
ludmilaasb and others added 2 commits July 30, 2026 11:42
Co-authored-by: Roberto Di Remigio Eikås <robertodr@users.noreply.github.com>
Signed-off-by: Ludmila Botelho <39570941+ludmilaasb@users.noreply.github.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 10, 2026
The per-backend `memory` series mixed four incommensurable quantities: monoprop's
operator accounting, an RSS ratchet for ppvm and Qiskit, and a device pool for the
GPU. Take the peak from the kernel's VmHWM in `_run_steps` instead, so every engine
is measured by one instrument over the timed region, and keep each library's own
figure in a separate `operator_memory` series. `run_scaling.jl` follows suit.

Resetting VmHWM also resets `ru_maxrss` and `Sys.maxrss()` (both read
`mm->hiwater_rss`), so the whole-run ceilings now take the maximum over the windows.

Drop the per-backend runner scripts: `run_one.py` already isolates each backend in
its own process, and `model.py` defines the circuit once rather than once per runner.

Assisted-by: GitHubCopilot:claude-opus-5
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Aug 11, 2026
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants