pytest-benchmem
On-demand memory profiling for your benchmarks. pytest-benchmem measures how much memory your code actually uses — and shows you where it goes — on the pytest-benchmark tests you already have. Find the heavy path, fix it, confirm the drop. It's for Python libraries and pipelines where memory is a real constraint: large numpy arrays, pandas frames, solvers, C/Cython/Rust extensions.
It builds on pytest-benchmark. Add one flag to an existing suite and a memray peak-memory number lands next to the timings — same test, same run, no test changes. When a number looks heavy, keep the profile and open a flamegraph to see the allocating call paths.
1. Measure — spot the heavy benchmark
Take an existing pytest-benchmark test. You don't change it:
import pytest
@pytest.mark.parametrize("n", [10_000, 100_000, 1_000_000])
def test_sort(benchmark, n):
benchmark(sorted, list(range(n, 0, -1)))
Add --benchmark-memory to the run:
pytest --benchmark-only --benchmark-memory --benchmark-columns=min,mean,median
Name (time in us) Min Mean Median │ peak·min (KiB) peak·mean peak·max
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
test_sort[10000] 30.2079 (1.0) 37.3511 (1.0) 38.6250 (1.0) │ 78.12 78.12 78.12
test_sort[100000] 299.2500 (9.91) 404.0027 (10.82) 408.5415 (10.58) │ 781.25 781.25 781.25
test_sort[1000000] 3,667.6250 (121.41) 4,427.5485 (118.54) 4,361.7500 (112.93) │ 7,812.50 7,812.50 7,812.50
The timing table is untouched; the memray peak-memory pass is folded in to the right of the │,
as a separate, untimed run. peak spreads into min/mean/max; allocated / allocations are
opt-in. Already rebuild state with benchmark.pedantic(setup=…)? The same setup runs (untracked)
before each memory sample, so stateful benchmarks stay accurate with no extra changes.
2. Find where the memory goes
A peak number tells you which benchmark is heavy, not where the memory goes. Keep the memray profile for the offenders, then render the allocating call paths:
pytest --benchmark-only --benchmark-memory --benchmark-memory-profile profiles/
benchmem flamegraph profiles/ --worst peak --open # render the heaviest, open it
The .bin is memray's raw capture, so it also feeds memray tree / summary / stats. For a
native-backed workload (polars/Rust, numpy/C), add --benchmark-memory-profile-native so the
flamegraph attributes memory to the real C/Rust frames instead of one opaque bucket.
3. Confirm the fix
Change the code, re-run, and diff the two runs to see the peak actually dropped:
benchmem compare before.json after.json --columns peak --diff
compare reads pytest-benchmark's own JSON and lays the runs side by side, keyed on the benchmark
id — --diff shows a signed Δ% per benchmark so the win (or the regression) reads at a glance.
Also available
Newer, less battle-tested than the profiling loop above — feedback welcome:
- Guard CI against a regression (
benchmem compare … --fail-on peak:10%) or against an absolute ceiling (@pytest.mark.benchmem(max_peak="500MiB")). - Plot scaling curves straight from your
parametrizeparams (benchmem plot run.json --columns peak), and sweep a metric across installed package versions (benchmem sweep mypkg 1.2 1.3 main). rss— the whole-process physical peak the OOM killer watches — via@pytest.mark.benchmem(isolate=True), for container/capacity questions.
Why memray, and where it sits
memray tracks the allocator directly. It catches the numpy/C-allocation detail that RSS sampling
(ASV's peakmem) misses, and folds out the interpreter baseline. pytest-benchmem uses
pytest-benchmark for timing and reads and writes its JSON. It does not reimplement timing, a CI
dashboard (CodSpeed), or cross-commit history (ASV).
For continuous CI tracking, reach for CodSpeed — history, dashboards, PR annotations. It runs
pytest-benchmark's benchmark() too, so the same tests serve both: write the benchmark once, let
CodSpeed watch timing in CI and pytest-benchmem profile memory on demand. No rewrite, no second set
of benchmarks.
vs pytest-memray: both wrap memray, pointed in opposite directions, and they complement each
other. pytest-memray is a guardrail — limit_memory and leak detection over the whole test.
pytest-benchmem is a benchmark: only the benchmarked action, measured alongside timing, then
profiled, compared, and plotted across inputs and versions.
Install
uv add pytest-benchmem # the fixture + flag + memray engine + benchmem sweep CLI
uv add "pytest-benchmem[plot]" # + benchmem compare tables and plot views (pandas, plotly)
memray is Linux/macOS only; Windows installs cleanly with timing-only (the memory pass raises a clear error there).
Status
Early — extracted from the linopy benchmark suite. The measure → profile → fix loop is the hardened core; the Also available features are newer and may move before 1.0. See the changelog.
Metadata
Release files for pytest-benchmem 0.5.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pytest_benchmem-0.5.5.tar.gz | 479.8 kB | With provenance | Details for pytest_benchmem-0.5.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pytest_benchmem-0.5.5-py3-none-any.whl | Python 3 | none | any | Details for pytest_benchmem-0.5.5-py3-none-any.whl |
Total release size: 568.6 kB
Release files / pytest_benchmem-0.5.5.tar.gz
| Download URL | pytest_benchmem-0.5.5.tar.gz |
|---|---|
| Size | 479.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35ce096e350976e6c3e85f9569d910241d5b554c8d332aacb8d039d9a30e5824
|
|
BLAKE2b-256 checksum How to use checksums |
85bb58aa2ee6df1e8ffc8a224d61aa224f17ac3ccebaade541fd507b9694ddd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / pytest_benchmem-0.5.5-py3-none-any.whl
| Download URL | pytest_benchmem-0.5.5-py3-none-any.whl |
|---|---|
| Size | 88.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2a2bcc90fff2c6c5e196573dcf5b6fd84040186e1ed42adef9cea141cb7b2c06
|
|
BLAKE2b-256 checksum How to use checksums |
9b90101196c24ffff5f6344e4c50b11a07bf8c4fafb88f960664dbede0cbd38a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logSecurity for pytest-benchmem 0.5.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pytest_benchmem-0.5.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.