Microbench
Running the same script on a laptop, cloud VM, or cluster can produce different results. Maybe some nodes have different GPUs, or you're running a different git commit without realising it.
Microbench records the context alongside your timings: Python version, package versions, hostname, hardware, environment variables, git commit, and more. When performance varies across machines or runs, the metadata tells you why. When you need to reproduce a result, it shows exactly what was running.
Unlike other benchmarking tools, Microbench focuses on reproducibility metadata — capturing these details is cheap and routine, so you can do it for every run, not just when something goes wrong.
Two ways to use it
Microbench has two modes:
- CLI — wraps any command (Python or not) with a single line; no code changes required. Ideal for SLURM jobs and shell scripts.
- Python API — decorates functions or wraps code blocks for richer capture: sub-timings, return values, live package versions, async support.
Results are saved to a JSONL file, Redis, or an HTTP endpoint. File writes
use O_APPEND and are safe for concurrent writes from multiple processes.
See CLI vs Python API below to help decide which to use.
What metadata can be captured?
Metadata are captured through mixins — small, composable modules that can be enabled from the CLI or mixed into a Python class. A sensible default set is active out of the box.
| Metadata | CLI flag | Python mixin |
|---|---|---|
| Run ID, version, timezone, duration(s), start/finish times, invocation method | (default) | (default) |
| Python version, prefix, and executable | (default) | (default: included in MicroBench) |
| Hostname, OS; CPU core count and total RAM (requires psutil) | (default) | MBHostInfo |
All SLURM_* environment variables |
(default) | MBSlurmInfo |
| Loaded Environment Modules / Lmod stack | (default) | MBLoadedModules |
| Current working directory | (default) | MBWorkingDir |
| CPU time, peak RSS, page faults, block I/O ops, and context switches (POSIX) | (default) | MBResourceUsage |
| Git repo, commit hash, branch, dirty flag | --mixin git-info |
MBGitInfo |
| SHA-256 (or other) hash of specified files | --mixin file-hash |
MBFileHash |
| Installed Python packages and versions | --mixin installed-packages |
MBInstalledPackages |
| Installed Conda packages and versions | --mixin conda-packages |
MBCondaPackages |
| NVIDIA GPU names, memory, and attributes | --mixin nvidia-smi |
MBNvidiaSmi |
| Cgroup CPU/RAM limits (containers, Linux only) | --mixin cgroup-limits |
MBCgroupLimits |
| Function call arguments | — | MBFunctionCall |
| Function return value | — | MBReturnValue |
Peak memory over a function call via tracemalloc |
— | MBPeakMemory |
| Python packages loaded into the caller's globals | — | MBGlobalPackages |
| Line-by-line performance profile | — | MBLineProfiler |
Installation
Requires Python 3.10+. No mandatory dependencies outside the standard library.
pip install microbench
Quick start — CLI
Wrap any command and capture host metadata alongside timing, with no code changes required:
microbench --outfile results.jsonl -- ./run_simulation.sh --steps 1000
This records one JSONL record per invocation. By default it captures timing,
hostname, Python version, SLURM variables, loaded modules, and working
directory. Add --monitor-interval to sample CPU and RSS memory over time:
microbench --outfile results.jsonl --monitor-interval 30 -- python train_model.py
Tag runs with custom fields:
microbench --outfile results.jsonl --field experiment=run-42 -- ./run.sh
Run microbench --help or microbench --show-mixins to see all options.
Example output
microbench -- echo "hello"
Output (written to stdout when --outfile is omitted):
{
"mb": {
"run_id": "8a3d213a-d7c2-44cb-a42f-1b68e6e0180e",
"version": "2.0.0",
"timezone": "UTC",
"duration_counter": "perf_counter"
},
"call": {
"invocation": "CLI",
"name": "echo",
"working_dir": "/home/user",
"command": ["echo", "hello"],
"durations": [0.004],
"start_time": "2026-03-17T14:36:08.140607+00:00",
"finish_time": "2026-03-17T14:36:08.144707+00:00",
"returncode": [0]
},
"host": {
"hostname": "cluster-node-04",
"os": "linux",
"cpu_cores_logical": 32,
"cpu_cores_physical": 16,
"ram_total": 137438953472
},
"python": {
"version": "3.13.1",
"prefix": "/opt/conda/envs/myenv",
"executable": "/opt/conda/envs/myenv/bin/python3.13"
},
"slurm": {},
"loaded_modules": {}
}
The CLI supports additional options, including capturing stdout/stderr, setting timeouts, and repeat iterations for benchmarking. See the CLI documentation for the full option reference.
Quick start — Python API
For Python-specific use cases, decorate functions directly:
from microbench import MicroBench
bench = MicroBench(outfile='/home/user/results.jsonl', experiment='baseline')
@bench
def my_function(n):
return sum(range(n))
my_function(1_000_000)
results = bench.get_results() # list of dicts — no extra dependencies
results = bench.get_results(format='df') # pandas DataFrame
bench.summary() # quick stats printout
Each call produces one record. With get_results(flat=True) the record looks
like:
mb.run_id mb.version call.name call.durations experiment
0 3f2a1b4c-8d9e-4f2a-b1c3-d4e5f6a7b8c9 2.0.0 my_function [0.049823] baseline
CLI vs Python API
| Use case | Recommended |
|---|---|
| Shell scripts, compiled executables, or non-Python programs | CLI |
| SLURM jobs or batch scripts | CLI |
| One-off timing with host metadata, no code changes | CLI |
Python functions needing sub-timings (bench.time()), return-value capture, or line-by-line profiling |
Python API |
| Custom capture logic (subclassing mixins) | Python API |
| Capturing live Python module versions (not just what's installed) | Python API |
| Async Python functions | Python API |
Python API — extended example
from microbench import MicroBench, MBFunctionCall, MBHostInfo, MBSlurmInfo
import numpy, pandas, time
class MyBench(MicroBench, MBFunctionCall, MBHostInfo, MBSlurmInfo):
outfile = '/home/user/my-benchmarks.jsonl'
capture_versions = (numpy, pandas) # record live module versions
env_vars = ('CUDA_VISIBLE_DEVICES',) # capture env vars as env.<NAME>
benchmark = MyBench(experiment='run-1', iterations=3,
duration_counter=time.monotonic)
@benchmark
def myfunction(arg1, arg2):
...
myfunction(x, y)
Mixins added here:
MBFunctionCallrecords the argumentsarg1andarg2.MBHostInfocaptureshost.hostname,host.os, CPU cores, and RAM.MBSlurmInfocaptures allSLURM_*environment variables.
MBPythonInfo is included in MicroBench by default — no need to list it
explicitly.
See the full documentation for context managers, async support, sub-timings, output sinks, and more.
Documentation
Full documentation, including a getting-started guide, mixin reference, and API reference, is at https://alubbock.github.io/microbench/.
Citing microbench
If you use microbench in your research, please cite:
Lubbock, A.L.R. and Lopez, C.F. (2022). Microbench: automated metadata management for systems biology benchmarking and reproducibility in Python. Bioinformatics, 38(20), 4823–4825. https://doi.org/10.1093/bioinformatics/btac580
Although the paper was written in the context of systems biology, microbench is a general-purpose benchmarking tool applicable to any Python workload.
Feedback
Bug reports and feature requests are welcome in GitHub issues.
Metadata
Release files for microbench 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| microbench-2.1.0.tar.gz | 175.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| microbench-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 226.5 kB
Release files / microbench-2.1.0.tar.gz
| Download URL | microbench-2.1.0.tar.gz |
|---|---|
| Size | 175.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac9a096c2a59384d5514f3d0e5819dfdf070df2a32f0225373300a400e99b8a0
|
|
BLAKE2b-256 checksum How to use checksums |
305015a064c006e95866f383df9700904fb95fddb5a4c63e9b86117c0481df14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Apr 26, 2026.
Transparency logRelease files / microbench-2.1.0-py3-none-any.whl
| Download URL | microbench-2.1.0-py3-none-any.whl |
|---|---|
| Size | 50.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
93408d7a1f463a4e652f147d2b7ed364656ca73224ab3ba642b8321d88258850
|
|
BLAKE2b-256 checksum How to use checksums |
575e74797679cceca78168b05dcc9098ec14ec2fbe45513d9d9ff717e75a6a94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Apr 26, 2026.
Transparency log