# PyBench — fast, precise microbenchmarks for Python
Measure small, focused snippets with minimal boilerplate, auto-discovery, smart calibration, and a clean CLI (command: `pybench`).
Run benchmarks with one command:
```bash
pybench examples/ [-k keyword] [-P key=value ...]
```
## ✨ Highlights
- Simple API: `@bench(...)` or suites with `Bench` and `BenchContext.start()/end()` for critical sections.
- Auto-discovery: `pybench <dir>` expands `**/*bench.py`.
- Parameterization: generate cases via `params={...}` (cartesian product) or per-case `args/kwargs`.
- Runtime tweaks: `-P key=value` overrides `n`, `repeat`, `warmup`, `group`, and custom params.
- Sound timing: monotonic high-res clock, GC control, warmup, repeats, context fast-path.
- Smart calibration: per-variant auto-calibration to hit a time budget.
- Pretty table: aligned columns, percentiles, iter/s, min…max, group headers, baseline and speedup vs. base.
- TTY-aware colors: `--no-color` for plain environments.
## 📦 Install
- pip
```bash
pip install pybenchx
```
- uv
```bash
uv pip install pybenchx
```
## 🚀 Quickstart
- Run all examples
```bash
pybench examples/
```
- Filter by name
```bash
pybench examples/ -k join
```
- Override params at runtime
```bash
pybench examples/ -P repeat=5 -P n=10000
```
## 🎛️ CLI options that matter
- Disable color
```bash
pybench examples/ --no-color
```
- Sorting
```bash
pybench examples/ --sort time --desc
```
- Time budget per variant (calibration)
```bash
pybench examples/ --budget 300ms # total per variant; split across repeats
pybench examples/ --max-n 1000000 # cap calibrated n
```
- Profiles
```bash
pybench examples/ --profile fast # ~150ms budget, repeat=10
pybench examples/ --profile thorough # ~1s budget, repeat=30
pybench examples/ --profile smoke # no calibration, repeat=3
```
## 🧪 Example benchmark
See `examples/strings_bench.py` for both styles:
```python
from pybench import bench, Bench, BenchContext
@bench(name="join", n=1000, repeat=10)
def join(sep: str = ","):
sep.join(str(i) for i in range(100))
suite = Bench("strings")
@suite.bench(name="join-baseline", baseline=True)
def join_baseline(b: BenchContext):
s = ",".join(str(i) for i in range(50))
b.start(); _ = ",".join([s] * 5); b.end()
```
## 📊 Output
Header includes CPU, Python, perf_counter clock info, total time, and mode. Table shows speed vs baseline with percent:
```
(pybench) [fullzer4@archlinux pybenchx]$ pybench examples/
cpu: x86_64
runtime: python 3.12.5 (x86_64-linux) | perf_counter: res=1.0e-09s, mono=True
time: 21.722s | mode: default, budget=0.300s, max-n=1000000, smoke=False
benchmark time (avg) iter/s (min … max) p75 p99 p995 vs base
join 11.72 µs 85.3 K 10.61 µs … 13.64 µs 12.16 µs 13.52 µs 13.58 µs -
join_param[n=100,sep='-'] 11.94 µs 83.8 K 10.56 µs … 13.61 µs 12.43 µs 13.56 µs 13.59 µs -
join_param[n=100,sep=':'] 11.55 µs 86.6 K 10.58 µs … 12.33 µs 12.21 µs 12.33 µs 12.33 µs -
join_param[n=1000,sep='-'] 118.69 µs 8.4 K 108.67 µs … 134.28 µs 121.52 µs 133.57 µs 133.93 µs -
join_param[n=1000,sep=':'] 121.14 µs 8.3 K 108.99 µs … 157.25 µs 123.28 µs 154.39 µs 155.82 µs -
group: strings
join-baseline ★ 429.42 ns 2.3 M 380.26 ns … 484.32 ns 452.78 ns 482.04 ns 483.18 ns baseline
join-basic 417.29 ns 2.4 M 383.02 ns … 471.58 ns 428.28 ns 468.33 ns 469.95 ns 1.03× faster (2.9%)
concat 8.58 µs 116.6 K 7.88 µs … 9.84 µs 8.84 µs 9.80 µs 9.82 µs 19.97× slower (95.0%)
```
## 💡 Tips
- Use `BenchContext.start()/end()` to isolate the critical section and avoid setup noise.
- Prefer `--profile fast` during development; switch to `--profile thorough` before publishing numbers.
- For CI or logs, use `--no-color`.
Raw data
{
"_id": null,
"home_page": null,
"name": "pybenchx",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "benchmark, microbenchmark, performance, timeit, deno",
"author": "Seu Nome",
"author_email": "Seu Nome <vc@example.com>",
"download_url": "https://files.pythonhosted.org/packages/47/cb/f78af614bba6cc08b6638c275b993f80515f98b8e8f2cd2c998abe33c043/pybenchx-1.0.0.tar.gz",
"platform": null,
"description": "# PyBench \u2014 fast, precise microbenchmarks for Python\n\nMeasure small, focused snippets with minimal boilerplate, auto-discovery, smart calibration, and a clean CLI (command: `pybench`).\n\nRun benchmarks with one command:\n\n```bash\npybench examples/ [-k keyword] [-P key=value ...]\n```\n\n## \u2728 Highlights\n\n- Simple API: `@bench(...)` or suites with `Bench` and `BenchContext.start()/end()` for critical sections.\n- Auto-discovery: `pybench <dir>` expands `**/*bench.py`.\n- Parameterization: generate cases via `params={...}` (cartesian product) or per-case `args/kwargs`.\n- Runtime tweaks: `-P key=value` overrides `n`, `repeat`, `warmup`, `group`, and custom params.\n- Sound timing: monotonic high-res clock, GC control, warmup, repeats, context fast-path.\n- Smart calibration: per-variant auto-calibration to hit a time budget.\n- Pretty table: aligned columns, percentiles, iter/s, min\u2026max, group headers, baseline and speedup vs. base.\n- TTY-aware colors: `--no-color` for plain environments.\n\n## \ud83d\udce6 Install\n\n- pip\n ```bash\n pip install pybenchx\n ```\n- uv\n ```bash\n uv pip install pybenchx\n ```\n\n## \ud83d\ude80 Quickstart\n\n- Run all examples\n ```bash\n pybench examples/\n ```\n- Filter by name\n ```bash\n pybench examples/ -k join\n ```\n- Override params at runtime\n ```bash\n pybench examples/ -P repeat=5 -P n=10000\n ```\n\n## \ud83c\udf9b\ufe0f CLI options that matter\n\n- Disable color\n ```bash\n pybench examples/ --no-color\n ```\n- Sorting\n ```bash\n pybench examples/ --sort time --desc\n ```\n- Time budget per variant (calibration)\n ```bash\n pybench examples/ --budget 300ms # total per variant; split across repeats\n pybench examples/ --max-n 1000000 # cap calibrated n\n ```\n- Profiles\n ```bash\n pybench examples/ --profile fast # ~150ms budget, repeat=10\n pybench examples/ --profile thorough # ~1s budget, repeat=30\n pybench examples/ --profile smoke # no calibration, repeat=3\n ```\n\n## \ud83e\uddea Example benchmark\n\nSee `examples/strings_bench.py` for both styles:\n\n```python\nfrom pybench import bench, Bench, BenchContext\n\n@bench(name=\"join\", n=1000, repeat=10)\ndef join(sep: str = \",\"):\n sep.join(str(i) for i in range(100))\n\nsuite = Bench(\"strings\")\n\n@suite.bench(name=\"join-baseline\", baseline=True)\ndef join_baseline(b: BenchContext):\n s = \",\".join(str(i) for i in range(50))\n b.start(); _ = \",\".join([s] * 5); b.end()\n```\n\n## \ud83d\udcca Output\n\nHeader includes CPU, Python, perf_counter clock info, total time, and mode. Table shows speed vs baseline with percent:\n\n```\n(pybench) [fullzer4@archlinux pybenchx]$ pybench examples/\ncpu: x86_64\nruntime: python 3.12.5 (x86_64-linux) | perf_counter: res=1.0e-09s, mono=True\ntime: 21.722s | mode: default, budget=0.300s, max-n=1000000, smoke=False\nbenchmark time (avg) iter/s (min \u2026 max) p75 p99 p995 vs base\njoin 11.72 \u00b5s 85.3 K 10.61 \u00b5s \u2026 13.64 \u00b5s 12.16 \u00b5s 13.52 \u00b5s 13.58 \u00b5s -\njoin_param[n=100,sep='-'] 11.94 \u00b5s 83.8 K 10.56 \u00b5s \u2026 13.61 \u00b5s 12.43 \u00b5s 13.56 \u00b5s 13.59 \u00b5s -\njoin_param[n=100,sep=':'] 11.55 \u00b5s 86.6 K 10.58 \u00b5s \u2026 12.33 \u00b5s 12.21 \u00b5s 12.33 \u00b5s 12.33 \u00b5s -\njoin_param[n=1000,sep='-'] 118.69 \u00b5s 8.4 K 108.67 \u00b5s \u2026 134.28 \u00b5s 121.52 \u00b5s 133.57 \u00b5s 133.93 \u00b5s -\njoin_param[n=1000,sep=':'] 121.14 \u00b5s 8.3 K 108.99 \u00b5s \u2026 157.25 \u00b5s 123.28 \u00b5s 154.39 \u00b5s 155.82 \u00b5s -\ngroup: strings \njoin-baseline \u2605 429.42 ns 2.3 M 380.26 ns \u2026 484.32 ns 452.78 ns 482.04 ns 483.18 ns baseline\njoin-basic 417.29 ns 2.4 M 383.02 ns \u2026 471.58 ns 428.28 ns 468.33 ns 469.95 ns 1.03\u00d7 faster (2.9%)\nconcat 8.58 \u00b5s 116.6 K 7.88 \u00b5s \u2026 9.84 \u00b5s 8.84 \u00b5s 9.80 \u00b5s 9.82 \u00b5s 19.97\u00d7 slower (95.0%)\n```\n\n## \ud83d\udca1 Tips\n\n- Use `BenchContext.start()/end()` to isolate the critical section and avoid setup noise.\n- Prefer `--profile fast` during development; switch to `--profile thorough` before publishing numbers.\n- For CI or logs, use `--no-color`.",
"bugtrack_url": null,
"license": null,
"summary": "A tiny, precise microbenchmarking framework for Python",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/fullzer4/pybenchx",
"Issues": "https://github.com/fullzer4/pybenchx/issues",
"Repository": "https://github.com/fullzer4/pybenchx"
},
"split_keywords": [
"benchmark",
" microbenchmark",
" performance",
" timeit",
" deno"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "3ecaec20ebb1e93f448577650cc80fca97ab66e647d00046d78ff2c38d334e46",
"md5": "e143cc45ec03551bcaf56fbb032e2a5c",
"sha256": "49545ed40ecf844b440e26a9c6cfb7ef9662e0f63be26d87f0452a4dac22e346"
},
"downloads": -1,
"filename": "pybenchx-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e143cc45ec03551bcaf56fbb032e2a5c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 12563,
"upload_time": "2025-08-22T16:50:01",
"upload_time_iso_8601": "2025-08-22T16:50:01.262217Z",
"url": "https://files.pythonhosted.org/packages/3e/ca/ec20ebb1e93f448577650cc80fca97ab66e647d00046d78ff2c38d334e46/pybenchx-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "47cbf78af614bba6cc08b6638c275b993f80515f98b8e8f2cd2c998abe33c043",
"md5": "f663db46c5fc4c18b3b8342333423e1c",
"sha256": "7cdb96e5d687424a87c4aa1517505872de15b755c88514f6b82816ae1f7c150c"
},
"downloads": -1,
"filename": "pybenchx-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "f663db46c5fc4c18b3b8342333423e1c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 11033,
"upload_time": "2025-08-22T16:50:02",
"upload_time_iso_8601": "2025-08-22T16:50:02.561657Z",
"url": "https://files.pythonhosted.org/packages/47/cb/f78af614bba6cc08b6638c275b993f80515f98b8e8f2cd2c998abe33c043/pybenchx-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-22 16:50:02",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "fullzer4",
"github_project": "pybenchx",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "pybenchx"
}