Benchmarks
Generated by
scripts/generate_benchmarks_doc.py. Re-run to refresh after new benchmark runs.
This document compares Galley (the generated LL/LR parser in this repository) against widely-used third-party parsers and parser-generators on JSON inputs.
Unless noted otherwise, results were recorded on an Apple M1 Pro.
JSON Parsing — Throughput Comparison
What are we comparing?
The parsers below fall into two distinct categories:
General-purpose parser generators / tools — you describe a grammar and the tool produces a parser for any language matching that grammar. Bison, LALRPOP, Nom, and Tree-sitter all belong here. Galley is in this category.
Specialised JSON libraries — simdjson, yyjson, and RapidJSON are hand-written libraries optimised exclusively for JSON. They exploit structural properties unique to JSON with SIMD intrinsics and two-pass parsing that is not generalisable to arbitrary grammars. They are reference points showing what a single-purpose native implementation can achieve, not direct competitors to a parser generator.
On
twitter.json, within the parser-generator category, Galley LL is 2.5× faster than LALRPOP (Rust), 1.7× faster than Bison/Flex (C), and 6.7× faster than Nom (Rust) — with full AST construction (496 MB/s) still outpacing LALRPOP's non-AST mode (212 MB/s).
Notably, Galley's no-ast throughput of 536 MB/s is within ~3% of RapidJSON's SAX mode (519 MB/s) — a hand-tuned C++ library with SIMD acceleration — despite Galley being a general-purpose parser generated from a grammar specification with no JSON-specific optimisations.
Each table below runs every parser on one shared input in the same harness (2 warmup + best of 5 runs) — Galley included. Grammars and tree shapes still differ per parser (see Methodology), so small gaps should not be over-read.
canada.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 3,316 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 1,426 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 1,008 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 850.7 MB/s |
| Galley LL | Zig | General | No AST | 816.8 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 734.4 MB/s |
| Galley LL | Zig | General | AST | 409.9 MB/s | |
| Galley LR | Zig | General | No AST | 357.8 MB/s | |
| Bison / Flex | C | General | No AST | 297.8 MB/s | |
| Bison / Flex | C | General | AST (simple) | 284.5 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 281.0 MB/s | |
| Bison / Flex | C | General | AST (payload) | 278.8 MB/s | |
| LALRPOP | Rust | General | No AST | 213.2 MB/s | |
| Nom | Rust | General | AST | 196.1 MB/s | |
| LALRPOP | Rust | General | AST | 180.7 MB/s | |
| Galley LR | Zig | General | AST | 159.8 MB/s | |
| Tree-sitter | C | General | CST | 25.0 MB/s |
citm_catalog.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 4,436 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 3,413 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 2,996 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 1,141 MB/s |
| Galley LL | Zig | General | No AST | 1,018 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 1,001 MB/s |
| Galley LL | Zig | General | AST | 813.9 MB/s | |
| Bison / Flex | C | General | No AST | 385.1 MB/s | |
| Bison / Flex | C | General | AST (simple) | 373.9 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 372.4 MB/s | |
| Bison / Flex | C | General | AST (payload) | 365.4 MB/s | |
| LALRPOP | Rust | General | No AST | 301.1 MB/s | |
| Galley LR | Zig | General | No AST | 294.2 MB/s | |
| LALRPOP | Rust | General | AST | 275.9 MB/s | |
| Galley LR | Zig | General | AST | 175.4 MB/s | |
| Nom | Rust | General | AST | 164.5 MB/s | |
| Tree-sitter | C | General | CST | 43.2 MB/s |
fgo.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 2,133 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 1,631 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 1,175 MB/s |
| Galley LL | Zig | General | No AST | 475.0 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 469.7 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 373.1 MB/s |
| Galley LL | Zig | General | AST | 322.9 MB/s | |
| Bison / Flex | C | General | No AST | 252.5 MB/s | |
| Galley LR | Zig | General | No AST | 237.8 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 237.0 MB/s | |
| Bison / Flex | C | General | AST (simple) | 231.8 MB/s | |
| Bison / Flex | C | General | AST (payload) | 226.4 MB/s | |
| LALRPOP | Rust | General | No AST | 144.6 MB/s | |
| Galley LR | Zig | General | AST | 131.8 MB/s | |
| LALRPOP | Rust | General | AST | 125.2 MB/s | |
| Nom | Rust | General | AST | 55.2 MB/s | |
| Tree-sitter | C | General | CST | 13.7 MB/s |
github_events.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 4,969 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 3,241 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 3,036 MB/s |
| Galley LL | Zig | General | No AST | 478.3 MB/s | |
| Galley LL | Zig | General | AST | 472.6 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 454.6 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 396.7 MB/s |
| Bison / Flex | C | General | No AST | 314.5 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 303.4 MB/s | |
| Bison / Flex | C | General | AST (simple) | 300.6 MB/s | |
| Bison / Flex | C | General | AST (payload) | 297.9 MB/s | |
| Galley LR | Zig | General | No AST | 288.4 MB/s | |
| LALRPOP | Rust | General | No AST | 185.3 MB/s | |
| LALRPOP | Rust | General | AST | 184.4 MB/s | |
| Galley LR | Zig | General | AST | 177.3 MB/s | |
| Nom | Rust | General | AST | 66.0 MB/s | |
| Tree-sitter | C | General | CST | 36.9 MB/s |
gsoc-2018.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 5,654 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 3,403 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 3,260 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 457.7 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 435.5 MB/s |
| Galley LL | Zig | General | AST | 354.6 MB/s | |
| Bison / Flex | C | General | No AST | 353.1 MB/s | |
| Galley LL | Zig | General | No AST | 352.5 MB/s | |
| Bison / Flex | C | General | AST (simple) | 350.0 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 348.2 MB/s | |
| Bison / Flex | C | General | AST (payload) | 343.1 MB/s | |
| Galley LR | Zig | General | No AST | 316.7 MB/s | |
| LALRPOP | Rust | General | No AST | 232.5 MB/s | |
| LALRPOP | Rust | General | AST | 224.9 MB/s | |
| Galley LR | Zig | General | AST | 189.6 MB/s | |
| Nom | Rust | General | AST | 64.3 MB/s | |
| Tree-sitter | C | General | CST | 62.6 MB/s |
lottie.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 1,325 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 1,037 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 673.2 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 440.4 MB/s |
| Galley LL | Zig | General | No AST | 361.8 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 311.9 MB/s |
| Galley LL | Zig | General | AST | 221.4 MB/s | |
| Galley LR | Zig | General | No AST | 209.6 MB/s | |
| Bison / Flex | C | General | No AST | 156.8 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 144.3 MB/s | |
| Bison / Flex | C | General | AST (simple) | 141.5 MB/s | |
| Bison / Flex | C | General | AST (payload) | 139.8 MB/s | |
| Galley LR | Zig | General | AST | 99.9 MB/s | |
| LALRPOP | Rust | General | No AST | 87.6 MB/s | |
| LALRPOP | Rust | General | AST | 74.7 MB/s | |
| Nom | Rust | General | AST | 46.5 MB/s | |
| Tree-sitter | C | General | CST | 8.8 MB/s |
otfcc.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 1,361 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 1,130 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 737.0 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 532.5 MB/s |
| Galley LL | Zig | General | No AST | 414.0 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 354.3 MB/s |
| Galley LR | Zig | General | No AST | 255.1 MB/s | |
| Galley LL | Zig | General | AST | 251.9 MB/s | |
| Bison / Flex | C | General | No AST | 181.9 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 167.7 MB/s | |
| Bison / Flex | C | General | AST (simple) | 165.7 MB/s | |
| Bison / Flex | C | General | AST (payload) | 163.9 MB/s | |
| Galley LR | Zig | General | AST | 116.7 MB/s | |
| LALRPOP | Rust | General | No AST | 102.9 MB/s | |
| LALRPOP | Rust | General | AST | 85.4 MB/s | |
| Nom | Rust | General | AST | 46.1 MB/s | |
| Tree-sitter | C | General | CST | 8.8 MB/s |
poet.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| yyjson | C | ✓ | JSON-specific | AST | 3,989 MB/s |
| simdjson | C++ | ✓ | JSON-specific | Validate | 3,614 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 2,699 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 446.2 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 422.0 MB/s |
| Galley LL | Zig | General | No AST | 376.1 MB/s | |
| Galley LL | Zig | General | AST | 357.0 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 343.9 MB/s | |
| Bison / Flex | C | General | No AST | 341.0 MB/s | |
| Bison / Flex | C | General | AST (payload) | 338.0 MB/s | |
| Bison / Flex | C | General | AST (simple) | 335.9 MB/s | |
| Galley LR | Zig | General | No AST | 329.6 MB/s | |
| LALRPOP | Rust | General | No AST | 216.6 MB/s | |
| LALRPOP | Rust | General | AST | 209.6 MB/s | |
| Galley LR | Zig | General | AST | 201.0 MB/s | |
| Nom | Rust | General | AST | 116.9 MB/s | |
| Tree-sitter | C | General | CST | 68.0 MB/s |
twitter.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 3,883 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 3,256 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 2,787 MB/s |
| Galley LL | Zig | General | No AST | 535.9 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 518.6 MB/s |
| Galley LL | Zig | General | AST | 496.1 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 469.0 MB/s |
| Bison / Flex | C | General | No AST | 315.7 MB/s | |
| Bison / Flex | C | General | AST (payload) | 300.8 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 299.6 MB/s | |
| Bison / Flex | C | General | AST (simple) | 297.5 MB/s | |
| Galley LR | Zig | General | No AST | 288.4 MB/s | |
| LALRPOP | Rust | General | No AST | 212.2 MB/s | |
| LALRPOP | Rust | General | AST | 197.4 MB/s | |
| Galley LR | Zig | General | AST | 173.1 MB/s | |
| Nom | Rust | General | AST | 79.7 MB/s | |
| Tree-sitter | C | General | CST | 33.6 MB/s |
twitterescaped.json
| Parser | Lang | SIMD | Category | Mode | Throughput |
|---|---|---|---|---|---|
| simdjson | C++ | ✓ | JSON-specific | Validate | 4,251 MB/s |
| yyjson | C | ✓ | JSON-specific | AST | 2,433 MB/s |
| simdjson | C++ | ✓ | JSON-specific | AST | 1,182 MB/s |
| Galley LL | Zig | General | No AST | 560.2 MB/s | |
| Galley LL | Zig | General | AST | 491.2 MB/s | |
| RapidJSON | C++ | ✓ | JSON-specific | SAX | 468.2 MB/s |
| RapidJSON | C++ | ✓ | JSON-specific | AST | 407.6 MB/s |
| Galley LR | Zig | General | No AST | 312.1 MB/s | |
| Bison / Flex | C | General | No AST | 297.4 MB/s | |
| Bison / Flex | C | General | AST (simple) | 289.4 MB/s | |
| Bison / Flex | C | General | AST (advanced) | 288.1 MB/s | |
| Bison / Flex | C | General | AST (payload) | 284.2 MB/s | |
| LALRPOP | Rust | General | No AST | 217.0 MB/s | |
| LALRPOP | Rust | General | AST | 197.9 MB/s | |
| Galley LR | Zig | General | AST | 191.9 MB/s | |
| Nom | Rust | General | AST | 69.6 MB/s | |
| Tree-sitter | C | General | CST | 21.2 MB/s |
Methodology
- Benchmarks are run by the
third_party/parser-benchmark/submodule. - Each parser runs 2 untimed warmup iterations plus 5 timed iterations per dataset; the best run is reported.
- Results are written below
third_party/parser-benchmark/benchmark_results/json/. - The standard
twitter,canada, andcitm_cataloginputs are downloaded on demand, checksum-verified, ignored external assets. - No benchmark input is stored in either repository.
- Every parser except Tree-sitter validates string escapes and UTF-8 with the same strictness as Galley's unicode grammar: the Flex lexer, both LALRPOP grammars, and Nom were tightened to match, and RapidJSON runs with encoding validation enabled. Tree-sitter runs upstream as-is, with laxer string rules.
- Parsers included: Tree-sitter (C, CST), Bison/Flex (C, multiple AST modes), LALRPOP (Rust, Non-AST & AST), simdjson (C++, Validate & DOM), Nom (Rust, AST), RapidJSON (C++, DOM & SAX), yyjson (C, DOM AST).
- Galley rows are timed in this same harness from its unicode JSON grammar. Galley's long-term tracking numbers across all grammars live in
BENCHMARKS_INTERNAL.mdand come fromscripts/benchmark.py, a different harness — expect them to differ.
Environment
Results will vary by machine. All numbers were recorded on an Apple M1 Pro.