Benchmarks · JSON
JSON, through yeptris
yeptris parses JSON as what it is — a strict subset of YAML 1.2 — through a dedicated fused walk that validates the RFC 8259 grammar and builds the document in a single pass. Conformance is gated by the JSONTestSuite corpus under the YAML 1.2 schema, where yeptris accepts all 95 valid inputs and rejects all 188 invalid inputs. The measurements below race the JSON-shaped corpora through the committed benchmark matrix against the YAML incumbents and against simdjson, the reference JSON parser, in the same run. Two consumption routes are measured against simdjson: DOM construction, which builds a navigable document, and the tape route introduced in yeptris 0.2.2, which validates into compact parallel columns with no document model. The simdjson comparison is stated with both numbers and is the honest centerpiece of this page.
| JSON — competitor | C / C++ | Ruby | Python | JavaScript | Rust |
|---|---|---|---|---|---|
| libyaml | 1.62×+ | — | — | — | — |
| ryml | 3.87×+ | — | — | — | — |
| simdjson | 0.38×–0.95× | — | — | — | — |
A green cell with a single value means every measured operation in that race is ahead, and the value shown is the smallest margin. A neutral cell shows the range from the weakest to the strongest operation; hovering lists the operations that remain behind. All rows, including deficits, appear in the tables below.
C
yeptris versus the YAML incumbents
The matrix generates four JSON-shaped corpora: a multi-document flow corpus, a single-document flow corpus, one large flat document, and a record-heavy users corpus. Each is measured through DOM construction, pull parsing and event recording, in addition to emission, in the same run against the same-build reference libraries.
| operation | leptris side | libyaml 0.2.5 | standing |
|---|---|---|---|
| Parse DOM — flow json | 299.08 MB/s | 49.2 MB/s | 6.08× |
| Parse pull — flow json | 79.67 MB/s | 49.2 MB/s | 1.62× |
| Parse recorder — flow json | 95.83 MB/s | 49.2 MB/s | 1.95× |
| Emit — flow json | 271.35 MB/s | 49.2 MB/s | 5.52× |
| Parse DOM — flow single | 414.41 MB/s | 52.34 MB/s | 7.92× |
| Parse pull — flow single | 113.02 MB/s | 52.34 MB/s | 2.16× |
| Parse recorder — flow single | 136.18 MB/s | 52.34 MB/s | 2.60× |
| Emit — flow single | 274.5 MB/s | 52.34 MB/s | 5.24× |
| Parse DOM — json doc | 400.49 MB/s | 46.7 MB/s | 8.58× |
| Parse pull — json doc | 88.32 MB/s | 46.7 MB/s | 1.89× |
| Parse recorder — json doc | 108.61 MB/s | 46.7 MB/s | 2.33× |
| Emit — json doc | 400.28 MB/s | 46.7 MB/s | 8.57× |
| Parse DOM — json users | 443.14 MB/s | 50.83 MB/s | 8.72× |
| Parse pull — json users | 102.35 MB/s | 50.83 MB/s | 2.01× |
| Parse recorder — json users | 131.2 MB/s | 50.83 MB/s | 2.58× |
| Emit — json users | 334.46 MB/s | 50.83 MB/s | 6.58× |
fresh runyeptris 0.6.22 (main f4b6e55)·min-of-iters; h2h rows: interleaved, median of rounds·GitHub Actions ubuntu-latest, x86_64 (AVX2)··bench_matrix — same corpus both engines, same run; h2h rows: interleaved head-to-head, median of rounds; simdjson parses a pre-built padded string (calibrated, #420)
Versus rapidyaml on the same corpora
| operation | leptris side | ryml 0.16.0 | standing |
|---|---|---|---|
| Head-to-head DOM — flow json | 301.13 MB/s | ryml 0.16.0 (f8ac8dd) | 4.17× |
| Head-to-head DOM — flow single | 402.21 MB/s | ryml 0.16.0 (f8ac8dd) | 3.88× |
| Head-to-head DOM — json doc | 400.85 MB/s | ryml 0.16.0 (f8ac8dd) | 5.25× |
| Head-to-head DOM — json users | 440.84 MB/s | ryml 0.16.0 (f8ac8dd) | 3.87× |
The head-to-head against rapidyaml is run interleaved with a fair-order referee and reports the median of rounds. The yeptris performance ledger records the engine-dispatch work behind these rows, together with every measured dead end, in theyeptris ledger.
Versus simdjson, the JSON-native reference
| operation | leptris side | simdjson 3.13.0 | standing |
|---|---|---|---|
| Head-to-head parse — json-doc via DOM construction | 1011.79 MB/s | simdjson 3.13.0 | 0.70× simdjson parses a pre-built padded string into its DOM; the raw-pointer overload's realloc_if_needed input copy is NOT in its timed loop (the harness was calibrated to match, #420). yeptris parse_json builds the full node tree. |
| Head-to-head parse — json-doc via the packed record tape | 546.79 MB/s | simdjson 3.13.0 | 0.38× |
| Head-to-head parse — json-users via DOM construction | 1494.24 MB/s | simdjson 3.13.0 | 0.95× simdjson parses a pre-built padded string into its DOM; the raw-pointer overload's realloc_if_needed input copy is NOT in its timed loop (the harness was calibrated to match, #420). yeptris parse_json builds the full node tree. |
| Head-to-head parse — json-users via the packed record tape | 753.69 MB/s | simdjson 3.13.0 | 0.48× |
simdjson validates JSON into a linear tape with SIMD structural indexing and no document model — a fundamentally cheaper contract than anything that also serves YAML. The referee is calibrated to simdjson’s own harness idiom: it parses a pre-built padded string, so no input-copy tax sits in its timed loop (the calibration itself is ledger history — an earlier version of this table flattered us). Calibrated, the DOM route measures 0.70× simdjson on the flat document shape and 0.95× on the record-heavy shape — the bracket of per-member overhead the ledger’s slices have been cutting — while the packed-record tape route trades tree materialization for bulk access. The walk is the residual, recorded slice by slice in the ledger.
To reproduce: configure yeptris with-DYEPTRIS_BUILD_BENCHMARKS=ON -DYEPTRIS_BENCH_LIBYAML_ROOT=…(and -DYEPTRIS_BENCH_RYML_ROOT=… for the head-to-head), then run bench_matrix --full. The harness is committed atbenchmarks.
JSON
Measured deficits
Every JSON operation in the result data that remains behind its competitor, ordered from the weakest ratio. This section is generated from the same result files as the tables above.
| operation | leptris side | versus | standing |
|---|---|---|---|
| Head-to-head parse — json-doc via the packed record tape | 546.79 MB/s | simdjson 3.13.0 | 0.38× |
| Head-to-head parse — json-users via the packed record tape | 753.69 MB/s | simdjson 3.13.0 | 0.48× |
| Head-to-head parse — json-doc via DOM construction | 1011.79 MB/s | simdjson 3.13.0 | 0.70× simdjson parses a pre-built padded string into its DOM; the raw-pointer overload's realloc_if_needed input copy is NOT in its timed loop (the harness was calibrated to match, #420). yeptris parse_json builds the full node tree. |
| Head-to-head parse — json-users via DOM construction | 1494.24 MB/s | simdjson 3.13.0 | 0.95× simdjson parses a pre-built padded string into its DOM; the raw-pointer overload's realloc_if_needed input copy is NOT in its timed loop (the harness was calibrated to match, #420). yeptris parse_json builds the full node tree. |