Simple and fast benchmarking utilities for Python functions
Project description
bencheetah
Simple, zero-dependency benchmarking utilities for Python functions — now with scaling experiments and charts.
Why bencheetah?
timeit is verbose. cProfile is overkill for quick comparisons. bencheetah gives you:
- Statistical timing (mean, min, max, stdev) for a single function.
- Side-by-side comparison of multiple implementations.
- Scaling experiments: sweep a range of input sizes and plot execution time vs. n — ideal for empirically verifying algorithmic complexity.
- Beautiful terminal tables and matplotlib charts with a single call.
No dependencies for the core functions. matplotlib only needed for plotting.
Installation
# Core (no dependencies)
pip install bencheetah
# With plotting support
pip install "bencheetah[plot]"
Requires Python ≥ 3.10.
Quick Start
Benchmark a single function
from bencheetah import benchmark, format_results
result = benchmark(sum, range(1_000_000), repeats=10)
print(format_results(result))
┌──────────────────────────────────────────┐
│ bencheetah — sum │
├──────────────────────────────────────────┤
│ Runs 10 │
│ Mean 8.23 ms │
│ Min 7.91 ms │
│ Max 9.14 ms │
│ Total 82.32 ms │
└──────────────────────────────────────────┘
Compare multiple implementations
from bencheetah import compare, format_results
def loop_sum(n):
return sum(range(n))
def gauss_sum(n):
return n * (n - 1) // 2
out = compare(
{"loop": loop_sum, "gauss": gauss_sum},
args=(1_000_000,),
repeats=8,
)
print(format_results(out))
bencheetah — comparison (2 functions)
────────────────────────────────────────────────────────────
Function Mean Min Max Total
────────────────────────────────────────────────────────────
gauss W 142.00 ns 130.00 ns 180.00 ns 1.14 µs
loop 8.23 ms 7.91 ms 9.14 ms 65.84 ms (57930.8x slower)
────────────────────────────────────────────────────────────
Winner: gauss W
Scaling experiment (execution time vs input size)
from bencheetah import scale_benchmark, plot_scaling
def bubble_sort(lst):
lst = lst[:]
n = len(lst)
for i in range(n):
for j in range(n - i - 1):
if lst[j] > lst[j + 1]:
lst[j], lst[j + 1] = lst[j + 1], lst[j]
return lst
data = scale_benchmark(
funcs={
"sorted() built-in": sorted,
"bubble sort": bubble_sort,
},
input_gen=lambda n: list(range(n, 0, -1)), # worst-case: reversed list
sizes=[100, 500, 1_000, 2_000, 5_000],
repeats=5,
)
fig, ax = plot_scaling(data, title="Sort algorithm scaling")
The chart shows mean execution time (±1 stdev error bars) vs input size, one line per algorithm — perfect for comparing O(n log n) vs O(n²) empirically.
API Reference
benchmark(func, *args, repeats=5, warmup=1, **kwargs) → dict
Runs func(*args, **kwargs) multiple times and returns timing statistics.
| Key | Description |
|---|---|
name |
Function name |
runs |
Number of timed runs |
mean |
Average execution time (seconds) |
min |
Fastest run |
max |
Slowest run |
stdev |
Standard deviation |
total |
Sum of all runs |
Parameters:
func— Callable to benchmark.*args— Positional arguments forwarded tofunc.repeats(int) — Number of timed runs. Default:5.warmup(int) — Un-timed warm-up runs (avoids cold-start effects). Default:1.**kwargs— Keyword arguments forwarded tofunc.
compare(funcs, args=None, kwargs=None, repeats=5, warmup=1) → dict
Benchmarks multiple functions with the same inputs and ranks them by mean time.
| Key | Description |
|---|---|
results |
Dict of benchmark dicts keyed by label |
winner |
Label of the fastest function |
ranking |
List of {name, mean} sorted fastest → slowest |
Parameters:
funcs(dict) —{"label": callable, ...}.args(tuple) — Positional arguments shared by all functions.kwargs(dict) — Keyword arguments shared by all functions.repeats,warmup— Same asbenchmark.
scale_benchmark(funcs, input_gen, sizes, repeats=5, warmup=1) → dict
Runs a scaling experiment: benchmarks one or more functions across a range of input sizes.
Parameters:
funcs— A single callable or a{"label": callable}dict.input_gen(callable) — Receives an integernand returns the input for that size. Return atupleif the function needs multiple positional arguments.input_gen = lambda n: list(range(n)) # single arg input_gen = lambda n: (list(range(n)), True) # multiple args → unpacked
sizes(iterable[int]) — The input sizes to sweep, e.g.[100, 1000, 5000, 10_000].repeats,warmup— Same asbenchmark.
Returns a dict keyed by function label, each value containing:
{"sizes": [...], "means": [...], "stdevs": [...], "mins": [...], "maxs": [...]}.
plot_scaling(scale_data, *, ...) → (Figure, Axes)
Plots the output of scale_benchmark() as a line chart (mean time vs input size).
Requires matplotlib. Install with pip install "bencheetah[plot]".
| Parameter | Default | Description |
|---|---|---|
title |
"Execution time vs input size" |
Chart title |
xlabel |
"Input size (n)" |
X-axis label |
ylabel |
auto | Y-axis label (auto-generated from time unit) |
time_unit |
"auto" |
One of "auto", "s", "ms", "us", "ns" |
show_errorbars |
True |
Draw ±1 stdev error bars |
show_minmax_band |
False |
Shade the min–max range behind each line |
logscale |
False |
Logarithmic Y axis |
figsize |
(9, 5) |
Matplotlib figure size in inches |
save_path |
None |
Save to file (.png, .svg, .pdf, …) |
show |
True |
Call plt.show() |
format_results(data) → str
Formats the output of benchmark() or compare() into a printable terminal table.
Automatically selects the most readable time unit (ns, µs, ms, s).
Tutorial Notebook
A step-by-step tutorial with all four functions is available as a Jupyter notebook. Click below to open it directly in Google Colab — no local setup required:
Running with Docker
# Build the image
docker build -t bencheetah .
# Run the demo (prints tables + saves scaling_sort.png inside the container)
docker run --rm bencheetah
# Copy the chart out of the container
docker run --rm -v "$PWD":/out bencheetah \
sh -c "python examples/demo.py && cp scaling_sort.png /out/"
# Run the test suite
docker run --rm bencheetah pytest tests/ -v
Development
git clone https://github.com/JobAlcantara/bencheetah.git
cd bencheetah
pip install -e ".[dev]"
pytest tests/ -v
Project Structure
bencheetah/
├── src/
│ └── bencheetah/
│ ├── __init__.py
│ ├── core.py # benchmark() and compare()
│ ├── formatters.py # format_results()
│ └── plotter.py # scale_benchmark() and plot_scaling()
├── tests/
│ └── test_bencheetah.py
├── examples/
│ └── demo.py
├── notebooks/
│ └── tutorial.ipynb
├── .github/
│ └── workflows/
│ └── ci.yml
├── Dockerfile
└── pyproject.toml
License
MIT © JobAlcantara
Project details
Release history Release notifications | RSS feed
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 bencheetah-0.2.0.tar.gz.
File metadata
- Download URL: bencheetah-0.2.0.tar.gz
- Upload date:
- Size: 14.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd93938b1edba7c16f374db63f241cc8936214b7fa5aff2e4a4b8de758e18a38
|
|
| MD5 |
8e2fd3816753237a0df00c262e9bc14f
|
|
| BLAKE2b-256 |
8584c7e1af19606889e9aab0b8cfb933cc546db7d67feb76774c6f33390ac7ca
|
Provenance
The following attestation bundles were made for bencheetah-0.2.0.tar.gz:
Publisher:
ci.yml on JobAlcantara/bencheetah
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bencheetah-0.2.0.tar.gz -
Subject digest:
cd93938b1edba7c16f374db63f241cc8936214b7fa5aff2e4a4b8de758e18a38 - Sigstore transparency entry: 1296933852
- Sigstore integration time:
-
Permalink:
JobAlcantara/bencheetah@d7f917cab0fa402e8855df494bc45454d22169c9 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/JobAlcantara
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@d7f917cab0fa402e8855df494bc45454d22169c9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bencheetah-0.2.0-py3-none-any.whl.
File metadata
- Download URL: bencheetah-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f5bea0a06bfc6f83f09020ab6bc04164527a29fb9145ba3af7e3c719708da65
|
|
| MD5 |
5516352c800c75068ff36e7096e76ad4
|
|
| BLAKE2b-256 |
0c6fcb0cea3ba38664d30258f7f6ecfccdfaa4a05b10b1dfc5d7f025e1f622e1
|
Provenance
The following attestation bundles were made for bencheetah-0.2.0-py3-none-any.whl:
Publisher:
ci.yml on JobAlcantara/bencheetah
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bencheetah-0.2.0-py3-none-any.whl -
Subject digest:
0f5bea0a06bfc6f83f09020ab6bc04164527a29fb9145ba3af7e3c719708da65 - Sigstore transparency entry: 1296933945
- Sigstore integration time:
-
Permalink:
JobAlcantara/bencheetah@d7f917cab0fa402e8855df494bc45454d22169c9 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/JobAlcantara
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@d7f917cab0fa402e8855df494bc45454d22169c9 -
Trigger Event:
push
-
Statement type: