Skip to content

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

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate3,316 MB/s
yyjsonCJSON-specificAST1,426 MB/s
simdjsonC++JSON-specificAST1,008 MB/s
RapidJSONC++JSON-specificSAX850.7 MB/s
Galley LLZigGeneralNo AST816.8 MB/s
RapidJSONC++JSON-specificAST734.4 MB/s
Galley LLZigGeneralAST409.9 MB/s
Galley LRZigGeneralNo AST357.8 MB/s
Bison / FlexCGeneralNo AST297.8 MB/s
Bison / FlexCGeneralAST (simple)284.5 MB/s
Bison / FlexCGeneralAST (advanced)281.0 MB/s
Bison / FlexCGeneralAST (payload)278.8 MB/s
LALRPOPRustGeneralNo AST213.2 MB/s
NomRustGeneralAST196.1 MB/s
LALRPOPRustGeneralAST180.7 MB/s
Galley LRZigGeneralAST159.8 MB/s
Tree-sitterCGeneralCST25.0 MB/s

citm_catalog.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate4,436 MB/s
yyjsonCJSON-specificAST3,413 MB/s
simdjsonC++JSON-specificAST2,996 MB/s
RapidJSONC++JSON-specificSAX1,141 MB/s
Galley LLZigGeneralNo AST1,018 MB/s
RapidJSONC++JSON-specificAST1,001 MB/s
Galley LLZigGeneralAST813.9 MB/s
Bison / FlexCGeneralNo AST385.1 MB/s
Bison / FlexCGeneralAST (simple)373.9 MB/s
Bison / FlexCGeneralAST (advanced)372.4 MB/s
Bison / FlexCGeneralAST (payload)365.4 MB/s
LALRPOPRustGeneralNo AST301.1 MB/s
Galley LRZigGeneralNo AST294.2 MB/s
LALRPOPRustGeneralAST275.9 MB/s
Galley LRZigGeneralAST175.4 MB/s
NomRustGeneralAST164.5 MB/s
Tree-sitterCGeneralCST43.2 MB/s

fgo.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate2,133 MB/s
yyjsonCJSON-specificAST1,631 MB/s
simdjsonC++JSON-specificAST1,175 MB/s
Galley LLZigGeneralNo AST475.0 MB/s
RapidJSONC++JSON-specificSAX469.7 MB/s
RapidJSONC++JSON-specificAST373.1 MB/s
Galley LLZigGeneralAST322.9 MB/s
Bison / FlexCGeneralNo AST252.5 MB/s
Galley LRZigGeneralNo AST237.8 MB/s
Bison / FlexCGeneralAST (advanced)237.0 MB/s
Bison / FlexCGeneralAST (simple)231.8 MB/s
Bison / FlexCGeneralAST (payload)226.4 MB/s
LALRPOPRustGeneralNo AST144.6 MB/s
Galley LRZigGeneralAST131.8 MB/s
LALRPOPRustGeneralAST125.2 MB/s
NomRustGeneralAST55.2 MB/s
Tree-sitterCGeneralCST13.7 MB/s

github_events.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate4,969 MB/s
yyjsonCJSON-specificAST3,241 MB/s
simdjsonC++JSON-specificAST3,036 MB/s
Galley LLZigGeneralNo AST478.3 MB/s
Galley LLZigGeneralAST472.6 MB/s
RapidJSONC++JSON-specificSAX454.6 MB/s
RapidJSONC++JSON-specificAST396.7 MB/s
Bison / FlexCGeneralNo AST314.5 MB/s
Bison / FlexCGeneralAST (advanced)303.4 MB/s
Bison / FlexCGeneralAST (simple)300.6 MB/s
Bison / FlexCGeneralAST (payload)297.9 MB/s
Galley LRZigGeneralNo AST288.4 MB/s
LALRPOPRustGeneralNo AST185.3 MB/s
LALRPOPRustGeneralAST184.4 MB/s
Galley LRZigGeneralAST177.3 MB/s
NomRustGeneralAST66.0 MB/s
Tree-sitterCGeneralCST36.9 MB/s

gsoc-2018.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate5,654 MB/s
simdjsonC++JSON-specificAST3,403 MB/s
yyjsonCJSON-specificAST3,260 MB/s
RapidJSONC++JSON-specificSAX457.7 MB/s
RapidJSONC++JSON-specificAST435.5 MB/s
Galley LLZigGeneralAST354.6 MB/s
Bison / FlexCGeneralNo AST353.1 MB/s
Galley LLZigGeneralNo AST352.5 MB/s
Bison / FlexCGeneralAST (simple)350.0 MB/s
Bison / FlexCGeneralAST (advanced)348.2 MB/s
Bison / FlexCGeneralAST (payload)343.1 MB/s
Galley LRZigGeneralNo AST316.7 MB/s
LALRPOPRustGeneralNo AST232.5 MB/s
LALRPOPRustGeneralAST224.9 MB/s
Galley LRZigGeneralAST189.6 MB/s
NomRustGeneralAST64.3 MB/s
Tree-sitterCGeneralCST62.6 MB/s

