Benchmark matrices for Python projects that need performance data they can trust, compare, and parse
[!TIP] Read the benchmatrix documentation for the quickstart, usage guides, and API reference.
benchmatrix sits on top of pytest-benchmark and adds the layer that benchmark suites usually grow by hand: implementation-by-case matrices, strict JSON-safe metadata, metric-aware result parsing, and concise display of saved benchmark runs.
| Build repeatable suites | Keep metrics honest | Parse saved runs |
|---|---|---|
| Generate pytest benchmark tests across implementations, cases, and metric views. | Separate latency, throughput, and local distribution comparisons instead of mixing unlike numbers. | Load benchmatrix-tagged pytest-benchmark JSON rows into structured Python objects. |
Quick Start
Create a benchmark matrix from ordinary synchronous callables in a pytest file:
from benchmatrix import BenchmarkCase, make_benchmark_test
implementations = {
"builtin": sum,
"loop": lambda vs: sum(v for v in vs),
}
cases = [
BenchmarkCase.from_values(
"small",
list(range(100)),
work_units=100,
work_unit_name="items",
),
]
test_sum_matrix = make_benchmark_test(implementations, cases)
Run it with pytest-benchmark and keep the machine-readable output:
uv run pytest tests/test_sum_benchmark.py --benchmark-json benchmark.json
Read the run back and compare it with a controlled baseline:
from benchmatrix import display_benchmark_rows, load_benchmark_run
baseline = load_benchmark_run("baseline.json")
candidate = load_benchmark_run("benchmark.json")
display_benchmark_rows(candidate.rows)
comparison = baseline.compare_to(candidate)
if not comparison.passed:
for cell in comparison.regressed:
print(cell.implementation_name, cell.case_name, cell.metric_name)
Collect a controlled repeated-run group without managing output names by hand:
benchmatrix collect --runs 5 --output benchmark-runs -- \
uv run pytest tests/test_sum_benchmark.py
The collection directory contains numbered pytest-benchmark JSON files and an
atomic benchmatrix-manifest.json. Collection can recover without discarding
its audit trail:
# Continue attempts after an interrupted process.
benchmatrix collect --resume --output benchmark-runs
# Append bounded retries while preserving every failed attempt.
benchmatrix collect --retry-failed --output benchmark-runs
The manifest command and working directory are reused, accepted files are revalidated, and retry attempts append to the audit trail instead of replacing failures.
Compare collection directories directly:
benchmatrix compare baseline-runs candidate-runs \
--threshold 5% \
--fail-on-regression
Existing automation can still combine individual repeated files:
benchmatrix compare baseline-1.json candidate-1.json \
--baseline-run baseline-2.json \
--candidate-run candidate-2.json \
--threshold 5% \
--fail-on-regression
Keep comparison policy under review with the benchmark suite:
[tool.benchmatrix.evidence]
minimum_runs = 3
[tool.benchmatrix.regression]
default_threshold_percent = 5.0
[tool.benchmatrix.regression.by_metric]
tail_latency = 8.0
benchmatrix compare discovers the nearest pyproject.toml. CLI policy
options override their corresponding configured scalar without discarding
per-metric, implementation, case, or exact-cell thresholds.
Inspect or validate that policy without running benchmarks:
benchmatrix policy show
benchmatrix policy validate --quiet
Comparison JSON is a strict, versioned decision record that can be archived and loaded independently of the original timing files:
benchmatrix compare baseline-runs candidate-runs \
--format json > comparison.json
from benchmatrix import load_comparison_report
report = load_comparison_report("comparison.json")
print(report.schema_version, report.passed, len(report.regressed))
Publish the same report as Markdown or a GitHub Actions step summary:
benchmatrix compare baseline-runs candidate-runs --format markdown
benchmatrix compare baseline-runs candidate-runs --github-summary
Why It Exists
pytest-benchmark owns timing, calibration, statistics, terminal reporting, and JSON export. benchmatrix owns the repeatable structure around those timings.
| Need | benchmatrix gives you |
|---|---|
| Compare multiple implementations | One generated pytest benchmark matrix with optional untimed output validation. |
| Track what each timing means | JSON-safe invocation metadata with implementation, case, and metric identity. |
| Report different metric views | Single-call latency, logical-work throughput, and local tail-latency summaries. |
| Reuse benchmark output | Manifest-backed collection, repeated-run evidence diagnostics, environment checks, regression policies, and matrix comparisons. |
benchmatrix is intentionally narrow: it benchmarks synchronous Python callables. It is not a load-testing framework, production latency monitor, or replacement for pytest-benchmark.
Interpreting Results
Benchmark output is environment-specific. Compare results only between runs from controlled environments, and keep the pytest-benchmark JSON output with the hardware, Python, dependency, and CI context that produced it.
Use metric names as part of every comparison:
- single-call latency compares one completed synchronous target call;
- batch throughput compares logical work per second when
work_unitsis meaningful and consistent; - tail-latency summaries describe local distribution shape for a benchmark run, not production service latency.
Install
Install the released package with uv:
uv add benchmatrix
or with pip:
python -m pip install benchmatrix
For local development from this repository:
make ready
Documentation
The documentation source lives under docs/. The top-level Markdown
files are short project entry points; detailed guides, explanations, references,
and runbooks live in the MkDocs documentation.
| Start here | Use it for |
|---|---|
| First benchmark | A complete first benchmark from test file to parsed JSON. |
| Create a benchmark matrix | Cases, work units, fresh inputs, and synchronous target wrappers. |
| Parse benchmark results | Loading and displaying benchmatrix-tagged pytest-benchmark JSON. |
| Performance model | What the metrics mean and what they do not prove. |
| Development | Local setup, test commands, and repository layout. |
| Compatibility | Supported Python versions, API stability, and support policy. |
| Publishing | Release artifacts, draft releases, PyPI publishing, and verification. |
| Configuration and automation | Make targets, CI workflows, Docker checks, docs, and SBOM generation. |
The MkDocs site builds in strict mode and generates API reference pages from the package docstrings.
Project Links
License
benchmatrix is distributed under the MIT License.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file benchmatrix-1.0.0.tar.gz.
File metadata
- Download URL: benchmatrix-1.0.0.tar.gz
- Upload date:
- Size: 162.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
027b0c1d73170072234e1db6cb9a74b56ec3f65f9181f840b21967da10ff7832
|
|
| MD5 |
15929b03516b527f8c6080714e792133
|
|
| BLAKE2b-256 |
7d49e52a643959acad4938fe9fbe8c09a15c8471f52c8a1d38a26bfe39b856b1
|
Provenance
The following attestation bundles were made for benchmatrix-1.0.0.tar.gz:
Publisher:
release.yml on ryancswallace/benchmatrix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
benchmatrix-1.0.0.tar.gz -
Subject digest:
027b0c1d73170072234e1db6cb9a74b56ec3f65f9181f840b21967da10ff7832 - Sigstore transparency entry: 2296840449
- Sigstore integration time:
-
Permalink:
ryancswallace/benchmatrix@8233c3e15439f18f65ab33d965380b8b490d99c3 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/ryancswallace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8233c3e15439f18f65ab33d965380b8b490d99c3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file benchmatrix-1.0.0-py3-none-any.whl.
File metadata
- Download URL: benchmatrix-1.0.0-py3-none-any.whl
- Upload date:
- Size: 69.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc3b506b597c6981f1d037c422223f6836b5ee7b129f543082bd05f1115e66e2
|
|
| MD5 |
54f94bd9a4398ddbf4b34d1df05bc9d5
|
|
| BLAKE2b-256 |
c3fd2d7166db6e8a30d414ec7a24933f84d58c3d5aaee8673a2ad7164adcc87f
|
Provenance
The following attestation bundles were made for benchmatrix-1.0.0-py3-none-any.whl:
Publisher:
release.yml on ryancswallace/benchmatrix
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
benchmatrix-1.0.0-py3-none-any.whl -
Subject digest:
cc3b506b597c6981f1d037c422223f6836b5ee7b129f543082bd05f1115e66e2 - Sigstore transparency entry: 2296840509
- Sigstore integration time:
-
Permalink:
ryancswallace/benchmatrix@8233c3e15439f18f65ab33d965380b8b490d99c3 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/ryancswallace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8233c3e15439f18f65ab33d965380b8b490d99c3 -
Trigger Event:
release
-
Statement type: