From b25168178b5ae2543e91cc5e2f2780912a908698 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:21:27 +0200 Subject: [PATCH 1/2] =?UTF-8?q?refactor(benchmarks):=20lean=20up=20?= =?UTF-8?q?=E2=80=94=20trim=20docstrings/comments,=20dedupe=20plotting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavior-preserving readability pass: - plotting.py: extract _metric_label (4x) and _diverging_kwargs (3x); cut comments that restate code, keep the plotly-quirk ones; tighten docstrings. - memory/bench/registry/snapshot: trim the 21-34 line module docstrings to essentials (keep the non-obvious why); fix stale lp_write -> to_lp refs. - sweep.py: trim restate comments (orchestration left as-is — no test coverage). No logic/API/CLI change; -84 lines. Verified: mypy clean, smoke 172 passed, _tests 14 passed, walkthrough notebook renders all plots. Co-Authored-By: Claude Opus 4.8 (1M context) --- benchmarks/bench.py | 34 +++---- benchmarks/memory.py | 39 +++----- benchmarks/plotting.py | 198 ++++++++++++++++------------------------- benchmarks/registry.py | 23 +++-- benchmarks/snapshot.py | 36 ++++---- benchmarks/sweep.py | 12 +-- 6 files changed, 129 insertions(+), 213 deletions(-) diff --git a/benchmarks/bench.py b/benchmarks/bench.py index 17d74bcbc..212b22165 100644 --- a/benchmarks/bench.py +++ b/benchmarks/bench.py @@ -1,36 +1,24 @@ """ Ad-hoc benchmarking of arbitrary callables on the *current* linopy tree. -Where the pytest suite measures the fixed registry grid and ``sweep`` -measures across installed linopy versions, ``bench`` is for the -interactive middle: time or memory-profile any callable — a registry -builder, a phase verb applied to a model you built by hand, or a one-off -lambda — get a result object back, and either inspect it as a DataFrame -or drop it into a snapshot the existing ``plot`` / ``compare`` machinery -already understands:: +Where the pytest suite measures the fixed registry grid and ``sweep`` measures +across installed linopy versions, ``bench`` is the interactive middle: time or +memory-profile any callable, get a result object, inspect it as a DataFrame or +drop it into a snapshot the ``plot`` / ``compare`` machinery already reads:: from benchmarks import bench, REGISTRY r = bench.time(REGISTRY["basic"].build, 100) - r # rich repr in a notebook r.to_snapshot("a.json", spec="basic", size=100, phase="build") - bench.compare({"v1": f1, "v2": f2}).to_snapshot("cmp.json") -This plugs into the *output* side of the pipeline (snapshot JSON read by -``snapshot.load_long_df``), not into ``sweep``: a sweep runs pytest inside -per-version venvs as subprocesses, so it can only measure importable -registry models — an in-process callable can't cross that boundary. To -sweep a custom model across versions, promote it to ``benchmarks/models/``. - -**Methodology.** Timing is built on :class:`timeit.Timer`: an -``autorange`` calibration picks the inner iteration count (so timer -resolution doesn't dominate fast callables), then the per-iteration time -is sampled across rounds with the suite's min-of-N convention (the -fastest sample approximates the no-noise floor). It is *not* -pytest-benchmark's calibrated timer, so absolute numbers are not -interchangeable with suite snapshots — compare ``bench`` to ``bench`` and -suite to suite. +It feeds the output side (snapshot JSON), not ``sweep`` — a sweep runs pytest in +per-version venvs, so only importable registry models cross that boundary; +promote a custom model to ``benchmarks/models/`` to sweep it. + +Timing uses :class:`timeit.Timer` (``autorange`` picks the inner iteration count +so resolution doesn't dominate) with the suite's min-of-N convention. It is *not* +pytest-benchmark's timer, so compare ``bench`` to ``bench``, suite to suite. """ from __future__ import annotations diff --git a/benchmarks/memory.py b/benchmarks/memory.py index 83d13897a..7f5c69a01 100644 --- a/benchmarks/memory.py +++ b/benchmarks/memory.py @@ -1,37 +1,22 @@ """ Measure and compare peak memory across the registry × phase grid. -Each measurement uses ``memray.Tracker`` directly so the model construction -(setup) lives *outside* the tracked region and the peak reflects only the -phase work itself:: +Each measurement runs the phase work inside ``memray.Tracker`` with model +construction *outside* it, so the peak reflects only the phase:: m = spec.build(size) # setup, not tracked with memray.Tracker(bin_path): wrapper(m) # tracked - peak = FileReader(bin_path).metadata.peak_memory - -This module exposes ``save(label, ...)`` and ``compare(label_a, label_b)`` as -plain functions; user-facing invocation goes through the typer CLI:: - - python -m benchmarks memory save