lottie.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate1,325 MB/s
yyjsonCJSON-specificAST1,037 MB/s
simdjsonC++JSON-specificAST673.2 MB/s
RapidJSONC++JSON-specificSAX440.4 MB/s
Galley LLZigGeneralNo AST361.8 MB/s
RapidJSONC++JSON-specificAST311.9 MB/s
Galley LLZigGeneralAST221.4 MB/s
Galley LRZigGeneralNo AST209.6 MB/s
Bison / FlexCGeneralNo AST156.8 MB/s
Bison / FlexCGeneralAST (advanced)144.3 MB/s
Bison / FlexCGeneralAST (simple)141.5 MB/s
Bison / FlexCGeneralAST (payload)139.8 MB/s
Galley LRZigGeneralAST99.9 MB/s
LALRPOPRustGeneralNo AST87.6 MB/s
LALRPOPRustGeneralAST74.7 MB/s
NomRustGeneralAST46.5 MB/s
Tree-sitterCGeneralCST8.8 MB/s

otfcc.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate1,361 MB/s
yyjsonCJSON-specificAST1,130 MB/s
simdjsonC++JSON-specificAST737.0 MB/s
RapidJSONC++JSON-specificSAX532.5 MB/s
Galley LLZigGeneralNo AST414.0 MB/s
RapidJSONC++JSON-specificAST354.3 MB/s
Galley LRZigGeneralNo AST255.1 MB/s
Galley LLZigGeneralAST251.9 MB/s
Bison / FlexCGeneralNo AST181.9 MB/s
Bison / FlexCGeneralAST (advanced)167.7 MB/s
Bison / FlexCGeneralAST (simple)165.7 MB/s
Bison / FlexCGeneralAST (payload)163.9 MB/s
Galley LRZigGeneralAST116.7 MB/s
LALRPOPRustGeneralNo AST102.9 MB/s
LALRPOPRustGeneralAST85.4 MB/s
NomRustGeneralAST46.1 MB/s
Tree-sitterCGeneralCST8.8 MB/s

poet.json

ParserLangSIMDCategoryModeThroughput
yyjsonCJSON-specificAST3,989 MB/s
simdjsonC++JSON-specificValidate3,614 MB/s
simdjsonC++JSON-specificAST2,699 MB/s
RapidJSONC++JSON-specificSAX446.2 MB/s
RapidJSONC++JSON-specificAST422.0 MB/s
Galley LLZigGeneralNo AST376.1 MB/s
Galley LLZigGeneralAST357.0 MB/s
Bison / FlexCGeneralAST (advanced)343.9 MB/s
Bison / FlexCGeneralNo AST341.0 MB/s
Bison / FlexCGeneralAST (payload)338.0 MB/s
Bison / FlexCGeneralAST (simple)335.9 MB/s
Galley LRZigGeneralNo AST329.6 MB/s
LALRPOPRustGeneralNo AST216.6 MB/s
LALRPOPRustGeneralAST209.6 MB/s
Galley LRZigGeneralAST201.0 MB/s
NomRustGeneralAST116.9 MB/s
Tree-sitterCGeneralCST68.0 MB/s

twitter.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate3,883 MB/s
yyjsonCJSON-specificAST3,256 MB/s
simdjsonC++JSON-specificAST2,787 MB/s
Galley LLZigGeneralNo AST535.9 MB/s
RapidJSONC++JSON-specificSAX518.6 MB/s
Galley LLZigGeneralAST496.1 MB/s
RapidJSONC++JSON-specificAST469.0 MB/s
Bison / FlexCGeneralNo AST315.7 MB/s
Bison / FlexCGeneralAST (payload)300.8 MB/s
Bison / FlexCGeneralAST (advanced)299.6 MB/s
Bison / FlexCGeneralAST (simple)297.5 MB/s
Galley LRZigGeneralNo AST288.4 MB/s
LALRPOPRustGeneralNo AST212.2 MB/s
LALRPOPRustGeneralAST197.4 MB/s
Galley LRZigGeneralAST173.1 MB/s
NomRustGeneralAST79.7 MB/s
Tree-sitterCGeneralCST33.6 MB/s

twitterescaped.json

ParserLangSIMDCategoryModeThroughput
simdjsonC++JSON-specificValidate4,251 MB/s
yyjsonCJSON-specificAST2,433 MB/s
simdjsonC++JSON-specificAST1,182 MB/s
Galley LLZigGeneralNo AST560.2 MB/s
Galley LLZigGeneralAST491.2 MB/s
RapidJSONC++JSON-specificSAX468.2 MB/s
RapidJSONC++JSON-specificAST407.6 MB/s
Galley LRZigGeneralNo AST312.1 MB/s
Bison / FlexCGeneralNo AST297.4 MB/s
Bison / FlexCGeneralAST (simple)289.4 MB/s
Bison / FlexCGeneralAST (advanced)288.1 MB/s
Bison / FlexCGeneralAST (payload)284.2 MB/s
LALRPOPRustGeneralNo AST217.0 MB/s
LALRPOPRustGeneralAST197.9 MB/s
Galley LRZigGeneralAST191.9 MB/s
NomRustGeneralAST69.6 MB/s
Tree-sitterCGeneralCST21.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, and citm_catalog inputs 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.md and come from scripts/benchmark.py, a different harness — expect them to differ.

Environment

Results will vary by machine. All numbers were recorded on an Apple M1 Pro.