docs: dump comparison and split acknowledgments in the 3.13.0 post

- a dump workload in bench_all and bench_rs: each engine writes a
  document parsed beforehand, and every output must read back with
  bit-identical numbers; an optional argument selects one workload
- the post's comparison gains a write table, a throughput chart, a dump
  row for all three configurations, and the x86-64 cases it loses
- the thanks section is split into adapted code and borrowed ideas

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-30 15:29:48 +01:00
1 parent f4a91f800d
commit c24c177583
9 files changed
+758 -170

No files matched your search

@@ -615,7 +615,8 @@ every number exactly; RapidJSON guarantees that only with `kParseFullPrecisionFl
(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
number), *select* (parse, then read a few fields of every record), *parse+dump*, and *dump* (write a document that
was parsed beforehand; only the writing is timed). 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
@@ -646,6 +647,41 @@ interleaved rounds):
<p class="nj-caption" markdown>The parse times of the table above as throughput (file size divided by time), more is better. RapidJSON, Glaze, serde_json and simd-json are left out to keep the chart readable; they are in the table.</p>
Writing, with each document parsed beforehand, so that only the writing of compact JSON into a new string is timed.
Before anything is timed, every output must read back as the same values, with bit-identical numbers, so every
engine writes every float exactly:
| engine | `twitter.json` | `citm_catalog.json` | `canada.json` | `jeopardy.json` |
| --- | --: | --: | --: | --: |
| nlohmann/json `json_document` | **74.5** | **133** | **1,625** | **14,757** |
| yyjson | 104 | 166 | 1,716 | 20,134 |
| sonic-cpp | 105 | 222 | 3,044 | 19,836 |
| Glaze `generic_u64` | 208 | 469 | 1,700 | 34,367 |
| sonic-rs (Rust) | 213 | 444 | 2,417 | 33,818 |
| nlohmann/json `json::dump` | 217 | 286 | 2,244 | 31,205 |
| serde_json (Rust) | 329 | 487 | 2,236 | 52,629 |
| simdjson DOM | 354 | 498 | 6,816 | 54,833 |
| simd-json (Rust) | 358 | 473 | 2,707 | 47,998 |
| Boost.JSON | 498 | 501 | 2,942 | 63,392 |
| RapidJSON | 592 | 815 | 6,999 | 83,397 |
<p class="nj-table-caption" markdown>Write times in µs, less is better: compact output of a document parsed beforehand, on an Apple M1 Max, best of 2 × 30 interleaved rounds (2 × 6 for `jeopardy.json`). The fastest engine of each file is in bold. Boost.JSON writes some floats of `canada.json` with more digits, so its output is 9 % larger.</p>
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_view_dump.svg"
</div>
<p class="nj-caption" markdown>The write times of the table above as throughput (size of the compact output divided by time), more is better, for the engines of the parse chart.</p>
On the Mac, `json_document` writes fastest on every file, 1.05 to 1.40 times ahead of the next engine. Part of that is its
design, not the writer: a string that had no escape sequence in the source has nothing to escape, so it is copied
from the source text without being scanned, and integers are copied as their source text. Floats are formatted
anew with Żmij (theme 3), and since `json_document` keeps floats as text, a float of more than 15 significant digits
is first converted from its digits to a `double`. That is why `canada.json` is the closest race on the Mac (Glaze
takes 1.05 times as long, yyjson 1.06) and is lost on x86-64, where yyjson takes 0.78 (GCC) and 0.93 (Clang) of
`json_document`'s time; with GCC, even `json::dump()`, which has the `double`s already, is faster there (0.92).
The fastest *other* engine for each workload, as its time divided by nlohmann/json's `json_document`'s, over the
four files above: above 1, `json_document` is ahead; below 1, it is behind.
@@ -655,6 +691,7 @@ four files above: above 1, `json_document` is ahead; below 1, it is behind.
| 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) |
| dump | 1.05–1.40 (yyjson, Glaze, sonic-cpp) | 1.23–1.34 (yyjson) on `twitter`, `citm_catalog`; **0.78** (yyjson) on `canada`; 0.99 (yyjson) on `jeopardy` | 1.28–1.33 (yyjson) on `twitter`, `citm_catalog`; **0.93** (yyjson) on `canada`; **0.95** (sonic-cpp) on `jeopardy` |
<p class="nj-table-caption" markdown>Time of the fastest other engine divided by the time of nlohmann/json's `json_document`, as a range over the four files, with the engines that were fastest; below 1, nlohmann/json is behind.</p>
@@ -672,11 +709,17 @@ Apple silicon. On x86-64 it ties with simdjson's DOM on typical documents. Where
- **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).
- **Writing floats on x86-64.** Writing a document it parsed beforehand, `json_document` is behind yyjson on
`canada.json` (0.78 with GCC, 0.93 with Clang), because it first converts most floats from their text, and ties
on `jeopardy.json` (0.95 to 0.99).
- **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.
times as fast on the Mac, and 2.4 to 4.5 times on the x86-64 server. For writing, the comparison goes the other way:
`json::dump()` writes 1.3 to 2.3 times as fast as Boost.JSON's `serialize()` on the Mac. On the x86-64 server it is
1.1 to 1.6 times as fast on three files, but Boost.JSON writes `jeopardy.json` 4 % (Clang) to 12 % (GCC) faster. On the Mac it is also ahead of RapidJSON, simdjson's DOM and simd-json on every file, and of sonic-rs and
serde_json on all but one file each, where they are within 2 %.
The programs are in
[`tests/benchmarks/json_view/others`](https://github.com/nlohmann/json/tree/develop/tests/benchmarks/json_view/others),
@@ -772,33 +815,39 @@ behaves differently. We did not test Windows for speed at all.
## Thanks
Most of what is in this post was invented by other people. The libraries and papers we took ideas or code from, in
the order they appear above, each with its license in parentheses. The library contains code adapted from four of
them, marked "adapted code", which it uses under the MIT License; the
[README](https://github.com/nlohmann/json#license) has their copyright notices. From the others we took the idea,
not their code.
Most of what is in this post was invented by other people. Each library is listed with its license in
parentheses.
**Code we adapted.** The library contains code adapted from these four projects. We use it under the MIT License,
and the source files that contain it carry the authors' copyright lines and say what was taken; the
[README](https://github.com/nlohmann/json#license) lists them too.
- [fast_float](https://github.com/fastfloat/fast_float) (Apache-2.0, MIT or BSL-1.0) by Daniel Lemire and
contributors: the Eisel-Lemire algorithm, its table of powers of five, its digit comparison for long numbers, and
its parsing of eight digits at a time (N. Mushtak and D. Lemire, "Fast number parsing without fallback", 2023).
W. D. Clinger for the fast path, M. Eisel for the algorithm.
- [Żmij](https://github.com/vitaut/zmij) (MIT) by Victor Zverovich, with the digit conversion of Xiang JunBo and the
SIMD sequence and compressed powers of ten of Dougall Johnson: ported to C++11.
- [simdjson](https://github.com/simdjson/simdjson) (Apache-2.0 or MIT) by Daniel Lemire, Geoff Langdale, John Keiser
and contributors: the "lookup4" UTF-8 check and its tables (J. Keiser and D. Lemire, "Validating UTF-8 In Less
Than One Instruction Per Byte", 2021), in `json.hpp`'s lexer and in `json_view.hpp`.
- [yyjson](https://github.com/ibireme/yyjson) (MIT) by YaoYuan: table-driven `\u` decoding and the unrolled checks
at fixed offsets in `json_view.hpp`'s parser.
**Ideas we took.** From these we took the idea, not their code, in the order they appear above:
- [serde_json](https://github.com/serde-rs/json) (MIT or Apache-2.0): deriving positions from the offset only on error.
- Sean Eron Anderson's [Bit Twiddling Hacks](https://graphics.stanford.edu/~seander/bithacks.html) (snippets in the
public domain): the zero-byte test behind every word-at-a-time scan.
- [Glaze](https://github.com/stephenberry/glaze) (MIT): skipping indentation in 8-byte steps (`skip_matching_ws`).
- [simdjson](https://github.com/simdjson/simdjson) (Apache-2.0 or MIT) by Daniel Lemire, Geoff Langdale, John Keiser
and contributors: the "lookup4" UTF-8 check (J. Keiser and D. Lemire, "Validating UTF-8 In Less Than One
Instruction Per Byte", 2021; adapted code), and the tape that showed what a flat index can do.
- [SQLite](https://sqlite.org) (public domain): writing short strings with a table loop, as its `jsonAppendString()`
does.
- [orjson](https://github.com/ijl/orjson) (Apache-2.0 or MIT; its escape table MPL-2.0) and
[sonic-rs](https://github.com/cloudwego/sonic-rs) (Apache-2.0), from which orjson adapted it: escape sequences as
fixed-size table rows (`QUOTE_TAB`).
- [fast_float](https://github.com/fastfloat/fast_float) (Apache-2.0, MIT or BSL-1.0) by Daniel Lemire and
contributors: the Eisel-Lemire algorithm, its table of powers of five, its digit comparison, and eight digits at a
time (N. Mushtak and D. Lemire, "Fast number parsing without fallback", 2023; adapted code). W. D. Clinger for the
fast path, M. Eisel for the algorithm.
- [Żmij](https://github.com/vitaut/zmij) (MIT) by Victor Zverovich, with the digit conversion of Xiang JunBo and the
SIMD sequence of Dougall Johnson (adapted code: ported to C++11).
- [simdjson](https://github.com/simdjson/simdjson)'s tape and [yyjson](https://github.com/ibireme/yyjson)'s 16-byte
immutable document: a flat index in document order instead of a tree.
- [Boost.JSON](https://github.com/boostorg/json) (BSL-1.0): switching to a hash table for large objects.
- [yyjson](https://github.com/ibireme/yyjson) (MIT) by YaoYuan: table-driven `\u` decoding and fixed-offset unrolled
checks (adapted code in `json_view.hpp`), and a 16-byte flat document to measure against.
- [RapidJSON](https://github.com/Tencent/rapidjson) (MIT): the measured reason to keep recursion as the default.
And the people who sent or shaped pull requests: [@gregmarr](https://github.com/gregmarr) reviewed most of them and
+1 -1
View File
@@ -1,6 +1,6 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 580 492" 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 nlohmann/json&#x27;s json_document and json::parse and five other document parsers, fresh documents, Apple M1 Max</title>
<desc id="nj-blog-view-d">Grouped horizontal bars in GB/s, more is better. twitter.json nlohmann/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 nlohmann/json json::parse 0.47 GB/s; citm_catalog.json nlohmann/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 nlohmann/json json::parse 0.72 GB/s; canada.json nlohmann/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 nlohmann/json json::parse 0.38 GB/s; jeopardy.json nlohmann/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 nlohmann/json json::parse 0.34 GB/s.</desc>
<desc id="nj-blog-view-d">Grouped horizontal bars of parse throughput in GB/s, more is better. twitter.json nlohmann/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 nlohmann/json json::parse 0.47 GB/s; citm_catalog.json nlohmann/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 nlohmann/json json::parse 0.72 GB/s; canada.json nlohmann/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 nlohmann/json json::parse 0.38 GB/s; jeopardy.json nlohmann/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 nlohmann/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">nlohmann/json json_document</text>
<rect class="nj-charts-c2" x="241.8" y="10" width="12" height="12" rx="3"/>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,106 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 580 472" role="img" aria-labelledby="nj-blog-view-dump nj-blog-view-dump-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-view-dump">Write throughput of nlohmann/json&#x27;s json_document and json, and five other libraries, each writing a document parsed beforehand, Apple M1 Max</title>
<desc id="nj-blog-view-dump-d">Grouped horizontal bars of write throughput in GB/s, more is better. twitter.json nlohmann/json json_document 6.27 GB/s; twitter.json yyjson 4.48 GB/s; twitter.json simdjson D&#8203;OM 1.32 GB/s; twitter.json sonic-rs (Rust) 2.20 GB/s; twitter.json sonic-cpp 4.46 GB/s; twitter.json Boost.J&#8203;SON 0.94 GB/s; twitter.json nlohmann/json json::dump 2.15 GB/s; citm_catalog.json nlohmann/json json_document 3.77 GB/s; citm_catalog.json yyjson 3.02 GB/s; citm_catalog.json simdjson D&#8203;OM 1.00 GB/s; citm_catalog.json sonic-rs (Rust) 1.13 GB/s; citm_catalog.json sonic-cpp 2.25 GB/s; citm_catalog.json Boost.J&#8203;SON 1.00 GB/s; citm_catalog.json nlohmann/json json::dump 1.75 GB/s; canada.json nlohmann/json json_document 1.29 GB/s; canada.json yyjson 1.22 GB/s; canada.json simdjson D&#8203;OM 0.31 GB/s; canada.json sonic-rs (Rust) 0.86 GB/s; canada.json sonic-cpp 0.69 GB/s; canada.json Boost.J&#8203;SON 0.71 GB/s; canada.json nlohmann/json json::dump 0.93 GB/s; jeopardy.json nlohmann/json json_document 3.56 GB/s; jeopardy.json yyjson 2.61 GB/s; jeopardy.json simdjson D&#8203;OM 0.96 GB/s; jeopardy.json sonic-rs (Rust) 1.55 GB/s; jeopardy.json sonic-cpp 2.65 GB/s; jeopardy.json Boost.J&#8203;SON 0.83 GB/s; jeopardy.json nlohmann/json json::dump 1.68 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">nlohmann/json json_document</text>
<rect class="nj-charts-c2" x="241.8" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="259.8" y="20.5">yyjson</text>
<rect class="nj-charts-c3" x="320.2" y="10" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="338.2" y="20.5">simdjson D&#8203;OM</text>
<rect class="nj-charts-c4" x="8" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="26" y="40.5">sonic-rs (Rust)</text>
<rect class="nj-charts-c5" x="153" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="171" y="40.5">sonic-cpp</text>
<rect class="nj-charts-c6" x="253.6" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="271.6" y="40.5">Boost.J&#8203;SON</text>
<rect class="nj-charts-c1 nj-charts-dim" x="361.6" y="30" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="379.6" y="40.5">nlohmann/json json::dump</text>
<line class="nj-charts-grid" x1="173" y1="60" x2="173" y2="428"/>
<text class="nj-charts-tick" x="173" y="444">0.5</text>
<line class="nj-charts-grid" x1="204" y1="60" x2="204" y2="428"/>
<text class="nj-charts-tick" x="204" y="444">1</text>
<line class="nj-charts-grid" x1="235" y1="60" x2="235" y2="428"/>
<text class="nj-charts-tick" x="235" y="444">1.5</text>
<line class="nj-charts-grid" x1="266" y1="60" x2="266" y2="428"/>
<text class="nj-charts-tick" x="266" y="444">2</text>
<line class="nj-charts-grid" x1="297" y1="60" x2="297" y2="428"/>
<text class="nj-charts-tick" x="297" y="444">2.5</text>
<line class="nj-charts-grid" x1="328" y1="60" x2="328" y2="428"/>
<text class="nj-charts-tick" x="328" y="444">3</text>
<line class="nj-charts-grid" x1="359" y1="60" x2="359" y2="428"/>
<text class="nj-charts-tick" x="359" y="444">3.5</text>
<line class="nj-charts-grid" x1="390" y1="60" x2="390" y2="428"/>
<text class="nj-charts-tick" x="390" y="444">4</text>
<line class="nj-charts-grid" x1="421" y1="60" x2="421" y2="428"/>
<text class="nj-charts-tick" x="421" y="444">4.5</text>
<line class="nj-charts-grid" x1="452" y1="60" x2="452" y2="428"/>
<text class="nj-charts-tick" x="452" y="444">5</text>
<line class="nj-charts-grid" x1="483" y1="60" x2="483" y2="428"/>
<text class="nj-charts-tick" x="483" y="444">5.5</text>
<line class="nj-charts-grid" x1="514" y1="60" x2="514" y2="428"/>
<text class="nj-charts-tick" x="514" y="444">6</text>
<line class="nj-charts-grid" x1="545" y1="60" x2="545" y2="428"/>
<text class="nj-charts-tick" x="545" y="444">6.5</text>
<text class="nj-charts-tick" x="343.5" y="462">GB/s, more is better</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 H526.566 Q530.566 64 530.566 68 V69 Q530.566 73 526.566 73 H142 Z"><title>nlohmann/json json_document, twitter.json: 6.27 GB/s</title></path>
<text class="nj-charts-val" x="534.566" y="71.5">6.27</text>
<path class="nj-charts-c2" d="M142 75 H415.814 Q419.814 75 419.814 79 V80 Q419.814 84 415.814 84 H142 Z"><title>yyjson, twitter.json: 4.48 GB/s</title></path>
<text class="nj-charts-val" x="423.814" y="82.5">4.48</text>
<path class="nj-charts-c3" d="M142 86 H219.728 Q223.728 86 223.728 90 V91 Q223.728 95 219.728 95 H142 Z"><title>simdjson D&#8203;OM, twitter.json: 1.32 GB/s</title></path>
<text class="nj-charts-val" x="227.728" y="93.5">1.32</text>
<path class="nj-charts-c4" d="M142 97 H274.163 Q278.163 97 278.163 101 V102 Q278.163 106 274.163 106 H142 Z"><title>sonic-rs (Rust), twitter.json: 2.20 GB/s</title></path>
<text class="nj-charts-val" x="282.163" y="104.5">2.20</text>
<path class="nj-charts-c5" d="M142 108 H414.751 Q418.751 108 418.751 112 V113 Q418.751 117 414.751 117 H142 Z"><title>sonic-cpp, twitter.json: 4.46 GB/s</title></path>
<text class="nj-charts-val" x="422.751" y="115.5">4.46</text>
<path class="nj-charts-c6" d="M142 119 H196.176 Q200.176 119 200.176 123 V124 Q200.176 128 196.176 128 H142 Z"><title>Boost.J&#8203;SON, twitter.json: 0.94 GB/s</title></path>
<text class="nj-charts-val" x="204.176" y="126.5">0.94</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 130 H271.586 Q275.586 130 275.586 134 V135 Q275.586 139 271.586 139 H142 Z"><title>nlohmann/json json::dump, twitter.json: 2.15 GB/s</title></path>
<text class="nj-charts-val" x="279.586" y="137.5">2.15</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 H371.573 Q375.573 155 375.573 159 V160 Q375.573 164 371.573 164 H142 Z"><title>nlohmann/json json_document, citm_catalog.json: 3.77 GB/s</title></path>
<text class="nj-charts-val" x="379.573" y="162.5">3.77</text>
<path class="nj-charts-c2" d="M142 166 H325.197 Q329.197 166 329.197 170 V171 Q329.197 175 325.197 175 H142 Z"><title>yyjson, citm_catalog.json: 3.02 GB/s</title></path>
<text class="nj-charts-val" x="333.197" y="173.5">3.02</text>
<path class="nj-charts-c3" d="M142 177 H200.261 Q204.261 177 204.261 181 V182 Q204.261 186 200.261 186 H142 Z"><title>simdjson D&#8203;OM, citm_catalog.json: 1.00 GB/s</title></path>
<text class="nj-charts-val" x="208.261" y="184.5">1.00</text>
<path class="nj-charts-c4" d="M142 188 H207.877 Q211.877 188 211.877 192 V193 Q211.877 197 207.877 197 H142 Z"><title>sonic-rs (Rust), citm_catalog.json: 1.13 GB/s</title></path>
<text class="nj-charts-val" x="215.877" y="195.5">1.13</text>
<path class="nj-charts-c5" d="M142 199 H277.535 Q281.535 199 281.535 203 V204 Q281.535 208 277.535 208 H142 Z"><title>sonic-cpp, citm_catalog.json: 2.25 GB/s</title></path>
<text class="nj-charts-val" x="285.535" y="206.5">2.25</text>
<path class="nj-charts-c6" d="M142 210 H199.864 Q203.864 210 203.864 214 V215 Q203.864 219 199.864 219 H142 Z"><title>Boost.J&#8203;SON, citm_catalog.json: 1.00 GB/s</title></path>
<text class="nj-charts-val" x="207.864" y="217.5">1.00</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 221 H246.646 Q250.646 221 250.646 225 V226 Q250.646 230 246.646 230 H142 Z"><title>nlohmann/json json::dump, citm_catalog.json: 1.75 GB/s</title></path>
<text class="nj-charts-val" x="254.646" y="228.5">1.75</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 H217.746 Q221.746 246 221.746 250 V251 Q221.746 255 217.746 255 H142 Z"><title>nlohmann/json json_document, canada.json: 1.29 GB/s</title></path>
<text class="nj-charts-val" x="225.746" y="253.5">1.29</text>
<path class="nj-charts-c2" d="M142 257 H213.534 Q217.534 257 217.534 261 V262 Q217.534 266 213.534 266 H142 Z"><title>yyjson, canada.json: 1.22 GB/s</title></path>
<text class="nj-charts-val" x="221.534" y="264.5">1.22</text>
<path class="nj-charts-c3" d="M142 268 H157.013 Q161.013 268 161.013 272 V273 Q161.013 277 157.013 277 H142 Z"><title>simdjson D&#8203;OM, canada.json: 0.31 GB/s</title></path>
<text class="nj-charts-val" x="165.013" y="275.5">0.31</text>
<path class="nj-charts-c4" d="M142 279 H191.622 Q195.622 279 195.622 283 V284 Q195.622 288 191.622 288 H142 Z"><title>sonic-rs (Rust), canada.json: 0.86 GB/s</title></path>
<text class="nj-charts-val" x="199.622" y="286.5">0.86</text>
<path class="nj-charts-c5" d="M142 290 H180.571 Q184.571 290 184.571 294 V295 Q184.571 299 180.571 299 H142 Z"><title>sonic-cpp, canada.json: 0.69 GB/s</title></path>
<text class="nj-charts-val" x="188.571" y="297.5">0.69</text>
<path class="nj-charts-c6" d="M142 301 H182.053 Q186.053 301 186.053 305 V306 Q186.053 310 182.053 310 H142 Z"><title>Boost.J&#8203;SON, canada.json: 0.71 GB/s</title></path>
<text class="nj-charts-val" x="190.053" y="308.5">0.71</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 312 H195.752 Q199.752 312 199.752 316 V317 Q199.752 321 195.752 321 H142 Z"><title>nlohmann/json json::dump, canada.json: 0.93 GB/s</title></path>
<text class="nj-charts-val" x="203.752" y="319.5">0.93</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 H358.607 Q362.607 337 362.607 341 V342 Q362.607 346 358.607 346 H142 Z"><title>nlohmann/json json_document, jeopardy.json: 3.56 GB/s</title></path>
<text class="nj-charts-val" x="366.607" y="344.5">3.56</text>
<path class="nj-charts-c2" d="M142 348 H299.698 Q303.698 348 303.698 352 V353 Q303.698 357 299.698 357 H142 Z"><title>yyjson, jeopardy.json: 2.61 GB/s</title></path>
<text class="nj-charts-val" x="307.698" y="355.5">2.61</text>
<path class="nj-charts-c3" d="M142 359 H197.371 Q201.371 359 201.371 363 V364 Q201.371 368 197.371 368 H142 Z"><title>simdjson D&#8203;OM, jeopardy.json: 0.96 GB/s</title></path>
<text class="nj-charts-val" x="205.371" y="366.5">0.96</text>
<path class="nj-charts-c4" d="M142 370 H234.265 Q238.265 370 238.265 374 V375 Q238.265 379 234.265 379 H142 Z"><title>sonic-rs (Rust), jeopardy.json: 1.55 GB/s</title></path>
<text class="nj-charts-val" x="242.265" y="377.5">1.55</text>
<path class="nj-charts-c5" d="M142 381 H302.122 Q306.122 381 306.122 385 V386 Q306.122 390 302.122 390 H142 Z"><title>sonic-cpp, jeopardy.json: 2.65 GB/s</title></path>
<text class="nj-charts-val" x="310.122" y="388.5">2.65</text>
<path class="nj-charts-c6" d="M142 392 H189.355 Q193.355 392 193.355 396 V397 Q193.355 401 189.355 401 H142 Z"><title>Boost.J&#8203;SON, jeopardy.json: 0.83 GB/s</title></path>
<text class="nj-charts-val" x="197.355" y="399.5">0.83</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 403 H242.327 Q246.327 403 246.327 407 V408 Q246.327 412 242.327 412 H142 Z"><title>nlohmann/json json::dump, jeopardy.json: 1.68 GB/s</title></path>
<text class="nj-charts-val" x="250.327" y="410.5">1.68</text>
<line class="nj-charts-zero" x1="142" y1="60" x2="142" y2="428"/>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

+22 -4
View File
@@ -8,6 +8,7 @@ Generated files:
- 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 and six other document parsers
- perf_blog_view_dump.svg: write throughput of the same engines, each writing a document parsed beforehand
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.
@@ -319,9 +320,23 @@ VIEW_US = [ # (engine, css class, [µs per file]), fresh documents, from the t
("nlohmann/json 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
# dump: the bytes of the compact output, and the same engines, from the dump table in "How it compares"
DUMP_BYTES = [466906, 500299, 2090234, 52508728]
DUMP_US = [
("nlohmann/json json_document", "nj-charts-c1", [74.5, 132.8, 1625.1, 14757.2]),
("yyjson", "nj-charts-c2", [104.2, 165.7, 1715.7, 20133.5]),
("simdjson DOM", "nj-charts-c3", [354.2, 498.2, 6816.1, 54833.4]),
("sonic-rs (Rust)", "nj-charts-c4", [212.6, 443.9, 2416.8, 33818.5]),
("sonic-cpp", "nj-charts-c5", [104.6, 222.3, 3044.2, 19836.1]),
("Boost.JSON", "nj-charts-c6", [497.6, 501.4, 2941.8, 63392.3]),
("nlohmann/json json::dump", "nj-charts-c1 nj-charts-dim", [216.7, 285.5, 2244.0, 31205.3]),
]
DUMP = [(e, c, [n / (t * 1000) for n, t in zip(DUMP_BYTES, us)]) for e, c, us in DUMP_US] # GB/s
def view():
def view(VIEW=VIEW, name="perf_blog_view.svg", tid="nj-blog-view",
title="Parse throughput of nlohmann/json's json_document and json::parse and five other document parsers, fresh documents, Apple M1 Max",
what="parse"):
W, L, R = 580, 142, 545
hi = max(max(v) for _, _, v in VIEW)
hi = math.ceil(hi * 2) / 2
@@ -354,9 +369,8 @@ def view():
b.append('<text class="nj-charts-val" x="%g" y="%g">%.2f</text>' % (X(vals[i]) + 4, y + bh - 1.5, vals[i]))
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 nlohmann/json's json_document and json::parse and five other document parsers, fresh documents, Apple M1 Max",
"Grouped horizontal bars in GB/s, more is better. " + "; ".join(desc) + ".", b)
write(name, W, axis_y + 44, "nj-charts--blog", tid, title,
"Grouped horizontal bars of %s throughput in GB/s, more is better. " % what + "; ".join(desc) + ".", b)
if __name__ == "__main__":
@@ -369,3 +383,7 @@ if __name__ == "__main__":
cliffs()
if VIEW:
view()
if DUMP:
view(DUMP, "perf_blog_view_dump.svg", "nj-blog-view-dump",
"Write throughput of nlohmann/json's json_document and json, and five other libraries, each writing a "
"document parsed beforehand, Apple M1 Max", "write")