docs: compare json_document with Glaze, sonic, RapidJSON and Rust parsers

Extends the comparison in "How 3.13.0 got faster" from yyjson, simdjson and
Boost.JSON to eleven engines: sonic-cpp, RapidJSON and Glaze (generic DOM,
lazy_json, reading into structs) in C++, sonic-rs, simd-json and serde_json in
Rust. Measured on an Apple M1 Max (Apple clang 21, Rust 1.99) and an x86-64
Haswell server (GCC 13, Clang 18). Every engine must return the same values,
string bytes and bit-identical number sums before it is timed.

The post now answers whether json_document is the fastest parser: it is the
fastest document parser at parse+dump everywhere and at parsing on Apple
silicon, ties with simdjson's DOM on x86-64, and loses to simdjson On-Demand
and Glaze structs when only a few fields are read.

tests/benchmarks/json_view/others holds the programs (bench_all.cpp, the Rust
crate with its Cargo.lock), summarize.py and the pinned versions and checksums.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-30 15:29:46 +01:00
1 parent ea848cd2e8
commit 7341f127d3
9 files changed
+1987 -117

No files matched your search

@@ -8,9 +8,10 @@ Since 2016, the README of this library has said this about speed:
That sentence is still true, but the gap is a lot smaller now. Swap the 3.12.0 header for the 3.13.0 one and recompile,
and the 182 benchmarks of the library's suite run on average 2.9× as fast, without a line of your code changing.
Parsing the 1.7 MB `citm_catalog.json` takes 1.75 ms instead of 7.20 ms, and `dump()` of documents made of objects
and strings is 4.7 to 6.7× as fast. The new read-only [`json_document`](../../features/json_view.md) parses the
usual test files faster than yyjson and simdjson's DOM on Apple silicon (with a caveat for float-heavy files that we
explain below).
and strings is 4.7 to 6.7× as fast. The new read-only [`json_document`](../../features/json_view.md) parses and
writes faster than the other document parsers we measured on Apple silicon, including yyjson, simdjson and
sonic-rs, and ties with simdjson on x86-64. It is not the fastest everywhere; [section 8](#8-build-a-different-data-structure)
says where it loses.
This post is about *how*. None of the techniques is new: almost every one of them is borrowed from simdjson, yyjson,
fast_float, Żmij, serde_json, SQLite, Boost.JSON or a textbook, and we name the source at each step. What we think is
@@ -552,42 +553,77 @@ entries in document order instead of trees of separate allocations, and yyjson's
returning the last one meant scanning every object to its end and made lookups in small objects 1.6 to 3.4 times
slower ([#5622][5622]).
Parse times in µs on the M1 Max (C++17, `-O3`, best of 30 interleaved rounds; a fresh `json_document` and yyjson
document each time, simdjson's parser reused as its documentation recommends):
### How it compares
| file | `json_document` | yyjson 0.13.0 | simdjson 4.6.11 DOM | Boost.JSON 1.92.0 | `json::parse` |
| --- | --: | --: | --: | --: | --: |
| `twitter.json` (632 KB) | **182** | 192 | 216 | 866 | 1,368 |
| `citm_catalog.json` (1.7 MB) | **360** | 478 | 490 | 1,480 | 2,409 |
| `canada.json` (2.3 MB) | **960** | 1,489 | 2,098 | 2,501 | 5,890 |
| `jeopardy.json` (56 MB) | **22,687** | 30,528 | 26,875 | 88,900 | 167,664 |
We compared `json_document` with eleven other engines. In C++: yyjson 0.13.0, simdjson 4.6.11 (its DOM and its
On-Demand API), sonic-cpp 1.0.2, RapidJSON (master, 24b5e7a), Glaze 9.0.0 (its `generic_u64` DOM, its `lazy_json`,
and reading straight into structs), and Boost.JSON (1.92 on the Mac, 1.83 on x86-64). In Rust: sonic-rs 0.5.10, simd-json 0.19.0 and serde_json
1.0.154. Plus `json::parse`. Before anything is timed, every engine must report the same number of values, the same
number of string bytes, and a bit-identical sum of all numbers in document order. That means every engine converts
every number exactly; RapidJSON guarantees that only with `kParseFullPrecisionFlag`, so that is what it runs with
(with its default flags it happened to produce the same values for these files, and those rows are in the data).
The workloads: *parse* (build the document and free it), *traverse* (parse, then visit every value and convert every
number), *select* (parse, then read a few fields of every record) and *parse+dump*. We ran them on the M1 Max with
Apple clang 21 (and Rust 1.99), and on the x86-64 Haswell server with GCC 13 and Clang 18 (`-march=haswell`, one
pinned core). That server has other work running, so differences of a few percent there are noise. Glaze 9 could
not be built with Clang 18 on it (Clang 18 can't use GCC 13's `std::expected`), and the Rust engines ran on the Mac
only.
Parse times in µs on the M1 Max, a fresh document each time (C++23 and Rust `--release`, `-O3`, best of 30
interleaved rounds):
| engine | `twitter.json` (632 KB) | `citm_catalog.json` (1.7 MB) | `canada.json` (2.3 MB) | `jeopardy.json` (56 MB) |
| --- | --: | --: | --: | --: |
| `json_document` | **183** | **364** | **943** | **22,681** |
| yyjson | 194 | 478 | 1,489 | 30,342 |
| simdjson DOM | 202 | 486 | 2,097 | 26,904 |
| sonic-rs (Rust) | 302 | 664 | 1,907 | 30,202 |
| sonic-cpp | 379 | 986 | 2,580 | 40,804 |
| simd-json (Rust, input copy included) | 567 | 1,616 | 4,939 | 59,364 |
| Boost.JSON | 868 | 1,483 | 2,481 | 88,925 |
| RapidJSON | 1,183 | 1,613 | 7,358 | 143,044 |
| serde_json (Rust) | 1,202 | 2,337 | 6,836 | 139,829 |
| Glaze `generic_u64` | 1,268 | 2,727 | 9,262 | 132,273 |
| `json::parse` | 1,352 | 2,386 | 5,915 | 163,750 |
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_view.svg"
</div>
On the same four files, reading every value takes yyjson 1.06 to 1.30 times as long as `json_document`, writing
them back with `dump()` 1.06 to 1.35 times, and parsing, editing a few values and writing them 1.34 to 1.85 times (1.0 to 1.57 times for an edit in every
record). Integers are
already converted when you read them, and the writer copies strings and integer tokens straight from the source
([#5633][5633]).
The fastest *other* engine for each workload, as its time divided by `json_document`'s, over the four files above:
above 1, `json_document` is ahead; below 1, it is behind.
It is not faster everywhere, and the harness ([#5627][5627], [#5914][5914]) is built to show where:
| workload | M1 Max, Apple clang 21 | x86-64, GCC 13 | x86-64, Clang 18 |
| --- | --- | --- | --- |
| parse | 1.06–1.58 (yyjson, simdjson DOM) | 0.97–1.01 (simdjson DOM) on `twitter`, `citm_catalog`; 1.89 on `canada`; **0.71** (sonic-cpp) on `jeopardy` | 0.96–0.97 (simdjson DOM) on `twitter`, `citm_catalog`; 1.21–1.56 on `canada`, `jeopardy` |
| traverse | 1.04–1.18 (yyjson, simdjson On-Demand) | **0.58–0.86** (simdjson On-Demand) | **0.86**–1.20 (sonic-cpp, simdjson On-Demand, yyjson) |
| select | **0.34–0.84** (Glaze structs, simdjson On-Demand) | **0.26–0.65** | **0.33–0.86** |
| parse+dump | 1.18–1.35 (yyjson) | 1.20–1.41 (yyjson, sonic-cpp) | 1.16–1.27 (yyjson, sonic-cpp) |
- **Reading a few fields.** simdjson's On-Demand API builds nothing and can only read forward. Picking a few fields
out of `twitter.json`, `canada.json` and `jeopardy.json` takes it 0.67 to 0.80 times as long as `json_document`.
- **Floats are converted later.** `json_document` converts a float when you read it; yyjson and simdjson convert
every number while parsing. For `canada.json`, which is almost all floats, the parse row therefore flatters
`json_document` (1.55× ahead of yyjson); reading every value after parsing is the fair comparison, and there it
is 1.07× ahead.
- **Other CPUs.** On the x86-64 machine with GCC, simdjson's DOM with AVX2 was 19 % ahead on parsing
`twitter.json` and 7 % on `citm_catalog.json` ([#5627][5627]), and yyjson's `dump()` of `canada.json` still is
ahead: `json_document` takes 1.4 times as long there ([#5908][5908]). Our tables are from one Apple silicon
machine.
- **Small documents.** For a 2.5 KB status message, all three engines parse in about a microsecond, and yyjson is
6 % ahead. For a 94-byte message, the engines trade places between runs.
- **`json::parse` itself.** Boost.JSON builds a mutable tree, as `json` does, so it is the fair comparison for
`json::parse`, not for `json_document`. It is still 1.6 to 2.4 times as fast.
So, is it the fastest JSON parser? Not in general. Among the parsers that build a document you can read in any
order, it is the fastest at parsing and writing back in every configuration we ran, and the fastest at parsing on
Apple silicon. On x86-64 it ties with simdjson's DOM on typical documents. Where it loses:
- **Reading a few known fields.** simdjson's On-Demand API builds nothing and reads forward only; Glaze reading into
structs that declare just the needed fields skips everything else without building it. Both are faster for
*select*, Glaze by up to 3.8× on `canada.json`, where it skips the coordinates.
- **One pass over everything on x86-64 with GCC.** simdjson On-Demand visits every value in 0.58 to 0.86 of the time.
- **Fresh large documents on Linux.** A fresh 56 MB `jeopardy.json` pays for the page faults of a new index of
3.25 million 16-byte nodes (52 MB). With GCC, sonic-cpp parses it in 0.71 of the time. Reusing the document (`read()`) halves `json_document`'s time
there, and then it is ahead of a reused simdjson parser (0.53 against 0.61 of the fresh time).
- **Float-heavy documents, measured fairly.** `json_document` converts a float when you read it; the others convert
while parsing. The `canada.json` parse row flatters it; *traverse* is the fair comparison, and there it is
1.04× ahead on the Mac and behind sonic-cpp with Clang on x86-64 (0.88).
- **Small documents.** On a 2.5 KB message, all document parsers take about a microsecond, and yyjson and
simdjson's DOM are as fast or a few percent faster.
And `json::parse`? Boost.JSON builds a mutable tree as `json` does, so it is the fair comparison. It is 1.6 to 2.4
times as fast on the Mac, and 2.4 to 4.5 times on the x86-64 server.
The programs are in
[`tests/benchmarks/json_view/others`](https://github.com/nlohmann/json/tree/develop/tests/benchmarks/json_view/others),
with the pinned versions and checksums of every library.
## What didn't work
+92 -72
View File
@@ -1,6 +1,6 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 580 404" role="img" aria-labelledby="nj-blog-view nj-blog-view-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-view">Parse throughput of json_document, yyjson, simdjson&#x27;s D&#8203;OM, Boost.J&#8203;SON and json::parse, Apple M1 Max</title>
<desc id="nj-blog-view-d">Grouped horizontal bars in GB/s. twitter.json json_document 3.48 GB/s; twitter.json yyjson 3.29 GB/s; twitter.json simdjson D&#8203;OM 2.92 GB/s; twitter.json Boost.J&#8203;SON 0.73 GB/s; twitter.json json::parse 0.46 GB/s; citm_catalog.json json_document 4.80 GB/s; citm_catalog.json yyjson 3.61 GB/s; citm_catalog.json simdjson D&#8203;OM 3.52 GB/s; citm_catalog.json Boost.J&#8203;SON 1.17 GB/s; citm_catalog.json json::parse 0.72 GB/s; canada.json json_document 2.35 GB/s; canada.json yyjson 1.51 GB/s; canada.json simdjson D&#8203;OM 1.07 GB/s; canada.json Boost.J&#8203;SON 0.90 GB/s; canada.json json::parse 0.38 GB/s; jeopardy.json json_document 2.45 GB/s; jeopardy.json yyjson 1.82 GB/s; jeopardy.json simdjson D&#8203;OM 2.07 GB/s; jeopardy.json Boost.J&#8203;SON 0.62 GB/s; jeopardy.json json::parse 0.33 GB/s.</desc>
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 580 472" role="img" aria-labelledby="nj-blog-view nj-blog-view-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-view">Parse throughput of json_document and six other document parsers, fresh documents, Apple M1 Max</title>
<desc id="nj-blog-view-d">Grouped horizontal bars in GB/s. twitter.json json_document 3.45 GB/s; twitter.json yyjson 3.26 GB/s; twitter.json simdjson D&#8203;OM 3.13 GB/s; twitter.json sonic-rs (Rust) 2.09 GB/s; twitter.json sonic-cpp 1.67 GB/s; twitter.json Boost.J&#8203;SON 0.73 GB/s; twitter.json json::parse 0.47 GB/s; citm_catalog.json json_document 4.75 GB/s; citm_catalog.json yyjson 3.61 GB/s; citm_catalog.json simdjson D&#8203;OM 3.55 GB/s; citm_catalog.json sonic-rs (Rust) 2.60 GB/s; citm_catalog.json sonic-cpp 1.75 GB/s; citm_catalog.json Boost.J&#8203;SON 1.16 GB/s; citm_catalog.json json::parse 0.72 GB/s; canada.json json_document 2.39 GB/s; canada.json yyjson 1.51 GB/s; canada.json simdjson D&#8203;OM 1.07 GB/s; canada.json sonic-rs (Rust) 1.18 GB/s; canada.json sonic-cpp 0.87 GB/s; canada.json Boost.J&#8203;SON 0.91 GB/s; canada.json json::parse 0.38 GB/s; jeopardy.json json_document 2.45 GB/s; jeopardy.json yyjson 1.83 GB/s; jeopardy.json simdjson D&#8203;OM 2.06 GB/s; jeopardy.json sonic-rs (Rust) 1.84 GB/s; jeopardy.json sonic-cpp 1.36 GB/s; jeopardy.json Boost.J&#8203;SON 0.62 GB/s; jeopardy.json json::parse 0.34 GB/s.</desc>
<rect class="nj-charts-c1" x="8" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="26" y="20.5">json_document</text>
<rect class="nj-charts-c2" x="138.2" y="10" width="12" height="12" rx="3"/>
@@ -8,73 +8,93 @@
<rect class="nj-charts-c3" x="216.6" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="234.6" y="20.5">simdjson D&#8203;OM</text>
<rect class="nj-charts-c4" x="339.4" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="357.4" y="20.5">Boost.J&#8203;SON</text>
<rect class="nj-charts-c5" x="447.4" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="465.4" y="20.5">json::parse</text>
<line class="nj-charts-grid" x1="182.3" y1="40" x2="182.3" y2="360"/>
<text class="nj-charts-tick" x="182.3" y="376">0.5</text>
<line class="nj-charts-grid" x1="222.6" y1="40" x2="222.6" y2="360"/>
<text class="nj-charts-tick" x="222.6" y="376">1</text>
<line class="nj-charts-grid" x1="262.9" y1="40" x2="262.9" y2="360"/>
<text class="nj-charts-tick" x="262.9" y="376">1.5</text>
<line class="nj-charts-grid" x1="303.2" y1="40" x2="303.2" y2="360"/>
<text class="nj-charts-tick" x="303.2" y="376">2</text>
<line class="nj-charts-grid" x1="343.5" y1="40" x2="343.5" y2="360"/>
<text class="nj-charts-tick" x="343.5" y="376">2.5</text>
<line class="nj-charts-grid" x1="383.8" y1="40" x2="383.8" y2="360"/>
<text class="nj-charts-tick" x="383.8" y="376">3</text>
<line class="nj-charts-grid" x1="424.1" y1="40" x2="424.1" y2="360"/>
<text class="nj-charts-tick" x="424.1" y="376">3.5</text>
<line class="nj-charts-grid" x1="464.4" y1="40" x2="464.4" y2="360"/>
<text class="nj-charts-tick" x="464.4" y="376">4</text>
<line class="nj-charts-grid" x1="504.7" y1="40" x2="504.7" y2="360"/>
<text class="nj-charts-tick" x="504.7" y="376">4.5</text>
<line class="nj-charts-grid" x1="545" y1="40" x2="545" y2="360"/>
<text class="nj-charts-tick" x="545" y="376">5</text>
<text class="nj-charts-tick" x="343.5" y="394">GB/s, longer is faster</text>
<text class="nj-charts-rowlabel" x="134" y="83.5" text-anchor="end">twitter.json</text>
<path class="nj-charts-c1" d="M142 44 H418.132 Q422.132 44 422.132 48 V51 Q422.132 55 418.132 55 H142 Z"><title>json_document, twitter.json: 3.48 GB/s</title></path>
<text class="nj-charts-val" x="426.132" y="53.5">3.48</text>
<path class="nj-charts-c2" d="M142 57 H403.104 Q407.104 57 407.104 61 V64 Q407.104 68 403.104 68 H142 Z"><title>yyjson, twitter.json: 3.29 GB/s</title></path>
<text class="nj-charts-val" x="411.104" y="66.5">3.29</text>
<path class="nj-charts-c3" d="M142 70 H373.213 Q377.213 70 377.213 74 V77 Q377.213 81 373.213 81 H142 Z"><title>simdjson D&#8203;OM, twitter.json: 2.92 GB/s</title></path>
<text class="nj-charts-val" x="381.213" y="79.5">2.92</text>
<path class="nj-charts-c4" d="M142 83 H196.776 Q200.776 83 200.776 87 V90 Q200.776 94 196.776 94 H142 Z"><title>Boost.J&#8203;SON, twitter.json: 0.73 GB/s</title></path>
<text class="nj-charts-val" x="204.776" y="92.5">0.73</text>
<path class="nj-charts-c5" d="M142 96 H175.208 Q179.208 96 179.208 100 V103 Q179.208 107 175.208 107 H142 Z"><title>json::parse, twitter.json: 0.46 GB/s</title></path>
<text class="nj-charts-val" x="183.208" y="105.5">0.46</text>
<text class="nj-charts-rowlabel" x="134" y="162.5" text-anchor="end">citm_catalog.json</text>
<path class="nj-charts-c1" d="M142 123 H524.809 Q528.809 123 528.809 127 V130 Q528.809 134 524.809 134 H142 Z"><title>json_document, citm_catalog.json: 4.80 GB/s</title></path>
<text class="nj-charts-val" x="532.809" y="132.5">4.80</text>
<path class="nj-charts-c2" d="M142 136 H429.179 Q433.179 136 433.179 140 V143 Q433.179 147 429.179 147 H142 Z"><title>yyjson, citm_catalog.json: 3.61 GB/s</title></path>
<text class="nj-charts-val" x="437.179" y="145.5">3.61</text>
<path class="nj-charts-c3" d="M142 149 H421.992 Q425.992 149 425.992 153 V156 Q425.992 160 421.992 160 H142 Z"><title>simdjson D&#8203;OM, citm_catalog.json: 3.52 GB/s</title></path>
<text class="nj-charts-val" x="429.992" y="158.5">3.52</text>
<path class="nj-charts-c4" d="M142 162 H232.063 Q236.063 162 236.063 166 V169 Q236.063 173 232.063 173 H142 Z"><title>Boost.J&#8203;SON, citm_catalog.json: 1.17 GB/s</title></path>
<text class="nj-charts-val" x="240.063" y="171.5">1.17</text>
<path class="nj-charts-c5" d="M142 175 H195.789 Q199.789 175 199.789 179 V182 Q199.789 186 195.789 186 H142 Z"><title>json::parse, citm_catalog.json: 0.72 GB/s</title></path>
<text class="nj-charts-val" x="203.789" y="184.5">0.72</text>
<text class="nj-charts-rowlabel" x="134" y="241.5" text-anchor="end">canada.json</text>
<path class="nj-charts-c1" d="M142 202 H327.093 Q331.093 202 331.093 206 V209 Q331.093 213 327.093 213 H142 Z"><title>json_document, canada.json: 2.35 GB/s</title></path>
<text class="nj-charts-val" x="335.093" y="211.5">2.35</text>
<path class="nj-charts-c2" d="M142 215 H259.85 Q263.85 215 263.85 219 V222 Q263.85 226 259.85 226 H142 Z"><title>yyjson, canada.json: 1.51 GB/s</title></path>
<text class="nj-charts-val" x="267.85" y="224.5">1.51</text>
<path class="nj-charts-c3" d="M142 228 H224.48 Q228.48 228 228.48 232 V235 Q228.48 239 224.48 239 H142 Z"><title>simdjson D&#8203;OM, canada.json: 1.07 GB/s</title></path>
<text class="nj-charts-val" x="232.48" y="237.5">1.07</text>
<path class="nj-charts-c4" d="M142 241 H210.545 Q214.545 241 214.545 245 V248 Q214.545 252 210.545 252 H142 Z"><title>Boost.J&#8203;SON, canada.json: 0.90 GB/s</title></path>
<text class="nj-charts-val" x="218.545" y="250.5">0.90</text>
<path class="nj-charts-c5" d="M142 254 H168.804 Q172.804 254 172.804 258 V261 Q172.804 265 168.804 265 H142 Z"><title>json::parse, canada.json: 0.38 GB/s</title></path>
<text class="nj-charts-val" x="176.804" y="263.5">0.38</text>
<text class="nj-charts-rowlabel" x="134" y="320.5" text-anchor="end">jeopardy.json</text>
<path class="nj-charts-c1" d="M142 281 H335.369 Q339.369 281 339.369 285 V288 Q339.369 292 335.369 292 H142 Z"><title>json_document, jeopardy.json: 2.45 GB/s</title></path>
<text class="nj-charts-val" x="343.369" y="290.5">2.45</text>
<path class="nj-charts-c2" d="M142 294 H284.675 Q288.675 294 288.675 298 V301 Q288.675 305 284.675 305 H142 Z"><title>yyjson, jeopardy.json: 1.82 GB/s</title></path>
<text class="nj-charts-val" x="292.675" y="303.5">1.82</text>
<path class="nj-charts-c3" d="M142 307 H304.612 Q308.612 307 308.612 311 V314 Q308.612 318 304.612 318 H142 Z"><title>simdjson D&#8203;OM, jeopardy.json: 2.07 GB/s</title></path>
<text class="nj-charts-val" x="312.612" y="316.5">2.07</text>
<path class="nj-charts-c4" d="M142 320 H188.368 Q192.368 320 192.368 324 V327 Q192.368 331 188.368 331 H142 Z"><title>Boost.J&#8203;SON, jeopardy.json: 0.62 GB/s</title></path>
<text class="nj-charts-val" x="196.368" y="329.5">0.62</text>
<path class="nj-charts-c5" d="M142 333 H164.706 Q168.706 333 168.706 337 V340 Q168.706 344 164.706 344 H142 Z"><title>json::parse, jeopardy.json: 0.33 GB/s</title></path>
<text class="nj-charts-val" x="172.706" y="342.5">0.33</text>
<line class="nj-charts-zero" x1="142" y1="40" x2="142" y2="360"/>
<text class="nj-charts-leg" x="357.4" y="20.5">sonic-rs (Rust)</text>
<rect class="nj-charts-c5" x="8" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="26" y="40.5">sonic-cpp</text>
<rect class="nj-charts-c6" x="108.6" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="126.6" y="40.5">Boost.J&#8203;SON</text>
<rect class="nj-charts-c1 nj-charts-dim" x="216.6" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="234.6" y="40.5">json::parse</text>
<line class="nj-charts-grid" x1="182.3" y1="60" x2="182.3" y2="428"/>
<text class="nj-charts-tick" x="182.3" y="444">0.5</text>
<line class="nj-charts-grid" x1="222.6" y1="60" x2="222.6" y2="428"/>
<text class="nj-charts-tick" x="222.6" y="444">1</text>
<line class="nj-charts-grid" x1="262.9" y1="60" x2="262.9" y2="428"/>
<text class="nj-charts-tick" x="262.9" y="444">1.5</text>
<line class="nj-charts-grid" x1="303.2" y1="60" x2="303.2" y2="428"/>
<text class="nj-charts-tick" x="303.2" y="444">2</text>
<line class="nj-charts-grid" x1="343.5" y1="60" x2="343.5" y2="428"/>
<text class="nj-charts-tick" x="343.5" y="444">2.5</text>
<line class="nj-charts-grid" x1="383.8" y1="60" x2="383.8" y2="428"/>
<text class="nj-charts-tick" x="383.8" y="444">3</text>
<line class="nj-charts-grid" x1="424.1" y1="60" x2="424.1" y2="428"/>
<text class="nj-charts-tick" x="424.1" y="444">3.5</text>
<line class="nj-charts-grid" x1="464.4" y1="60" x2="464.4" y2="428"/>
<text class="nj-charts-tick" x="464.4" y="444">4</text>
<line class="nj-charts-grid" x1="504.7" y1="60" x2="504.7" y2="428"/>
<text class="nj-charts-tick" x="504.7" y="444">4.5</text>
<line class="nj-charts-grid" x1="545" y1="60" x2="545" y2="428"/>
<text class="nj-charts-tick" x="545" y="444">5</text>
<text class="nj-charts-tick" x="343.5" y="462">GB/s, longer is faster</text>
<text class="nj-charts-rowlabel" x="134" y="109.5" text-anchor="end">twitter.json</text>
<path class="nj-charts-c1" d="M142 64 H416.142 Q420.142 64 420.142 68 V69 Q420.142 73 416.142 73 H142 Z"><title>json_document, twitter.json: 3.45 GB/s</title></path>
<text class="nj-charts-val" x="424.142" y="71.5">3.45</text>
<path class="nj-charts-c2" d="M142 75 H400.371 Q404.371 75 404.371 79 V80 Q404.371 84 400.371 84 H142 Z"><title>yyjson, twitter.json: 3.26 GB/s</title></path>
<text class="nj-charts-val" x="408.371" y="82.5">3.26</text>
<path class="nj-charts-c3" d="M142 86 H389.98 Q393.98 86 393.98 90 V91 Q393.98 95 389.98 95 H142 Z"><title>simdjson D&#8203;OM, twitter.json: 3.13 GB/s</title></path>
<text class="nj-charts-val" x="397.98" y="93.5">3.13</text>
<path class="nj-charts-c4" d="M142 97 H306.543 Q310.543 97 310.543 101 V102 Q310.543 106 306.543 106 H142 Z"><title>sonic-rs (Rust), twitter.json: 2.09 GB/s</title></path>
<text class="nj-charts-val" x="314.543" y="104.5">2.09</text>
<path class="nj-charts-c5" d="M142 108 H272.301 Q276.301 108 276.301 112 V113 Q276.301 117 272.301 117 H142 Z"><title>sonic-cpp, twitter.json: 1.67 GB/s</title></path>
<text class="nj-charts-val" x="280.301" y="115.5">1.67</text>
<path class="nj-charts-c6" d="M142 119 H196.641 Q200.641 119 200.641 123 V124 Q200.641 128 196.641 128 H142 Z"><title>Boost.J&#8203;SON, twitter.json: 0.73 GB/s</title></path>
<text class="nj-charts-val" x="204.641" y="126.5">0.73</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 130 H175.648 Q179.648 130 179.648 134 V135 Q179.648 139 175.648 139 H142 Z"><title>json::parse, twitter.json: 0.47 GB/s</title></path>
<text class="nj-charts-val" x="183.648" y="137.5">0.47</text>
<text class="nj-charts-rowlabel" x="134" y="200.5" text-anchor="end">citm_catalog.json</text>
<path class="nj-charts-c1" d="M142 155 H520.452 Q524.452 155 524.452 159 V160 Q524.452 164 520.452 164 H142 Z"><title>json_document, citm_catalog.json: 4.75 GB/s</title></path>
<text class="nj-charts-val" x="528.452" y="162.5">4.75</text>
<path class="nj-charts-c2" d="M142 166 H429.24 Q433.24 166 433.24 170 V171 Q433.24 175 429.24 175 H142 Z"><title>yyjson, citm_catalog.json: 3.61 GB/s</title></path>
<text class="nj-charts-val" x="437.24" y="173.5">3.61</text>
<path class="nj-charts-c3" d="M142 177 H424.446 Q428.446 177 428.446 181 V182 Q428.446 186 424.446 186 H142 Z"><title>simdjson D&#8203;OM, citm_catalog.json: 3.55 GB/s</title></path>
<text class="nj-charts-val" x="432.446" y="184.5">3.55</text>
<path class="nj-charts-c4" d="M142 188 H347.658 Q351.658 188 351.658 192 V193 Q351.658 197 347.658 197 H142 Z"><title>sonic-rs (Rust), citm_catalog.json: 2.60 GB/s</title></path>
<text class="nj-charts-val" x="355.658" y="195.5">2.60</text>
<path class="nj-charts-c5" d="M142 199 H279.189 Q283.189 199 283.189 203 V204 Q283.189 208 279.189 208 H142 Z"><title>sonic-cpp, citm_catalog.json: 1.75 GB/s</title></path>
<text class="nj-charts-val" x="287.189" y="206.5">1.75</text>
<path class="nj-charts-c6" d="M142 210 H231.872 Q235.872 210 235.872 214 V215 Q235.872 219 231.872 219 H142 Z"><title>Boost.J&#8203;SON, citm_catalog.json: 1.16 GB/s</title></path>
<text class="nj-charts-val" x="239.872" y="217.5">1.16</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 221 H196.346 Q200.346 221 200.346 225 V226 Q200.346 230 196.346 230 H142 Z"><title>json::parse, citm_catalog.json: 0.72 GB/s</title></path>
<text class="nj-charts-val" x="204.346" y="228.5">0.72</text>
<text class="nj-charts-rowlabel" x="134" y="291.5" text-anchor="end">canada.json</text>
<path class="nj-charts-c1" d="M142 246 H330.402 Q334.402 246 334.402 250 V251 Q334.402 255 330.402 255 H142 Z"><title>json_document, canada.json: 2.39 GB/s</title></path>
<text class="nj-charts-val" x="338.402" y="253.5">2.39</text>
<path class="nj-charts-c2" d="M142 257 H259.85 Q263.85 257 263.85 261 V262 Q263.85 266 259.85 266 H142 Z"><title>yyjson, canada.json: 1.51 GB/s</title></path>
<text class="nj-charts-val" x="267.85" y="264.5">1.51</text>
<path class="nj-charts-c3" d="M142 268 H224.521 Q228.521 268 228.521 272 V273 Q228.521 277 224.521 277 H142 Z"><title>simdjson D&#8203;OM, canada.json: 1.07 GB/s</title></path>
<text class="nj-charts-val" x="232.521" y="275.5">1.07</text>
<path class="nj-charts-c4" d="M142 279 H233.141 Q237.141 279 237.141 283 V284 Q237.141 288 233.141 288 H142 Z"><title>sonic-rs (Rust), canada.json: 1.18 GB/s</title></path>
<text class="nj-charts-val" x="241.141" y="286.5">1.18</text>
<path class="nj-charts-c5" d="M142 290 H208.324 Q212.324 290 212.324 294 V295 Q212.324 299 208.324 299 H142 Z"><title>sonic-cpp, canada.json: 0.87 GB/s</title></path>
<text class="nj-charts-val" x="216.324" y="297.5">0.87</text>
<path class="nj-charts-c6" d="M142 301 H211.13 Q215.13 301 215.13 305 V306 Q215.13 310 211.13 310 H142 Z"><title>Boost.J&#8203;SON, canada.json: 0.91 GB/s</title></path>
<text class="nj-charts-val" x="219.13" y="308.5">0.91</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 312 H168.674 Q172.674 312 172.674 316 V317 Q172.674 321 168.674 321 H142 Z"><title>json::parse, canada.json: 0.38 GB/s</title></path>
<text class="nj-charts-val" x="176.674" y="319.5">0.38</text>
<text class="nj-charts-rowlabel" x="134" y="382.5" text-anchor="end">jeopardy.json</text>
<path class="nj-charts-c1" d="M142 337 H335.421 Q339.421 337 339.421 341 V342 Q339.421 346 335.421 346 H142 Z"><title>json_document, jeopardy.json: 2.45 GB/s</title></path>
<text class="nj-charts-val" x="343.421" y="344.5">2.45</text>
<path class="nj-charts-c2" d="M142 348 H285.574 Q289.574 348 289.574 352 V353 Q289.574 357 285.574 357 H142 Z"><title>yyjson, jeopardy.json: 1.83 GB/s</title></path>
<text class="nj-charts-val" x="293.574" y="355.5">1.83</text>
<path class="nj-charts-c3" d="M142 359 H304.433 Q308.433 359 308.433 363 V364 Q308.433 368 304.433 368 H142 Z"><title>simdjson D&#8203;OM, jeopardy.json: 2.06 GB/s</title></path>
<text class="nj-charts-val" x="312.433" y="366.5">2.06</text>
<path class="nj-charts-c4" d="M142 370 H286.258 Q290.258 370 290.258 374 V375 Q290.258 379 286.258 379 H142 Z"><title>sonic-rs (Rust), jeopardy.json: 1.84 GB/s</title></path>
<text class="nj-charts-val" x="294.258" y="377.5">1.84</text>
<path class="nj-charts-c5" d="M142 381 H247.737 Q251.737 381 251.737 385 V386 Q251.737 390 247.737 390 H142 Z"><title>sonic-cpp, jeopardy.json: 1.36 GB/s</title></path>
<text class="nj-charts-val" x="255.737" y="388.5">1.36</text>
<path class="nj-charts-c6" d="M142 392 H188.354 Q192.354 392 192.354 396 V397 Q192.354 401 188.354 401 H142 Z"><title>Boost.J&#8203;SON, jeopardy.json: 0.62 GB/s</title></path>
<text class="nj-charts-val" x="196.354" y="399.5">0.62</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 403 H165.345 Q169.345 403 169.345 407 V408 Q169.345 412 165.345 412 H142 Z"><title>json::parse, jeopardy.json: 0.34 GB/s</title></path>
<text class="nj-charts-val" x="173.345" y="410.5">0.34</text>
<line class="nj-charts-zero" x1="142" y1="60" x2="142" y2="428"/>
</svg>

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 11 KiB

+19 -14
View File
@@ -7,7 +7,7 @@ Generated files:
json.hpp or json_view.hpp since 3.12.0, one panel each
- perf_blog_swar.svg: the eight-byte string test on one word of input
- perf_blog_cliffs.svg: operations that were quadratic or worse, 3.12.0 against 3.13.0 (log scale)
- perf_blog_view.svg: parse throughput of json_document, yyjson, simdjson's DOM, Boost.JSON and json::parse
- perf_blog_view.svg: parse throughput of json_document and six other document parsers
The numbers are copied from the tables of the post (the timeline from data/perf_timeline.csv, which
`tests/benchmarks/history/history.py summarize` writes); the tables stay on the page as the accessible fallback. Update both together.
@@ -303,12 +303,14 @@ def cliffs():
# engines and GB/s per file, copied from the table in "Build a different data structure"
VIEW_FILES = ["twitter.json", "citm_catalog.json", "canada.json", "jeopardy.json"]
VIEW_BYTES = [631514, 1727204, 2251051, 55554625]
VIEW_US = [ # (engine, css class, [µs per file])
("json_document", "nj-charts-c1", [181.7, 359.9, 959.5, 22687]),
("yyjson", "nj-charts-c2", [192.0, 478.1, 1489, 30528]),
("simdjson DOM", "nj-charts-c3", [216.4, 490.2, 2098, 26875]),
("Boost.JSON", "nj-charts-c4", [866.0, 1480, 2501, 88900]),
("json::parse", "nj-charts-c5", [1368, 2409, 5890, 167664]),
VIEW_US = [ # (engine, css class, [µs per file]), fresh documents, from the table in "How it compares"
("json_document", "nj-charts-c1", [183, 364, 943, 22681]),
("yyjson", "nj-charts-c2", [194, 478, 1489, 30342]),
("simdjson DOM", "nj-charts-c3", [202, 486, 2097, 26904]),
("sonic-rs (Rust)", "nj-charts-c4", [302, 664, 1907, 30202]),
("sonic-cpp", "nj-charts-c5", [379, 986, 2580, 40804]),
("Boost.JSON", "nj-charts-c6", [868, 1483, 2481, 88925]),
("json::parse", "nj-charts-c1 nj-charts-dim", [1352, 2386, 5915, 163750]),
]
VIEW = [(e, c, [n / (t * 1000) for n, t in zip(VIEW_BYTES, us)]) for e, c, us in VIEW_US] # GB/s
@@ -318,15 +320,18 @@ def view():
hi = max(max(v) for _, _, v in VIEW)
hi = math.ceil(hi * 2) / 2
X = lambda v: L + v / hi * (R - L)
bh, gap = 11, 2
top = 44
bh, gap = 9, 2
top = 64
group_h = len(VIEW) * (bh + gap) + 14
b, desc = [], []
x = 8
x, ly = 8, 10
for j, (eng, cls, _) in enumerate(VIEW):
b.append('<rect class="%s" x="%g" y="10" width="12" height="12" rx="3"/>' % (cls, x))
b.append('<text class="nj-charts-leg" x="%g" y="20.5">%s</text>' % (x + 18, esc(eng)))
x += 18 + 7.4 * len(eng) + 16
w = 18 + 7.4 * len(eng) + 16
if x + w > W:
x, ly = 8, ly + 20
b.append('<rect class="%s" x="%g" y="%g" width="12" height="12" rx="3"/>' % (cls, x, ly))
b.append('<text class="nj-charts-leg" x="%g" y="%g">%s</text>' % (x + 18, ly + 10.5, esc(eng)))
x += w
axis_y = top + group_h * len(VIEW_FILES)
t = 0.5
while t <= hi + 1e-9:
@@ -344,7 +349,7 @@ def view():
desc.append("%s %s %.2f GB/s" % (f, eng, vals[i]))
b.append('<line class="nj-charts-zero" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(0), top - 4, X(0), axis_y))
write("perf_blog_view.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-view",
"Parse throughput of json_document, yyjson, simdjson's DOM, Boost.JSON and json::parse, Apple M1 Max",
"Parse throughput of json_document and six other document parsers, fresh documents, Apple M1 Max",
"Grouped horizontal bars in GB/s. " + "; ".join(desc) + ".", b)