The same benchmarks CodSpeed runs, measured locally¶
linopy benchmarks its model construction with
pytest-benchmark and runs that suite on CodSpeed — which, since
its 2026 memory instrument, tracks memory as well as time. pytest-benchmem reuses those
exact tests: the benchmark(...) call is all it reads. No second suite, no new markers —
point it at the benchmarks you already have and get a memray memory profile locally, on
demand, without a CI round-trip or an account. It was extracted from linopy's suite to
be exactly that: the terminal companion for the numbers CodSpeed keeps in CI.
Here is the suite's model — linopy's "basic problem", an N×N LP — construction plus a
couple of LinearExpression operations, sized by n:
from numpy import arange
import linopy
def create_model(n: int) -> linopy.Model:
m = linopy.Model()
N, M = arange(n), arange(n)
x = m.add_variables(coords=[N, M], name="x")
y = m.add_variables(coords=[N, M], name="y")
m.add_constraints(x - y >= N)
m.add_constraints(x + y >= 0)
m.add_objective(2 * x.sum() + y.sum())
return m
The same test, in your terminal¶
An ordinary pytest-benchmark test — the one already in the suite — with
--benchmark-memory adding the peak on the same call it already times:
@pytest.mark.parametrize("n", [100, 200, 400])
def test_create_model(benchmark, n):
benchmark(create_model, n)
benchmark: 3 tests
Name (time in ms) Mean │ peak·min (MiB) peak·mean peak·max
──────────────────────────────────────────────────────────────────────────────────────
test_create_model[100] 83.0831 (1.0) │ 2.16 2.16 2.16
test_create_model[200] 87.1668 (1.05) │ 8.64 8.64 8.64
test_create_model[400] 100.9533 (1.22) │ 34.52 34.52 34.52
memory (right of │): a separate, untimed pass, not the timed rounds • also available
via --benchmark-memory-columns: allocated, allocations
3 passed in 8.72s
Peak next to the time, straight from the call. The peak climbs with the square of n
(~2 → ~35 MiB here) while the timer, mostly fixed overhead at this size, barely moves —
the kind of thing you want to catch before it becomes a model that won't build.
The local half of the loop¶
CodSpeed keeps the history, the dashboards, the PR annotations. pytest-benchmem is the
offline companion on the same tests, for the tight loop where a CI round-trip is too
slow — run it, then diff two runs, flamegraph where it
allocated, chart the scaling, or sweep across
installed linopy versions, all in the terminal:
benchmem compare base.json head.json --columns peak # what moved
benchmem flamegraph profiles/ --worst peak --open # where it allocated
benchmem sweep linopy 0.7.0 0.8.0 --suite bench/ # across versions
One suite, measured both ways. The Quickstart starts from benchmarks you already have.