LEPTRIS

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 — competitorC / C++RubyPythonJavaScriptRust
libyaml1.62×+————
ryml3.87×+————
simdjson0.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.

operationleptris sidelibyaml 0.2.5standing
Parse DOM — flow json299.08 MB/s49.2 MB/s6.08×
Parse pull — flow json79.67 MB/s49.2 MB/s1.62×
Parse recorder — flow json95.83 MB/s49.2 MB/s1.95×
Emit — flow json271.35 MB/s49.2 MB/s5.52×
Parse DOM — flow single414.41 MB/s52.34 MB/s7.92×
Parse pull — flow single113.02 MB/s52.34 MB/s2.16×
Parse recorder — flow single136.18 MB/s52.34 MB/s2.60×
Emit — flow single274.5 MB/s52.34 MB/s5.24×
Parse DOM — json doc400.49 MB/s46.7 MB/s8.58×
Parse pull — json doc88.32 MB/s46.7 MB/s1.89×
Parse recorder — json doc108.61 MB/s46.7 MB/s2.33×
Emit — json doc400.28 MB/s46.7 MB/s8.57×
Parse DOM — json users443.14 MB/s50.83 MB/s8.72×
Parse pull — json users102.35 MB/s50.83 MB/s2.01×
Parse recorder — json users131.2 MB/s50.83 MB/s2.58×
Emit — json users334.46 MB/s50.83 MB/s6.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

operationleptris sideryml 0.16.0standing
Head-to-head DOM — flow json301.13 MB/sryml 0.16.0 (f8ac8dd)4.17×
Head-to-head DOM — flow single402.21 MB/sryml 0.16.0 (f8ac8dd)3.88×
Head-to-head DOM — json doc400.85 MB/sryml 0.16.0 (f8ac8dd)5.25×
Head-to-head DOM — json users440.84 MB/sryml 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

operationleptris sidesimdjson 3.13.0standing
Head-to-head parse — json-doc via DOM construction1011.79 MB/ssimdjson 3.13.00.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 tape546.79 MB/ssimdjson 3.13.00.38×
Head-to-head parse — json-users via DOM construction1494.24 MB/ssimdjson 3.13.00.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 tape753.69 MB/ssimdjson 3.13.00.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.

operationleptris sideversusstanding
Head-to-head parse — json-doc via the packed record tape546.79 MB/ssimdjson 3.13.00.38×
Head-to-head parse — json-users via the packed record tape753.69 MB/ssimdjson 3.13.00.48×
Head-to-head parse — json-doc via DOM construction1011.79 MB/ssimdjson 3.13.00.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 construction1494.24 MB/ssimdjson 3.13.00.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.