Skip to content

Commit 08d1e2e

Browse files
authored
Merge pull request #78 from alvinreal/perf/blazing-fast-readme
docs: performance section with measured benchmarks and jq comparison
2 parents 6ef94de + ca1f5dd commit 08d1e2e

File tree

1 file changed

+70
-20
lines changed

1 file changed

+70
-20
lines changed

README.md

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -166,54 +166,104 @@ cargo build --release
166166

167167
📖 **[Full installation guide](docs/INSTALLATION.md)** — includes shell completions, manual downloads, updating, and troubleshooting.
168168

169-
## Performance
169+
## ⚡ Blazingly Fast
170170

171-
morph is built in Rust and designed for speed. Benchmarks are run using [Criterion](https://github.com/bheisler/criterion.rs) at 100, 1,000, and 10,000 record scales.
171+
morph is built in Rust and optimized for high-throughput data pipelines.
172172

173-
### Throughput — Parsing
173+
### Current Throughput (Criterion)
174+
175+
Measured from `cargo bench --bench benchmarks` on macOS arm64 (Feb 2026).
176+
177+
#### Parsing
174178

175179
| Format | 100 records | 1,000 records | 10,000 records |
176180
|--------|------------|---------------|----------------|
177-
| JSON | ~118 MiB/s | ~121 MiB/s | ~121 MiB/s |
178-
| CSV | ~72 MiB/s | ~92 MiB/s | ~99 MiB/s |
179-
| YAML | ~27 MiB/s | ~26 MiB/s | ~24 MiB/s |
181+
| JSON | ~127 MiB/s | ~129 MiB/s | ~129 MiB/s |
182+
| CSV | ~79 MiB/s | ~97 MiB/s | ~103 MiB/s |
183+
| YAML | ~28 MiB/s | ~29 MiB/s | ~29 MiB/s |
180184

181-
### Throughput — Format Conversion
185+
#### Format Conversion
182186

183187
| Conversion | 100 records | 1,000 records | 10,000 records |
184188
|----------------|------------|---------------|----------------|
185-
| JSON → YAML | ~65 MiB/s | ~60 MiB/s | ~55 MiB/s |
186-
| CSV → JSON | ~55 MiB/s | ~70 MiB/s | ~75 MiB/s |
189+
| JSON → YAML | ~41 MiB/s | ~41 MiB/s | ~42 MiB/s |
190+
| CSV → JSON | ~43 MiB/s | ~50 MiB/s | ~54 MiB/s |
187191

188-
### Mapping Overhead
189-
190-
Mapping operations add minimal overhead on top of format conversion:
192+
#### Mapping Overhead
191193

192194
| Operation | 10,000 records |
193195
|---------------------|----------------|
194-
| `rename` (1 field) | ~2 ms |
195-
| `where` (filter) | ~3 ms |
196-
| Complex pipeline* | ~5 ms |
196+
| `rename` (1 field) | ~3.8 ms |
197+
| `where` (filter) | ~3.0 ms |
198+
| Complex pipeline* | ~3.8 ms |
197199

198200
\* *rename + set + drop + cast combined*
199201

200-
### Running Benchmarks Locally
202+
### Head-to-Head (actual)
203+
204+
All comparisons below were run on the same machine (macOS arm64), same 10,000-record dataset, with warmup and repeated timed runs via `hyperfine`.
205+
206+
#### 1) JSON → YAML conversion
207+
208+
| Tool | Mean runtime | Relative |
209+
|------|--------------|----------|
210+
| **morph** (`morph -f json -t yaml`) | **23.7 ms** | **1.00x** |
211+
| yq (`yq -P '.'`) | 713.2 ms | 30.03x slower |
212+
213+
#### 2) JSON transform (rename + filter)
214+
215+
Task: `rename .name -> .username` + `where .age > 30`
216+
217+
| Tool | Mean runtime | Relative |
218+
|------|--------------|----------|
219+
| **morph** | **18.3 ms** | **1.00x** |
220+
| jq | 40.0 ms | 2.19x slower |
221+
| yq | 101.5 ms | 5.55x slower |
222+
223+
#### 3) CSV → JSON conversion
224+
225+
| Tool | Mean runtime | Relative |
226+
|------|--------------|----------|
227+
| **morph** (`morph -f csv -t json`) | **11.7 ms** | **1.00x** |
228+
| miller (`mlr --icsv --ojson`) | 17.2 ms | 1.47x slower |
229+
230+
### Comparison commands
231+
232+
```bash
233+
# JSON -> YAML
234+
hyperfine --warmup 3 --runs 15 \
235+
"./target/release/morph -i bench.json -o /tmp/morph_out.yaml -f json -t yaml" \
236+
"yq -P '.' bench.json > /tmp/yq_out.yaml"
237+
238+
# JSON transform (rename + filter)
239+
hyperfine --warmup 3 --runs 20 \
240+
"./target/release/morph -i bench.json -o /tmp/morph_map.json -m mapping.morph -f json -t json" \
241+
"jq 'map(select(.age > 30) | .username=.name | del(.name))' bench.json > /tmp/jq_map.json" \
242+
"yq -o=json 'map(select(.age > 30) | .username = .name | del(.name))' bench.json > /tmp/yq_map.json"
243+
244+
# CSV -> JSON
245+
hyperfine --warmup 3 --runs 20 \
246+
"./target/release/morph -i bench.csv -o /tmp/morph_csv.json -f csv -t json" \
247+
"mlr --icsv --ojson cat bench.csv > /tmp/mlr_csv.json"
248+
```
249+
250+
### Run Benchmarks Locally
201251

202252
```bash
203-
# Run the full benchmark suite
253+
# Full suite
204254
cargo bench
205255

206-
# Run a specific benchmark group
256+
# Specific groups
207257
cargo bench -- parse_json
208258
cargo bench -- mapping_rename
209259

210260
# List available benchmarks
211261
cargo bench -- --list
212262
```
213263

214-
Results are saved to `target/criterion/` with HTML reports for detailed analysis. CI runs benchmarks on every PR and uploads results as artifacts.
264+
Results are saved to `target/criterion/` with HTML reports for detailed analysis.
215265

216-
> **Note:** Numbers above are representative and will vary by machine. Run `cargo bench` on your hardware for accurate results.
266+
> **Note:** Performance varies by CPU, disk, and dataset shape. For apples-to-apples comparisons, run all tools on the same machine and same dataset.
217267
218268
## Design Principles
219269

0 commit comments

Comments
 (0)