Skip to content

Commit 46d2228

Browse files
committed
docs: add benchmarking readme
1 parent 3453e5d commit 46d2228

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

tests/benchmarks/README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Benchmarks
2+
3+
This directory contains performance and memory benchmarks for JSONLT `Table` operations. The benchmarks measure CPU time and memory usage across different table sizes, record complexities, and key types.
4+
5+
## Overview
6+
7+
This directory organizes benchmarks into three categories:
8+
9+
- **Performance benchmarks** (`test_bench_table.py`) - Measure CPU time for all core Table operations
10+
- **Memory benchmarks** (`test_bench_memory.py`) - Enforce memory limits using pytest-memray
11+
- **Import time benchmark** (`test_bench_imports.py`) - Measures module import time
12+
13+
## Benchmark categories
14+
15+
### Performance benchmarks (`test_bench_table.py`)
16+
17+
Tests all core Table operations across different dimensions:
18+
19+
**Operations tested:**
20+
21+
- `load` - Initial table loading from file
22+
- `reload` - Reloading table data from disk
23+
- `get` - Single record retrieval (existing and nonexistent keys)
24+
- `all` - Retrieving all records
25+
- `find` - Predicate-based filtering with different selectivities
26+
- `find_one` - Single record matching (early, late, and no match cases)
27+
- `put` - Writing new and updating existing records
28+
- `batch write` - Writing records in batches (10 and 100 record batches)
29+
- `compact` - Compacting tables with history or tombstones
30+
- `keys` - Retrieving all keys
31+
- `items` - Retrieving all key-value pairs
32+
- `count` - Counting records
33+
- `has` - Checking key existence
34+
- `delete` - Removing records
35+
36+
**Parameters:**
37+
38+
| Dimension | Values |
39+
| ------------ | --------------------------------------------------------------------------- |
40+
| Record sizes | small (~5 fields), medium (~20 fields), large (~100 fields with 1KB+ text) |
41+
| Key types | string, integer, tuple (composite) |
42+
| Scales | 100, 1000, 10000, 100000 records |
43+
44+
### Memory benchmarks (`test_bench_memory.py`)
45+
46+
Uses pytest-memray with `@pytest.mark.limit_memory()` to enforce memory limits.
47+
48+
**Tests include:**
49+
50+
- Loading tables of different sizes (1k, 10k, 100k records)
51+
- Read operations (`all`, `find`, `keys`)
52+
- Write operations (`put`, `delete`, `compact`)
53+
54+
**Note:** memory benchmarks run only on Linux and macOS. They skip automatically on Windows where pytest-memray is not available.
55+
56+
### Import time benchmark (`test_bench_imports.py`)
57+
58+
Measures the time to import the `jsonlt` module, useful for detecting import-time regressions.
59+
60+
## Data generation
61+
62+
The `_generators.py` module provides deterministic test data generation:
63+
64+
- Uses seeded random instances for reproducibility across runs
65+
- Generates records of varying sizes (small, medium, large)
66+
- Supports all key types (string, integer, tuple)
67+
- Provides helper functions for creating tables with history and tombstones
68+
69+
## Running benchmarks
70+
71+
### Running locally
72+
73+
```bash
74+
# Run all benchmarks (excluding slow tests)
75+
just benchmark
76+
77+
# Run specific test classes
78+
just benchmark -k "TestBenchLoad"
79+
80+
# Include slow benchmarks (10k+ records)
81+
just benchmark -m "benchmark and slow"
82+
```
83+
84+
### Markers
85+
86+
| Marker | Description |
87+
| -------------- | ----------------------------------------------------------------- |
88+
| `benchmark` | Auto-applied to all tests in this directory |
89+
| `slow` | Applied to larger scale tests (10k+ records), excluded by default |
90+
| `limit_memory` | Applied to memory tests (pytest-memray marker) |
91+
92+
Default test runs exclude benchmarks. The default marker expression in `pyproject.toml` is:
93+
94+
```text
95+
-m "not benchmark and not slow"
96+
```
97+
98+
This means running `pytest` alone only executes unit tests.
99+
100+
## CI integration
101+
102+
Benchmarks run on GitHub Actions via Codspeed:
103+
104+
- **Mode:** simulation (CPU instruction counting, not wall-clock time)
105+
- **Sharding:** the workflow distributes tests across 7 parallel jobs for faster feedback
106+
- **Slow tests:** excluded in CI to keep benchmark runs under 5 minutes
107+
- **Triggers:** runs on pushes and pull requests to `main` when relevant files change
108+
109+
### CI shards
110+
111+
| Shard | Test Classes |
112+
| --------------- | --------------------------------------------------------- |
113+
| load-reload | `TestBenchLoad`, `TestBenchReload` |
114+
| get | `TestBenchGet` |
115+
| find | `TestBenchFind` |
116+
| find-one-delete | `TestBenchFindOne`, `TestBenchDelete` |
117+
| write-compact | `TestBenchPut`, `TestBenchBatchWrite`, `TestBenchCompact` |
118+
| all-keys-items | `TestBenchAll`, `TestBenchKeys`, `TestBenchItems` |
119+
| count-has | `TestBenchCount`, `TestBenchHas` |
120+
121+
## Benchmark results
122+
123+
Codspeed tracks the results:
124+
125+
<https://codspeed.io/jsonlt/jsonlt-python/benchmarks>

0 commit comments

Comments
 (0)