Skip to main content

Memory benchmarking for Python, on the pytest-benchmark suites you already time: a memray peak-memory pass on the same tests, plus param-driven plots and cross-version sweeps.

Project description

pytest-benchmem

PyPI Python versions CI Docs Ruff License: MIT

pytest-benchmem measures how much memory your code allocates, on the same benchmarks you already time. It is for Python libraries and pipelines where memory is a real constraint: large numpy arrays, pandas frames, solvers, C/Cython/Rust extensions. If you already track performance in CI, you can track memory the same way and fail a PR when the footprint grows.

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, one JSON file, no test changes.

๐Ÿ“– Full documentation

Quickstart

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 memory pass is folded in to the right of the โ”‚. It runs as a separate, untimed memray pass: peak spreads into min/mean/max, and allocated / allocations are opt-in. A fourth metric, rss, is the whole-process physical peak the OOM killer watches; opt in per test with @pytest.mark.benchmem(isolate=True).

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.

Plot across inputs and versions

Your parametrize params become plot axes on their own โ€” no id parsing, no config. The n in parametrize("n", [...]) is a numeric x-axis, so benchmem plot draws a scaling curve from it:

benchmem plot run.json --columns peak     # peak vs n
benchmem plot run.json --columns time     # the same axis, timing instead

The plots read pytest-benchmark's own JSON, so they work on your timing results whether or not you ran the memory pass. Point --columns at time, peak, allocated, allocations, or rss, and facet by any other param or dim:

benchmem plot run.json --columns time --facet node.func

Sweep across installed versions of a package from one command:

benchmem sweep mypkg 1.2.0 1.3.0 main --suite bench/

Compare and gate CI

benchmem compare diffs two runs into a per-benchmark table. It shows time โ”‚ peak across every stat, each cell a relative (ร—) multiplier against the best run. Add --fail-on to fail CI on a regression:

test_build[n=5000]
             time (s)     time (s)      time (s)      time (s)      time (s)         peak (MiB)     peak (MiB)     peak (MiB)     peak (MiB)     peak (KiB)
 name             min          max          mean        median        stddev   โ”‚            min            max           mean         median         stddev
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 (base)       2 (1.0)    2.3 (1.0)    2.12 (1.0)    2.08 (1.0)    0.09 (1.0)   โ”‚    60.00 (1.0)    60.50 (1.0)    60.23 (1.0)    60.20 (1.0)    210.41 (1.0)
 (head)   2.05 (1.02)   2.4 (1.04)   2.18 (1.03)   2.12 (1.02)   0.11 (1.22)   โ”‚   72.00 (1.20)   73.20 (1.21)   72.53 (1.20)   72.40 (1.20)   510.86 (2.43)

You can also gate inline during the run with --benchmark-memory-compare-fail. Pass --benchmark-memory-profile DIR to keep the memray .bin of each offender, and benchmem flamegraph then shows where the memory grew.

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).

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 compared, swept, and plotted across inputs and versions.

Install

uv add pytest-benchmem            # the fixture + flag + memray engine
uv add "pytest-benchmem[plot]"    # + the benchmem plot/compare/sweep CLI (pandas, plotly, typer)

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. API may move before 1.0; see the changelog.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_benchmem-0.4.9.tar.gz (261.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_benchmem-0.4.9-py3-none-any.whl (76.4 kB view details)

Uploaded Python 3

File details

Details for the file pytest_benchmem-0.4.9.tar.gz.

File metadata

  • Download URL: pytest_benchmem-0.4.9.tar.gz
  • Upload date:
  • Size: 261.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pytest_benchmem-0.4.9.tar.gz
Algorithm Hash digest
SHA256 a7a22f778cc90653bddd954ce15b00c1551167b3f5f758835d95a598a8ddb2f7
MD5 eb2ccf7dd192063976c41b5c81ed3e0f
BLAKE2b-256 812fd55de3f83233c6266144fba42c2764bbd6aa12a1b9bb21f25610443e7691

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_benchmem-0.4.9.tar.gz:

Publisher: release.yaml on fluxopt/pytest-benchmem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_benchmem-0.4.9-py3-none-any.whl.

File metadata

  • Download URL: pytest_benchmem-0.4.9-py3-none-any.whl
  • Upload date:
  • Size: 76.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pytest_benchmem-0.4.9-py3-none-any.whl
Algorithm Hash digest
SHA256 a383f42065f272134fb4f8c0dbd1ec9a07c19dc9d12d45c5bb8fc2d7c4db0bfd
MD5 3472631b5330fca40f296a744e71f24b
BLAKE2b-256 a27a4585e18e68405de659e04f907fd84be47845e1c11826764d64fbe1fc3429

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_benchmem-0.4.9-py3-none-any.whl:

Publisher: release.yaml on fluxopt/pytest-benchmem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page