docs: captions, test-file table and figure fixes for the 3.13.0 post

- caption every table and figure
- describe what makes twitter.json, citm_catalog.json, canada.json and
  jeopardy.json hard, and what each timeline panel exercises
- split the json_view layout figure into the tree and the index, with
  the example text above; fix the arrows into the string boxes
- arrows and a "less is better" axis label in the cliffs figure
- name nlohmann/json in the comparison tables and chart
- licenses of the adapted code in the thanks section

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 7341f127d3
commit 4566d5ae26
18 files changed
+468 -160

No files matched your search

+1
View File
@@ -51,6 +51,7 @@
.nj-charts .nj-charts-grid { stroke: var(--nj-charts-grid); stroke-width: 1; }
.nj-charts .nj-charts-zero, .nj-charts .nj-charts-axis { stroke: var(--nj-charts-base); stroke-width: 1.5; }
.nj-charts .nj-charts-ref { stroke: currentColor; stroke-width: 1.5; }
.nj-charts .nj-charts-head { fill: var(--nj-charts-base); }
.nj-charts .nj-charts-c1 { fill: var(--nj-charts-c1); }
.nj-charts .nj-charts-c2 { fill: var(--nj-charts-c2); }
@@ -26,6 +26,19 @@ machine, and say so.
## The short version
Most rows below use three files from Milo Yip's [nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)
that JSON libraries have been measured with for a decade, plus one large file. They stress different parts of a
parser:
| file | size | what it is | what makes it hard |
| --- | --: | --- | --- |
| `twitter.json` | 632 KB | 100 tweets from Twitter's search API, with their users | strings: 58 % of the bytes are keys and strings, 15 % of the bytes are non-ASCII (almost all of it Japanese text), and 13,345 keys |
| `citm_catalog.json` | 1.7 MB | a concert hall's catalog of events, performances and seat categories, in French | structure: 21,388 small objects and arrays, 14,392 integers, keys that average 8 bytes, and 71 % whitespace from indentation |
| `canada.json` | 2.3 MB | the outline of Canada in GeoJSON | numbers: 111,080 floating-point coordinates, most with 16 or 17 significant digits, in 56,045 arrays, and almost no whitespace |
| `jeopardy.json` | 56 MB | 216,930 Jeopardy! questions as one array of objects | size: 1.5 million short strings in objects of 7 members; far larger than the CPU caches |
<p class="nj-table-caption" markdown>The test files. The counts are of the parsed values; the share of whitespace, string and non-ASCII bytes is of the file as distributed.</p>
Apple M1 Max, Apple clang 21, `-O3 -flto`, the compiler's default standard (C++14); the same benchmark source for both
headers. The parse rows do not include destroying the result (the suite pauses the timer for that):
@@ -50,10 +63,14 @@ headers. The parse rows do not include destroying the result (the suite pauses t
| copying `citm_catalog.json` and destroying the copy | 1.61 ms | 1.45 ms | 1.11× |
| `==` of `citm_catalog.json` and a copy | 0.264 ms | 0.254 ms | 1.04× |
<p class="nj-table-caption" markdown>Time per call with 3.12.0 and 3.13.0, Google Benchmark suite, median of 8 runs; the speedup is the old time divided by the new one.</p>
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_overview.svg"
</div>
<p class="nj-caption" markdown>The speedups of the table above as bars. More is better; the vertical line at 1× is 3.12.0.</p>
The average over all 182 benchmarks of the suite is 2.93× (geometric mean); none got slower except the time of a
copy alone, 0.94 to 1.03× (copying and destroying together is 1.09 to 1.29× as fast). We have not measured where the
copy's few percent go; one known cost is the counter that bounds its recursion, about ten nanoseconds per copied
@@ -81,8 +98,18 @@ Eight themes did most of the work:
The suite compares two points. To see which change did what, we compiled one small benchmark against the header of
every commit on `develop` that changed `json.hpp` or `json_view.hpp` since 3.12.0, 315 of them, and ran all of them interleaved
(details in [How we measured](#how-we-measured)). Each panel shows the speedup over 3.12.0 after each commit; the
labels name the pull requests behind the largest steps. Each point is one build, and moving code around changes a
(details in [How we measured](#how-we-measured)). Each panel is one workload, chosen so that each exercises a
different part of the library:
- `parse()` of `citm_catalog.json`: the lexer's structure and whitespace handling, and building many small objects;
- `parse()` of `canada.json`: converting text to floating-point numbers;
- `accept()` of `twitter.json`: the lexer alone, since `accept()` only validates and builds nothing;
- `parse()` of `twitter.json` from an `std::ifstream`: reading from a stream instead of a string;
- `dump()` of `twitter.json` and of `canada.json`: writing strings and writing floating-point numbers;
- `from_cbor()` and `to_cbor()` of `twitter.json`: reading and writing a binary format.
Each panel shows the speedup over 3.12.0 after each commit on a logarithmic scale, so that a step of 2× has the same
height everywhere; the labels name the pull requests behind the largest steps. Each point is one build, and moving code around changes a
build's speed by a few percent on its own, so only the larger steps mean something. When `accept()` of
`twitter.json` got 2.5 % slower over the last 20 commits, we timed the two ends against each other in one binary
with six code layouts: they were equal within 0.2 %.
@@ -114,6 +141,8 @@ with six code layouts: they were equal within 0.2 %.
</div>
</div>
<p class="nj-caption" markdown>Speedup over 3.12.0 of eight workloads after each of the 315 commits that changed the headers, from 3.12.0 (left) to the 3.13.0 candidate (right). More is better; each point is the median of 4 interleaved runs of one build.</p>
A few things stand out:
- **There is no single big step.** Parsing `citm_catalog.json` got faster in about a dozen visible steps; the largest
@@ -250,6 +279,8 @@ also flag a byte *after* a real hit (a borrow), but never one before it, so the
--8<-- "images/perf_blog_swar.svg"
</div>
<p class="nj-caption" markdown>`swar_string_special()` on the last eight bytes of `"twitter",`: one word in, one flag out, and the count of trailing zero bits says how many bytes can be copied before the quote.</p>
The same kind of word test, written in standard C++11 with a `memcpy` load and a fallback for big-endian targets,
now runs in many places:
@@ -261,6 +292,8 @@ now runs in many places:
| `dump()` | runs that need no escaping, with and without `ensure_ascii` | [#5285][5285] |
| `json_view` `dump()` | ASCII runs with `ensure_ascii` | [#5879][5879] |
<p class="nj-table-caption" markdown>Where the eight-byte test is used in 3.13.0, and the pull requests that added it.</p>
Where a vector unit is part of the baseline instruction set (SSE2 on x86-64, NEON on 64-bit Arm), the string paths
use 16 bytes per step ([#5853][5853], [#5628][5628]). Non-ASCII text is validated 16 bytes at a time with simdjson's
"lookup4" UTF-8 check (Keiser and Lemire, 2021). That is the one place that needs more than the baseline: on x86-64
@@ -495,10 +528,14 @@ fixed in this release cycle, measured on the same machine:
| 100,000 × `push_back()` on an `ordered_json` with `JSON_DIAGNOSTICS` | 1,514 ms | 4.98 ms | 304× | every insert re-pointed the parent pointers of all elements | [#5832][5832] |
| 10,000 × `at(i)` on an `ordered_json` array with `JSON_DIAGNOSTICS` | 43.2 ms | 0.081 ms | 533× | the same | [#5832][5832] |
<p class="nj-table-caption" markdown>Operations that were quadratic or worse in 3.12.0, timed with both versions (C++17, `-O3`, median of 3 interleaved runs).</p>
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_cliffs.svg"
</div>
<p class="nj-caption" markdown>The times of the table above on a logarithmic scale; each arrow leads from the time with 3.12.0 to the time with 3.13.0. Less is better.</p>
The `<` case matters to anyone who keeps `json` values in a `std::set`, uses them as `std::map` keys, or sorts them
before C++20. Each level of nesting doubled the work: two equal values nested 30 levels deep took 3.8 seconds to
compare in [#5390][5390]'s measurement, and nothing about such a value is unusual. Since C++20, `<` is derived from
@@ -522,13 +559,24 @@ one million small objects 1.39 times (125 ms to 90 ms).
After all of the above, `json::parse()` is still bound by what it builds: one heap allocation per string, array and
object, and a `std::map` node per member. Many programs only parse a document, read some fields and throw it away.
For them, 3.13.0 adds [`json_document`](../../features/json_view.md) and `json_view` in a new header,
`<nlohmann/json_view.hpp>`.
`<nlohmann/json_view.hpp>`. The two figures below show what each parser makes of this 54-byte text:
```json
{"port": 6379, "price": 19.90, "tags": ["eu", "a\"b"]}
```
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_layout.svg"
--8<-- "images/json_view_layout_tree.svg"
</div>
<p class="nj-caption" markdown>Top: the tree of separate heap allocations that `json::parse()` builds. Bottom: `json_document::parse()` keeps the source text and builds one flat index of 16-byte nodes that point back into it, plus a buffer of decoded strings.</p>
<p class="nj-caption" markdown>What `json::parse()` builds: a tree in which every object, array and string is a separate heap allocation (dashed). The float is converted to a `double` while parsing, so the original text `19.90` is gone.</p>
<div class="nj-fig-wrap" markdown>
--8<-- "images/json_view_layout_index.svg"
</div>
<p class="nj-caption" markdown>What `json_document::parse()` builds from the same text: one flat index of nine 16-byte nodes in document order, which point back into the source text, plus a buffer for the one string with an escape. A `json_view` is two pointers, here to the array.</p>
The design is not ours either. simdjson's tape and yyjson's immutable document are both flat arrays of fixed-size
entries in document order instead of trees of separate allocations, and yyjson's entries are 16 bytes, too. What
@@ -575,7 +623,7 @@ 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** |
| nlohmann/json `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 |
@@ -585,14 +633,18 @@ interleaved rounds):
| 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 |
| nlohmann/json `json::parse` | 1,352 | 2,386 | 5,915 | 163,750 |
<p class="nj-table-caption" markdown>Parse times in µs, less is better: a fresh document per call, built and freed, on an Apple M1 Max. The fastest engine of each file is in bold.</p>
<div class="nj-fig-wrap" markdown>
--8<-- "images/perf_blog_view.svg"
</div>
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.
<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>
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.
| workload | M1 Max, Apple clang 21 | x86-64, GCC 13 | x86-64, Clang 18 |
| --- | --- | --- | --- |
@@ -601,6 +653,8 @@ above 1, `json_document` is ahead; below 1, it is behind.
| 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) |
<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>
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:
@@ -642,6 +696,8 @@ The PRs record the ideas that measured worse, which is as useful as the ones tha
| `json_view`: note a large object inline in the parse loop | `canada.json` 37 % slower | [#5628][5628] |
| `json_view`: vector-scan every string in `set()` | 14–16 % slower on 16-byte strings | [#5926][5926] |
<p class="nj-table-caption" markdown>Ideas that were measured and dropped, from the pull requests that tried them.</p>
## Making fast paths safe
Fast paths are where the bugs are: they read in 8- and 16-byte steps, they skip validation that the slow path did, and
@@ -670,6 +726,8 @@ header of 11,310 lines that you only pay for if you include it). Apple clang 21
| only includes `json.hpp` | 528 ms | 709 ms (+34 %) | 508 ms (−4 %) |
| parses, dumps and writes CBOR | 1,175 ms | 1,885 ms (+60 %) | 1,858 ms (+58 %) |
<p class="nj-table-caption" markdown>Compile time of one translation unit, Apple clang 21, `-O2`, median of 9 compilations; less is better.</p>
We have not broken the second row down by change. [`JSON_NO_AUTOMATIC_UDLS`](../../api/macros/json_no_automatic_udls.md) moves the
`_json` literals into their own header and more than makes up for the first row; the
[compile-time page](../../integration/compile_times.md) lists the other options.
@@ -693,6 +751,8 @@ removed because 3.12.0 has no BON8.
| noise | the coefficient of variation was 3 % or less for 176 of the 182 rows with 3.12.0 and 178 with 3.13.0; the largest was 12 % |
| inputs | `twitter.json`, `citm_catalog.json` and `canada.json` from [nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark), a 56 MB `jeopardy.json`, and number-heavy files |
<p class="nj-table-caption" markdown>Setup of the Google Benchmark comparison of 3.12.0 and 3.13.0.</p>
The cliffs come from small extra programs (C++17, `-O3`, median of 3 interleaved runs). The timeline is
[`tests/benchmarks/history`](https://github.com/nlohmann/json/tree/develop/tests/benchmarks/history): one program,
compiled against `single_include` of 3.12.0, of each of the 315 commits on `develop` that changed `json.hpp` or `json_view.hpp` since, and of the candidate, 4 rounds in random order, median of
@@ -710,7 +770,9 @@ 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:
the order they appear above. Where the library contains code adapted from another project, we name the license we use
it under; the [README](https://github.com/nlohmann/json#license) has the copyright notices. From the others we took
the idea, not their code.
- [serde_json](https://github.com/serde-rs/json): deriving positions from the offset only on error.
- Sean Eron Anderson's [Bit Twiddling Hacks](https://graphics.stanford.edu/~seander/bithacks.html): the zero-byte
@@ -718,17 +780,19 @@ the order they appear above:
- [Glaze](https://github.com/stephenberry/glaze): skipping indentation in 8-byte steps (`skip_matching_ws`).
- [simdjson](https://github.com/simdjson/simdjson) 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), and the tape that showed what a flat index can do.
2021, adapted code; MIT License, also available under the Apache License 2.0), and the tape that showed what a
flat index can do.
- [SQLite](https://sqlite.org)'s `jsonAppendString()`: writing short strings with a table loop.
- [orjson](https://github.com/ijl/orjson)'s `QUOTE_TAB`: escape sequences as fixed-size table rows.
- [fast_float](https://github.com/fastfloat/fast_float) 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). W. D. Clinger for the fast path, M. Eisel for the algorithm.
"Fast number parsing without fallback", 2023; adapted code; MIT License, also available under the Apache License
2.0 and the Boost Software License 1.0). W. D. Clinger for the fast path, M. Eisel for the algorithm.
- [Żmij](https://github.com/vitaut/zmij) by Victor Zverovich, with the digit conversion of Xiang JunBo and the SIMD
sequence of Dougall Johnson.
sequence of Dougall Johnson (ported to C++11; MIT License).
- [Boost.JSON](https://github.com/boostorg/json): switching to a hash table for large objects.
- [yyjson](https://github.com/ibireme/yyjson) by YaoYuan: table-driven `\u` decoding, fixed-offset unrolled checks,
and a 16-byte flat document to measure against.
and a 16-byte flat document to measure against (adapted code in `json_view.hpp`; MIT License).
- [RapidJSON](https://github.com/Tencent/rapidjson): 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
@@ -775,6 +839,7 @@ object keys ([#5328][5328]).
[5741]: https://github.com/nlohmann/json/pull/5741
[5746]: https://github.com/nlohmann/json/pull/5746
[5762]: https://github.com/nlohmann/json/pull/5762
[5782]: https://github.com/nlohmann/json/pull/5782
[5809]: https://github.com/nlohmann/json/pull/5809
[5810]: https://github.com/nlohmann/json/pull/5810
[5822]: https://github.com/nlohmann/json/pull/5822
+5 -5
View File
@@ -17,16 +17,16 @@
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M76 115 L106 115" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="108" y="98" width="84" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="150" y="120" text-anchor="middle" xml:space="preserve">std::map</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 67 226 67" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 67" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="50" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="72" xml:space="preserve">&quot;port&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="72" text-anchor="end" xml:space="preserve">6379</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 115 226 115" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 115" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="98" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="120" xml:space="preserve">&quot;price&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="120" text-anchor="end" xml:space="preserve">19.9</text>
<text class="nj-jsonview-note" x="418" y="120" xml:space="preserve">double: 19.90 is gone</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 C192 115 226 163 226 163" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 163" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="228" y="146" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="168" xml:space="preserve">&quot;tags&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-line" x="396" y="168" text-anchor="end" xml:space="preserve">•</text>
@@ -38,8 +38,8 @@
<path class="nj-jsonview-sep" d="M624 146 V180"/>
<text class="nj-jsonview-mono" x="601" y="168" text-anchor="middle" xml:space="preserve">json</text>
<text class="nj-jsonview-mono" x="647" y="168" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 126 706 150 706 130" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 200 706 176 706 196" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 130 641 130 706 130" marker-end="url(#jvl-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 196 687 196 706 196" marker-end="url(#jvl-line)"/>
<rect class="nj-jsonview-heap" x="708" y="113" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="135" text-anchor="middle" xml:space="preserve">std::string eu</text>
<rect class="nj-jsonview-heap" x="708" y="179" width="126" height="34" rx="5"/>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,148 @@
<svg class="nj-fig nj-jsonview " viewBox="0 0 840 456" role="img" aria-labelledby="fig-jvli-title fig-jvli-title-d" xmlns="http://www.w3.org/2000/svg">
<title id="fig-jvli-title">The same J&#8203;SON text parsed by json_document::parse()</title>
<desc id="fig-jvli-title-d">The same text parsed by json_document::parse(): it keeps the 54 bytes of source text and builds a flat index of nine 16-byte nodes in document order: object, key port, unsigned integer 6379 (the converted value is in the node), key price, float, key tags, array, string eu, and an escaped string. Keys, the float, and the plain string point back into the source text; the escaped string points into the document&#x27;s buffer of decoded strings. A json_view is two pointers: one to the document and one to a node, here the array.</desc>
<defs>
<marker id="jvli-line" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-str" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-key" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-num" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-dec" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-own" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-struct" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvli-bad" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
</defs>
<g transform="translate(0 -236)">
<text class="nj-jsonview-h" x="16" y="262" xml:space="preserve">json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes</text>
<text class="nj-jsonview-note" x="16" y="290" xml:space="preserve">source text, 54 bytes (borrowed, or owned by the document)</text>
<rect class="nj-jsonview-ribbon" x="42" y="300" width="756" height="26" rx="4"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="71" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-num" x="169" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="267" y="302" width="68" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-num" x="379" y="302" width="68" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-key" x="491" y="302" width="54" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-str" x="617" y="302" width="26" height="22" rx="3"/>
<rect class="nj-jsonview-span nj-jsonview-c-dec" x="701" y="302" width="54" height="22" rx="3"/>
<text class="nj-jsonview-mono nj-jsonview-byte" x="49" y="317.5" text-anchor="middle" xml:space="preserve">{</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="63" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="77" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="91" y="317.5" text-anchor="middle" xml:space="preserve">o</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="105" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="119" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="133" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="147" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="175" y="317.5" text-anchor="middle" xml:space="preserve">6</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="189" y="317.5" text-anchor="middle" xml:space="preserve">3</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="203" y="317.5" text-anchor="middle" xml:space="preserve">7</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="217" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="231" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="259" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="273" y="317.5" text-anchor="middle" xml:space="preserve">p</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="287" y="317.5" text-anchor="middle" xml:space="preserve">r</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="301" y="317.5" text-anchor="middle" xml:space="preserve">i</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="315" y="317.5" text-anchor="middle" xml:space="preserve">c</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="329" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="343" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="357" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="385" y="317.5" text-anchor="middle" xml:space="preserve">1</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="399" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="413" y="317.5" text-anchor="middle" xml:space="preserve">.</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="427" y="317.5" text-anchor="middle" xml:space="preserve">9</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="441" y="317.5" text-anchor="middle" xml:space="preserve">0</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="455" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="483" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="497" y="317.5" text-anchor="middle" xml:space="preserve">t</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="511" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="525" y="317.5" text-anchor="middle" xml:space="preserve">g</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="539" y="317.5" text-anchor="middle" xml:space="preserve">s</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="553" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="567" y="317.5" text-anchor="middle" xml:space="preserve">:</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="595" y="317.5" text-anchor="middle" xml:space="preserve">[</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="609" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="623" y="317.5" text-anchor="middle" xml:space="preserve">e</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="637" y="317.5" text-anchor="middle" xml:space="preserve">u</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="651" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="665" y="317.5" text-anchor="middle" xml:space="preserve">,</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="693" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="707" y="317.5" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="721" y="317.5" text-anchor="middle" xml:space="preserve">\</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="735" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="749" y="317.5" text-anchor="middle" xml:space="preserve">b</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="763" y="317.5" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="777" y="317.5" text-anchor="middle" xml:space="preserve">]</text>
<text class="nj-jsonview-mono nj-jsonview-byte" x="791" y="317.5" text-anchor="middle" xml:space="preserve">}</text>
<text class="nj-jsonview-tiny" x="49" y="340" text-anchor="middle" xml:space="preserve">0</text>
<text class="nj-jsonview-tiny" x="189" y="340" text-anchor="middle" xml:space="preserve">10</text>
<text class="nj-jsonview-tiny" x="329" y="340" text-anchor="middle" xml:space="preserve">20</text>
<text class="nj-jsonview-tiny" x="469" y="340" text-anchor="middle" xml:space="preserve">30</text>
<text class="nj-jsonview-tiny" x="609" y="340" text-anchor="middle" xml:space="preserve">40</text>
<text class="nj-jsonview-tiny" x="749" y="340" text-anchor="middle" xml:space="preserve">50</text>
<rect class="nj-jsonview-frame" x="16" y="366" width="808" height="254" rx="10"/>
<text class="nj-jsonview-note nj-jsonview-strong" x="30" y="602" xml:space="preserve">json_document: owns the node index and the buffer of decoded strings</text>
<text class="nj-jsonview-note" x="30" y="500" xml:space="preserve">node index: 9 nodes × 16 bytes = 144 bytes, in document order</text>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="36" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="42" y="420" xml:space="preserve">0</text>
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="78" y="434" text-anchor="middle" xml:space="preserve">object</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="451" text-anchor="middle" xml:space="preserve">len 3</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="78" y="465" text-anchor="middle" xml:space="preserve">next 9</text>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="124" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="130" y="420" xml:space="preserve">1</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="166" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="451" text-anchor="middle" xml:space="preserve">off 2</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="166" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M166 406 C166 367 98 367 98 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-num" x="212" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="218" y="420" xml:space="preserve">2</text>
<text class="nj-jsonview-kind nj-jsonview-c-num" x="254" y="434" text-anchor="middle" xml:space="preserve">uint</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="451" text-anchor="middle" xml:space="preserve">6379</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="254" y="465" text-anchor="middle" xml:space="preserve">(converted)</text>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="300" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="306" y="420" xml:space="preserve">3</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="342" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="451" text-anchor="middle" xml:space="preserve">off 16</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="342" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M342 406 C342 367 301 367 301 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-num" x="388" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="394" y="420" xml:space="preserve">4</text>
<text class="nj-jsonview-kind nj-jsonview-c-num" x="430" y="434" text-anchor="middle" xml:space="preserve">float</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="451" text-anchor="middle" xml:space="preserve">off 24</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="430" y="465" text-anchor="middle" xml:space="preserve">len 5</text>
<path class="nj-jsonview-arr nj-jsonview-c-num" d="M430 406 C430 367 413 367 413 328" marker-end="url(#jvli-num)"/>
<rect class="nj-jsonview-node nj-jsonview-c-key" x="476" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="482" y="420" xml:space="preserve">5</text>
<text class="nj-jsonview-kind nj-jsonview-c-key" x="518" y="434" text-anchor="middle" xml:space="preserve">key</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="451" text-anchor="middle" xml:space="preserve">off 32</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="518" y="465" text-anchor="middle" xml:space="preserve">len 4</text>
<path class="nj-jsonview-arr nj-jsonview-c-key" d="M518 406 C518 367 518 367 518 328" marker-end="url(#jvli-key)"/>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="564" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="570" y="420" xml:space="preserve">6</text>
<text class="nj-jsonview-kind nj-jsonview-c-struct" x="606" y="434" text-anchor="middle" xml:space="preserve">array</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="451" text-anchor="middle" xml:space="preserve">len 2</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="606" y="465" text-anchor="middle" xml:space="preserve">next 3</text>
<rect class="nj-jsonview-node nj-jsonview-c-str" x="652" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="658" y="420" xml:space="preserve">7</text>
<text class="nj-jsonview-kind nj-jsonview-c-str" x="694" y="434" text-anchor="middle" xml:space="preserve">string</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="451" text-anchor="middle" xml:space="preserve">off 41</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="694" y="465" text-anchor="middle" xml:space="preserve">len 2</text>
<path class="nj-jsonview-arr nj-jsonview-c-str" d="M694 406 C694 367 630 367 630 328" marker-end="url(#jvli-str)"/>
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="406" width="84" height="68" rx="5"/>
<text class="nj-jsonview-tiny" x="746" y="420" xml:space="preserve">8</text>
<text class="nj-jsonview-kind nj-jsonview-c-dec" x="782" y="434" text-anchor="middle" xml:space="preserve">string</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="451" text-anchor="middle" xml:space="preserve">escaped</text>
<text class="nj-jsonview-mono nj-jsonview-xs" x="782" y="465" text-anchor="middle" xml:space="preserve">len 3</text>
<text class="nj-jsonview-note" x="773" y="568" text-anchor="middle" xml:space="preserve">decoded strings</text>
<rect class="nj-jsonview-node nj-jsonview-c-dec" x="740" y="518" width="66" height="30" rx="4"/>
<text class="nj-jsonview-mono" x="751" y="538" text-anchor="middle" xml:space="preserve">a</text>
<text class="nj-jsonview-mono" x="773" y="538" text-anchor="middle" xml:space="preserve">&quot;</text>
<text class="nj-jsonview-mono" x="795" y="538" text-anchor="middle" xml:space="preserve">b</text>
<path class="nj-jsonview-arr nj-jsonview-c-dec" d="M782 474 C782 496 773 496 773 518" marker-end="url(#jvli-dec)"/>
<text class="nj-jsonview-mono nj-jsonview-sm" x="470" y="670" text-anchor="end" xml:space="preserve">json_view v = doc.root()[&quot;tags&quot;]</text>
<rect class="nj-jsonview-node nj-jsonview-c-struct" x="480" y="648" width="140" height="34" rx="6"/>
<path class="nj-jsonview-sep" d="M550 648 V682"/>
<text class="nj-jsonview-mono" x="515" y="670" text-anchor="middle" xml:space="preserve">doc*</text>
<text class="nj-jsonview-mono" x="585" y="670" text-anchor="middle" xml:space="preserve">node*</text>
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M515 648 L515 622" marker-end="url(#jvli-struct)"/>
<path class="nj-jsonview-arr nj-jsonview-c-struct" d="M585 648 C585 561 606 561 606 474" marker-end="url(#jvli-struct)"/>
<text class="nj-jsonview-note" x="30" y="524" xml:space="preserve">integers are converted while parsing and kept in their node;</text>
<text class="nj-jsonview-note" x="30" y="542" xml:space="preserve">floats and strings point back into the text</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,49 @@
<svg class="nj-fig nj-jsonview " viewBox="0 0 840 222" role="img" aria-labelledby="fig-jvlt-title fig-jvlt-title-d" xmlns="http://www.w3.org/2000/svg">
<title id="fig-jvlt-title">A J&#8203;SON text parsed by basic_json::parse()</title>
<desc id="fig-jvlt-title-d">The text {&quot;port&quot;: 6379, &quot;price&quot;: 19.90, &quot;tags&quot;: [&quot;eu&quot;, &quot;a\&quot;b&quot;]} parsed by basic_json::parse(): the root json value points to a std::map whose three nodes are separate heap allocations; the price is stored as the double 19.9; the tags array is a std::vector of two json values, each pointing to its own std::string.</desc>
<defs>
<marker id="jvlt-line" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-line nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-str" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-str nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-key" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-key nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-num" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-num nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-dec" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-dec nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-own" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-own nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-struct" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-struct nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
<marker id="jvlt-bad" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6.5" markerHeight="6.5" orient="auto-start-reverse"><path class="nj-jsonview-c-bad nj-jsonview-head" d="M0 1 L10 5 L0 9 z"/></marker>
</defs>
<text class="nj-jsonview-h" x="16" y="26" xml:space="preserve">basic_json::parse(): a tree, every array, object, and string in its own heap allocation</text>
<rect class="nj-jsonview-box" x="16" y="98" width="60" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="46" y="120" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M76 115 L106 115" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="108" y="98" width="84" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="150" y="120" text-anchor="middle" xml:space="preserve">std::map</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 67" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="50" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="72" xml:space="preserve">&quot;port&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="72" text-anchor="end" xml:space="preserve">6379</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 115" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="98" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="120" xml:space="preserve">&quot;price&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-num" x="396" y="120" text-anchor="end" xml:space="preserve">19.9</text>
<text class="nj-jsonview-note" x="418" y="120" xml:space="preserve">double: 19.90 is gone</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M192 115 L226 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="228" y="146" width="180" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-c-key" x="240" y="168" xml:space="preserve">&quot;tags&quot;</text>
<text class="nj-jsonview-mono nj-jsonview-c-line" x="396" y="168" text-anchor="end" xml:space="preserve">•</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M408 163 L442 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="444" y="146" width="104" height="34" rx="5"/>
<text class="nj-jsonview-mono" x="496" y="168" text-anchor="middle" xml:space="preserve">std::vector</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M548 163 L576 163" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="578" y="146" width="92" height="34" rx="5"/>
<path class="nj-jsonview-sep" d="M624 146 V180"/>
<text class="nj-jsonview-mono" x="601" y="168" text-anchor="middle" xml:space="preserve">json</text>
<text class="nj-jsonview-mono" x="647" y="168" text-anchor="middle" xml:space="preserve">json</text>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M601 146 C601 130 641 130 706 130" marker-end="url(#jvlt-line)"/>
<path class="nj-jsonview-arr nj-jsonview-c-line" d="M647 180 C647 196 687 196 706 196" marker-end="url(#jvlt-line)"/>
<rect class="nj-jsonview-heap" x="708" y="113" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="135" text-anchor="middle" xml:space="preserve">std::string eu</text>
<rect class="nj-jsonview-heap" x="708" y="179" width="126" height="34" rx="5"/>
<text class="nj-jsonview-mono nj-jsonview-sm nj-jsonview-c-str" x="771" y="201" text-anchor="middle" xml:space="preserve">std::string a&quot;b</text>
<rect class="nj-jsonview-heap" x="16" y="186" width="18" height="14" rx="3"/>
<text class="nj-jsonview-note" x="42" y="198" xml:space="preserve">a separate heap allocation</text>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

+13 -11
View File
@@ -1,6 +1,6 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 600 364" role="img" aria-labelledby="nj-blog-cliffs nj-blog-cliffs-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 600 380" role="img" aria-labelledby="nj-blog-cliffs nj-blog-cliffs-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-cliffs">Operations that grew quadratically or worse: time with 3.12.0 and 3.13.0, log scale</title>
<desc id="nj-blog-cliffs-d">Dot plot on a logarithmic time axis. diff() 64k numbers vs []: 4102 ms to 9.98 ms; diff() 20k objects vs half: 119 ms to 3.85 ms; parse() callback, 32k objects: 1334 ms to 11.5 ms; &lt; nested 24 deep: 62.6 ms to 0.002 ms; &lt; citm, 10x: 274 ms to 3.81 ms; flatten() citm, ordered_json: 253 ms to 1.37 ms; to_bson() 200 deep, 100x: 19.5 ms to 0.566 ms; push_back() 100k, diagnostics: 1514 ms to 4.98 ms; at(i) 10k, diagnostics: 43.2 ms to 0.081 ms.</desc>
<desc id="nj-blog-cliffs-d">Dot plot on a logarithmic time axis, less is better; an arrow leads from each 3.12.0 time to the 3.13.0 time. diff() 64k numbers vs []: 4102 ms to 9.98 ms; diff() 20k objects vs half: 119 ms to 3.85 ms; parse() callback, 32k objects: 1334 ms to 11.5 ms; &lt; nested 24 deep: 62.6 ms to 0.002 ms; &lt; citm, 10x: 274 ms to 3.81 ms; flatten() citm, ordered_json: 253 ms to 1.37 ms; to_bson() 200 deep, 100x: 19.5 ms to 0.566 ms; push_back() 100k, diagnostics: 1514 ms to 4.98 ms; at(i) 10k, diagnostics: 43.2 ms to 0.081 ms.</desc>
<line class="nj-charts-grid" x1="250" y1="30" x2="250" y2="336"/>
<text class="nj-charts-tick" x="250" y="352">1 µs</text>
<line class="nj-charts-grid" x1="297.857" y1="30" x2="297.857" y2="336"/>
@@ -17,50 +17,52 @@
<text class="nj-charts-tick" x="537.143" y="352">1 s</text>
<line class="nj-charts-grid" x1="585" y1="30" x2="585" y2="336"/>
<text class="nj-charts-tick" x="585" y="352">10 s</text>
<text class="nj-charts-tick" x="417.5" y="370">runtime (log scale), less is better</text>
<defs><marker id="nj-blog-cliffs-head" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" orient="auto"><path class="nj-charts-head" d="M0 0 L10 5 L0 10 z"/></marker></defs>
<circle class="nj-charts-ojson-dot" cx="250" cy="14" r="5"/><text class="nj-charts-leg" x="260" y="18.5">3.12.0</text>
<circle class="nj-charts-json-dot" cx="330" cy="14" r="5"/><text class="nj-charts-leg" x="340" y="18.5">3.13.0</text>
<text class="nj-charts-rowlabel" x="240" y="52" text-anchor="end">diff() 64k numbers vs []</text>
<line class="nj-charts-axis" x1="441.387" y1="48" x2="566.479" y2="48"/>
<line class="nj-charts-axis" x1="560.479" y1="48" x2="448.387" y2="48" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="566.479" cy="48" r="5"><title>diff() 64k numbers vs [], 3.12.0: 4102 ms</title></circle>
<circle class="nj-charts-json-dot" cx="441.387" cy="48" r="5"><title>diff() 64k numbers vs [], 3.13.0: 9.98 ms</title></circle>
<text class="nj-charts-factor" x="503.933" y="41">411&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="86" text-anchor="end">diff() 20k objects vs half</text>
<line class="nj-charts-axis" x1="421.59" y1="82" x2="492.901" y2="82"/>
<line class="nj-charts-axis" x1="486.901" y1="82" x2="428.59" y2="82" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="492.901" cy="82" r="5"><title>diff() 20k objects vs half, 3.12.0: 119 ms</title></circle>
<circle class="nj-charts-json-dot" cx="421.59" cy="82" r="5"><title>diff() 20k objects vs half, 3.13.0: 3.85 ms</title></circle>
<text class="nj-charts-factor" x="457.246" y="75">31&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="120" text-anchor="end">parse() callback, 32k objects</text>
<line class="nj-charts-axis" x1="444.333" y1="116" x2="543.132" y2="116"/>
<line class="nj-charts-axis" x1="537.132" y1="116" x2="451.333" y2="116" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="543.132" cy="116" r="5"><title>parse() callback, 32k objects, 3.12.0: 1334 ms</title></circle>
<circle class="nj-charts-json-dot" cx="444.333" cy="116" r="5"><title>parse() callback, 32k objects, 3.13.0: 11.5 ms</title></circle>
<text class="nj-charts-factor" x="493.733" y="109">116&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="154" text-anchor="end">&lt; nested 24 deep</text>
<line class="nj-charts-axis" x1="264.406" y1="150" x2="479.55" y2="150"/>
<line class="nj-charts-axis" x1="473.55" y1="150" x2="271.406" y2="150" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="479.55" cy="150" r="5"><title>&lt; nested 24 deep, 3.12.0: 62.6 ms</title></circle>
<circle class="nj-charts-json-dot" cx="264.406" cy="150" r="5"><title>&lt; nested 24 deep, 3.13.0: 0.002 ms</title></circle>
<text class="nj-charts-factor" x="371.978" y="143">31300&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="188" text-anchor="end">&lt; citm, 10x</text>
<line class="nj-charts-axis" x1="421.373" y1="184" x2="510.235" y2="184"/>
<line class="nj-charts-axis" x1="504.235" y1="184" x2="428.373" y2="184" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="510.235" cy="184" r="5"><title>&lt; citm, 10x, 3.12.0: 274 ms</title></circle>
<circle class="nj-charts-json-dot" cx="421.373" cy="184" r="5"><title>&lt; citm, 10x, 3.13.0: 3.81 ms</title></circle>
<text class="nj-charts-factor" x="465.804" y="177">72&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="222" text-anchor="end">flatten() citm, ordered_json</text>
<line class="nj-charts-axis" x1="400.114" y1="218" x2="508.578" y2="218"/>
<line class="nj-charts-axis" x1="502.578" y1="218" x2="407.114" y2="218" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="508.578" cy="218" r="5"><title>flatten() citm, ordered_json, 3.12.0: 253 ms</title></circle>
<circle class="nj-charts-json-dot" cx="400.114" cy="218" r="5"><title>flatten() citm, ordered_json, 3.13.0: 1.37 ms</title></circle>
<text class="nj-charts-factor" x="454.346" y="211">185&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="256" text-anchor="end">to_bson() 200 deep, 100x</text>
<line class="nj-charts-axis" x1="381.742" y1="252" x2="455.309" y2="252"/>
<line class="nj-charts-axis" x1="449.309" y1="252" x2="388.742" y2="252" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="455.309" cy="252" r="5"><title>to_bson() 200 deep, 100x, 3.12.0: 19.5 ms</title></circle>
<circle class="nj-charts-json-dot" cx="381.742" cy="252" r="5"><title>to_bson() 200 deep, 100x, 3.13.0: 0.566 ms</title></circle>
<text class="nj-charts-factor" x="418.525" y="245">34&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="290" text-anchor="end">push_back() 100k, diagnostics</text>
<line class="nj-charts-axis" x1="426.939" y1="286" x2="545.763" y2="286"/>
<line class="nj-charts-axis" x1="539.763" y1="286" x2="433.939" y2="286" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="545.763" cy="286" r="5"><title>push_back() 100k, diagnostics, 3.12.0: 1514 ms</title></circle>
<circle class="nj-charts-json-dot" cx="426.939" cy="286" r="5"><title>push_back() 100k, diagnostics, 3.13.0: 4.98 ms</title></circle>
<text class="nj-charts-factor" x="486.351" y="279">304&#215;</text>
<text class="nj-charts-rowlabel" x="240" y="324" text-anchor="end">at(i) 10k, diagnostics</text>
<line class="nj-charts-axis" x1="341.335" y1="320" x2="471.841" y2="320"/>
<line class="nj-charts-axis" x1="465.841" y1="320" x2="348.335" y2="320" marker-end="url(#nj-blog-cliffs-head)"/>
<circle class="nj-charts-ojson-dot" cx="471.841" cy="320" r="5"><title>at(i) 10k, diagnostics, 3.12.0: 43.2 ms</title></circle>
<circle class="nj-charts-json-dot" cx="341.335" cy="320" r="5"><title>at(i) 10k, diagnostics, 3.13.0: 0.081 ms</title></circle>
<text class="nj-charts-factor" x="406.588" y="313">533&#215;</text>

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

@@ -1,6 +1,6 @@
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 560 614" role="img" aria-labelledby="nj-blog-overview nj-blog-overview-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-overview">Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang</title>
<desc id="nj-blog-overview-d">Horizontal bars, longer is faster. twitter.json 3.0x; citm_catalog.json 4.1x; canada.json 3.5x; canada.json, indented 6.7x; citm, ordered_json 6.6x; twitter, std::ifstream 2.5x; citm, FILE* 4.8x; citm, accept() 7.0x; dump() twitter 6.7x; dump() canada 3.0x; dump(4) citm 4.6x; to_cbor() twitter 4.5x; twitter, memory 3.1x; twitter, FILE* 6.3x; diff() canada 10x; iterate canada 2.7x; copy + destroy citm 1.11x; == citm 1.04x.</desc>
<desc id="nj-blog-overview-d">Horizontal bars of the speedup, more is better. twitter.json 3.0x; citm_catalog.json 4.1x; canada.json 3.5x; canada.json, indented 6.7x; citm, ordered_json 6.6x; twitter, std::ifstream 2.5x; citm, FILE* 4.8x; citm, accept() 7.0x; dump() twitter 6.7x; dump() canada 3.0x; dump(4) citm 4.6x; to_cbor() twitter 4.5x; twitter, memory 3.1x; twitter, FILE* 6.3x; diff() canada 10x; iterate canada 2.7x; copy + destroy citm 1.11x; == citm 1.04x.</desc>
<text class="nj-charts-panel" x="8" y="46">Parsing</text>
<text class="nj-charts-panel" x="8" y="270">Writing</text>
<text class="nj-charts-panel" x="8" y="398">Reading C&#8203;BOR</text>
@@ -83,5 +83,5 @@
<text class="nj-charts-val" x="226.2" y="572">1.04&#215;</text>
<line class="nj-charts-ref" x1="220" y1="34" x2="220" y2="586"/>
<line class="nj-charts-zero" x1="190" y1="34" x2="190" y2="586"/>
<text class="nj-charts-note" x="190" y="18">speedup over 3.12.0 (the line at 1&#215; is 3.12.0)</text>
<text class="nj-charts-note" x="190" y="18">speedup over 3.12.0, more is better (the line at 1&#215; is 3.12.0)</text>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-accept_twitter nj-blog-tl-accept_twitter-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-accept_twitter nj-blog-tl-accept_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-accept_twitter">accept() twitter.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-accept_twitter-d">accept() twitter.json: speedup over 3.12.0 at each of 317 commits, ending at 5.0x. Labeled steps: #5234, #5283, #5592, #5809, #5810, #5853.</desc>
<text class="nj-charts-panel" x="8" y="18">accept() twitter.json</text>
@@ -34,4 +34,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="299.2" y1="54.0" x2="299.2" y2="91.1"/>
<text class="nj-charts-note" x="299.2" y="50.0" text-anchor="middle">#5853</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-dump_canada nj-blog-tl-dump_canada-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-dump_canada nj-blog-tl-dump_canada-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-dump_canada">dump() canada.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-dump_canada-d">dump() canada.json: speedup over 3.12.0 at each of 317 commits, ending at 3.3x. Labeled steps: #5285, #5634.</desc>
<text class="nj-charts-panel" x="8" y="18">dump() canada.json</text>
@@ -24,4 +24,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="269.4" y1="54.0" x2="269.4" y2="123.5"/>
<text class="nj-charts-note" x="269.4" y="50.0" text-anchor="middle">#5634</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-dump_twitter nj-blog-tl-dump_twitter-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-dump_twitter nj-blog-tl-dump_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-dump_twitter">dump() twitter.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-dump_twitter-d">dump() twitter.json: speedup over 3.12.0 at each of 317 commits, ending at 6.7x. Labeled steps: #5285, #5738, #5878, #5883.</desc>
<text class="nj-charts-panel" x="8" y="18">dump() twitter.json</text>
@@ -32,4 +32,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="308.3" y1="28.0" x2="308.3" y2="101.8"/>
<text class="nj-charts-note" x="308.3" y="24.0" text-anchor="middle">#5883</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-from_cbor_twitter nj-blog-tl-from_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-from_cbor_twitter nj-blog-tl-from_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-from_cbor_twitter">from_cbor() twitter: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-from_cbor_twitter-d">from_cbor() twitter: speedup over 3.12.0 at each of 317 commits, ending at 2.6x. Labeled steps: #5233, #5501, #5185, #5746.</desc>
<text class="nj-charts-panel" x="8" y="18">from_cbor() twitter</text>
@@ -28,4 +28,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="235.0" y1="54.0" x2="235.0" y2="114.6"/>
<text class="nj-charts-note" x="235.0" y="50.0" text-anchor="middle">#5746</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-parse_canada nj-blog-tl-parse_canada-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_canada nj-blog-tl-parse_canada-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_canada">parse() canada.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_canada-d">parse() canada.json: speedup over 3.12.0 at each of 317 commits, ending at 2.8x. Labeled steps: #5234, #5283, #5617, #5738, #5851, #5882.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() canada.json</text>
@@ -34,4 +34,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="312.8" y1="54.0" x2="312.8" y2="94.2"/>
<text class="nj-charts-note" x="312.0" y="50.0" text-anchor="middle">#5882</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-parse_citm nj-blog-tl-parse_citm-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_citm nj-blog-tl-parse_citm-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_citm">parse() citm_catalog.json: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_citm-d">parse() citm_catalog.json: speedup over 3.12.0 at each of 317 commits, ending at 3.3x. Labeled steps: #5234, #5283, #5592, #5809, #5810, #5882.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() citm_catalog.json</text>
@@ -34,4 +34,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="312.8" y1="54.0" x2="312.8" y2="118.3"/>
<text class="nj-charts-note" x="312.0" y="50.0" text-anchor="middle">#5882</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-parse_twitter_ifstream nj-blog-tl-parse_twitter_ifstream-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-parse_twitter_ifstream nj-blog-tl-parse_twitter_ifstream-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-parse_twitter_ifstream">parse() twitter.json, std::ifstream: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-parse_twitter_ifstream-d">parse() twitter.json, std::ifstream: speedup over 3.12.0 at each of 317 commits, ending at 2.2x. Labeled steps: #5828, #5884.</desc>
<text class="nj-charts-panel" x="8" y="18">parse() twitter.json, std::ifstream</text>
@@ -22,4 +22,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="306.5" y1="41.0" x2="306.5" y2="119.7"/>
<text class="nj-charts-note" x="306.5" y="37.0" text-anchor="middle">#5884</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

@@ -1,4 +1,4 @@
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 252" role="img" aria-labelledby="nj-blog-tl-to_cbor_twitter nj-blog-tl-to_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<svg class="nj-fig nj-charts nj-charts--timeline" viewBox="0 0 340 270" role="img" aria-labelledby="nj-blog-tl-to_cbor_twitter nj-blog-tl-to_cbor_twitter-d" xmlns="http://www.w3.org/2000/svg">
<title id="nj-blog-tl-to_cbor_twitter">to_cbor() twitter: speedup over 3.12.0 by commit</title>
<desc id="nj-blog-tl-to_cbor_twitter-d">to_cbor() twitter: speedup over 3.12.0 at each of 317 commits, ending at 5.0x. Labeled steps: #5328, #5824, #5885.</desc>
<text class="nj-charts-panel" x="8" y="18">to_cbor() twitter</text>
@@ -27,4 +27,5 @@
<line class="nj-charts-grid" stroke-dasharray="2 2" x1="309.2" y1="54.0" x2="309.2" y2="88.7"/>
<text class="nj-charts-note" x="309.2" y="50.0" text-anchor="middle">#5885</text>
<line class="nj-charts-axis" x1="44" y1="208" x2="330" y2="208"/>
<text class="nj-charts-note" x="8" y="262">speedup over 3.12.0 (log scale), more is better</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

+98 -98
View File
@@ -1,100 +1,100 @@
<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>
<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>
<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"/>
<text class="nj-charts-leg" x="156.2" y="20.5">yyjson</text>
<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">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"/>
<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="8" y="50" width="12" height="12" rx="3"/>
<text class="nj-charts-leg" x="26" y="60.5">nlohmann/json json::parse</text>
<line class="nj-charts-grid" x1="182.3" y1="80" x2="182.3" y2="448"/>
<text class="nj-charts-tick" x="182.3" y="464">0.5</text>
<line class="nj-charts-grid" x1="222.6" y1="80" x2="222.6" y2="448"/>
<text class="nj-charts-tick" x="222.6" y="464">1</text>
<line class="nj-charts-grid" x1="262.9" y1="80" x2="262.9" y2="448"/>
<text class="nj-charts-tick" x="262.9" y="464">1.5</text>
<line class="nj-charts-grid" x1="303.2" y1="80" x2="303.2" y2="448"/>
<text class="nj-charts-tick" x="303.2" y="464">2</text>
<line class="nj-charts-grid" x1="343.5" y1="80" x2="343.5" y2="448"/>
<text class="nj-charts-tick" x="343.5" y="464">2.5</text>
<line class="nj-charts-grid" x1="383.8" y1="80" x2="383.8" y2="448"/>
<text class="nj-charts-tick" x="383.8" y="464">3</text>
<line class="nj-charts-grid" x1="424.1" y1="80" x2="424.1" y2="448"/>
<text class="nj-charts-tick" x="424.1" y="464">3.5</text>
<line class="nj-charts-grid" x1="464.4" y1="80" x2="464.4" y2="448"/>
<text class="nj-charts-tick" x="464.4" y="464">4</text>
<line class="nj-charts-grid" x1="504.7" y1="80" x2="504.7" y2="448"/>
<text class="nj-charts-tick" x="504.7" y="464">4.5</text>
<line class="nj-charts-grid" x1="545" y1="80" x2="545" y2="448"/>
<text class="nj-charts-tick" x="545" y="464">5</text>
<text class="nj-charts-tick" x="343.5" y="482">GB/s, more is better</text>
<text class="nj-charts-rowlabel" x="134" y="129.5" text-anchor="end">twitter.json</text>
<path class="nj-charts-c1" d="M142 84 H416.142 Q420.142 84 420.142 88 V89 Q420.142 93 416.142 93 H142 Z"><title>nlohmann/json json_document, twitter.json: 3.45 GB/s</title></path>
<text class="nj-charts-val" x="424.142" y="91.5">3.45</text>
<path class="nj-charts-c2" d="M142 95 H400.371 Q404.371 95 404.371 99 V100 Q404.371 104 400.371 104 H142 Z"><title>yyjson, twitter.json: 3.26 GB/s</title></path>
<text class="nj-charts-val" x="408.371" y="102.5">3.26</text>
<path class="nj-charts-c3" d="M142 106 H389.98 Q393.98 106 393.98 110 V111 Q393.98 115 389.98 115 H142 Z"><title>simdjson D&#8203;OM, twitter.json: 3.13 GB/s</title></path>
<text class="nj-charts-val" x="397.98" y="113.5">3.13</text>
<path class="nj-charts-c4" d="M142 117 H306.543 Q310.543 117 310.543 121 V122 Q310.543 126 306.543 126 H142 Z"><title>sonic-rs (Rust), twitter.json: 2.09 GB/s</title></path>
<text class="nj-charts-val" x="314.543" y="124.5">2.09</text>
<path class="nj-charts-c5" d="M142 128 H272.301 Q276.301 128 276.301 132 V133 Q276.301 137 272.301 137 H142 Z"><title>sonic-cpp, twitter.json: 1.67 GB/s</title></path>
<text class="nj-charts-val" x="280.301" y="135.5">1.67</text>
<path class="nj-charts-c6" d="M142 139 H196.641 Q200.641 139 200.641 143 V144 Q200.641 148 196.641 148 H142 Z"><title>Boost.J&#8203;SON, twitter.json: 0.73 GB/s</title></path>
<text class="nj-charts-val" x="204.641" y="146.5">0.73</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 150 H175.648 Q179.648 150 179.648 154 V155 Q179.648 159 175.648 159 H142 Z"><title>nlohmann/json json::parse, twitter.json: 0.47 GB/s</title></path>
<text class="nj-charts-val" x="183.648" y="157.5">0.47</text>
<text class="nj-charts-rowlabel" x="134" y="220.5" text-anchor="end">citm_catalog.json</text>
<path class="nj-charts-c1" d="M142 175 H520.452 Q524.452 175 524.452 179 V180 Q524.452 184 520.452 184 H142 Z"><title>nlohmann/json json_document, citm_catalog.json: 4.75 GB/s</title></path>
<text class="nj-charts-val" x="528.452" y="182.5">4.75</text>
<path class="nj-charts-c2" d="M142 186 H429.24 Q433.24 186 433.24 190 V191 Q433.24 195 429.24 195 H142 Z"><title>yyjson, citm_catalog.json: 3.61 GB/s</title></path>
<text class="nj-charts-val" x="437.24" y="193.5">3.61</text>
<path class="nj-charts-c3" d="M142 197 H424.446 Q428.446 197 428.446 201 V202 Q428.446 206 424.446 206 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="204.5">3.55</text>
<path class="nj-charts-c4" d="M142 208 H347.658 Q351.658 208 351.658 212 V213 Q351.658 217 347.658 217 H142 Z"><title>sonic-rs (Rust), citm_catalog.json: 2.60 GB/s</title></path>
<text class="nj-charts-val" x="355.658" y="215.5">2.60</text>
<path class="nj-charts-c5" d="M142 219 H279.189 Q283.189 219 283.189 223 V224 Q283.189 228 279.189 228 H142 Z"><title>sonic-cpp, citm_catalog.json: 1.75 GB/s</title></path>
<text class="nj-charts-val" x="287.189" y="226.5">1.75</text>
<path class="nj-charts-c6" d="M142 230 H231.872 Q235.872 230 235.872 234 V235 Q235.872 239 231.872 239 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="237.5">1.16</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 241 H196.346 Q200.346 241 200.346 245 V246 Q200.346 250 196.346 250 H142 Z"><title>nlohmann/json json::parse, citm_catalog.json: 0.72 GB/s</title></path>
<text class="nj-charts-val" x="204.346" y="248.5">0.72</text>
<text class="nj-charts-rowlabel" x="134" y="311.5" text-anchor="end">canada.json</text>
<path class="nj-charts-c1" d="M142 266 H330.402 Q334.402 266 334.402 270 V271 Q334.402 275 330.402 275 H142 Z"><title>nlohmann/json json_document, canada.json: 2.39 GB/s</title></path>
<text class="nj-charts-val" x="338.402" y="273.5">2.39</text>
<path class="nj-charts-c2" d="M142 277 H259.85 Q263.85 277 263.85 281 V282 Q263.85 286 259.85 286 H142 Z"><title>yyjson, canada.json: 1.51 GB/s</title></path>
<text class="nj-charts-val" x="267.85" y="284.5">1.51</text>
<path class="nj-charts-c3" d="M142 288 H224.521 Q228.521 288 228.521 292 V293 Q228.521 297 224.521 297 H142 Z"><title>simdjson D&#8203;OM, canada.json: 1.07 GB/s</title></path>
<text class="nj-charts-val" x="232.521" y="295.5">1.07</text>
<path class="nj-charts-c4" d="M142 299 H233.141 Q237.141 299 237.141 303 V304 Q237.141 308 233.141 308 H142 Z"><title>sonic-rs (Rust), canada.json: 1.18 GB/s</title></path>
<text class="nj-charts-val" x="241.141" y="306.5">1.18</text>
<path class="nj-charts-c5" d="M142 310 H208.324 Q212.324 310 212.324 314 V315 Q212.324 319 208.324 319 H142 Z"><title>sonic-cpp, canada.json: 0.87 GB/s</title></path>
<text class="nj-charts-val" x="216.324" y="317.5">0.87</text>
<path class="nj-charts-c6" d="M142 321 H211.13 Q215.13 321 215.13 325 V326 Q215.13 330 211.13 330 H142 Z"><title>Boost.J&#8203;SON, canada.json: 0.91 GB/s</title></path>
<text class="nj-charts-val" x="219.13" y="328.5">0.91</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 332 H168.674 Q172.674 332 172.674 336 V337 Q172.674 341 168.674 341 H142 Z"><title>nlohmann/json json::parse, canada.json: 0.38 GB/s</title></path>
<text class="nj-charts-val" x="176.674" y="339.5">0.38</text>
<text class="nj-charts-rowlabel" x="134" y="402.5" text-anchor="end">jeopardy.json</text>
<path class="nj-charts-c1" d="M142 357 H335.421 Q339.421 357 339.421 361 V362 Q339.421 366 335.421 366 H142 Z"><title>nlohmann/json json_document, jeopardy.json: 2.45 GB/s</title></path>
<text class="nj-charts-val" x="343.421" y="364.5">2.45</text>
<path class="nj-charts-c2" d="M142 368 H285.574 Q289.574 368 289.574 372 V373 Q289.574 377 285.574 377 H142 Z"><title>yyjson, jeopardy.json: 1.83 GB/s</title></path>
<text class="nj-charts-val" x="293.574" y="375.5">1.83</text>
<path class="nj-charts-c3" d="M142 379 H304.433 Q308.433 379 308.433 383 V384 Q308.433 388 304.433 388 H142 Z"><title>simdjson D&#8203;OM, jeopardy.json: 2.06 GB/s</title></path>
<text class="nj-charts-val" x="312.433" y="386.5">2.06</text>
<path class="nj-charts-c4" d="M142 390 H286.258 Q290.258 390 290.258 394 V395 Q290.258 399 286.258 399 H142 Z"><title>sonic-rs (Rust), jeopardy.json: 1.84 GB/s</title></path>
<text class="nj-charts-val" x="294.258" y="397.5">1.84</text>
<path class="nj-charts-c5" d="M142 401 H247.737 Q251.737 401 251.737 405 V406 Q251.737 410 247.737 410 H142 Z"><title>sonic-cpp, jeopardy.json: 1.36 GB/s</title></path>
<text class="nj-charts-val" x="255.737" y="408.5">1.36</text>
<path class="nj-charts-c6" d="M142 412 H188.354 Q192.354 412 192.354 416 V417 Q192.354 421 188.354 421 H142 Z"><title>Boost.J&#8203;SON, jeopardy.json: 0.62 GB/s</title></path>
<text class="nj-charts-val" x="196.354" y="419.5">0.62</text>
<path class="nj-charts-c1 nj-charts-dim" d="M142 423 H165.345 Q169.345 423 169.345 427 V428 Q169.345 432 165.345 432 H142 Z"><title>nlohmann/json json::parse, jeopardy.json: 0.34 GB/s</title></path>
<text class="nj-charts-val" x="173.345" y="430.5">0.34</text>
<line class="nj-charts-zero" x1="142" y1="80" x2="142" y2="448"/>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

+39 -10
View File
@@ -104,10 +104,8 @@ def ribbon(body, x0, y, cw, prefix, label=True):
# ---------------------------------------------------------------- figure 1: parse() vs json_document
def layout():
W, H, P = 840, 692, "jvl"
b = markers(P)
# --- panel A: basic_json::parse()
def layout_tree(b, P):
"""panel A: basic_json::parse(), y from 0 to 220"""
b.append(text(16, 26, "basic_json::parse(): a tree, every array, object, and string in its own heap allocation", "nj-jsonview-h"))
b.append(rect(16, 98, 60, 34, "nj-jsonview-box"))
b.append(text(46, 120, "json", "nj-jsonview-mono", anchor="middle"))
@@ -117,7 +115,7 @@ def layout():
rows = [('"port"', "6379", None), ('"price"', "19.9", "double: 19.90 is gone"), ('"tags"', "\u2022", None)]
for i, (k, v, note) in enumerate(rows):
y = 50 + i * 48
b.append(curve(192, 115, 226, y + 17, LINE, P, bend=0))
b.append(line(192, 115, 226, y + 17, LINE, P))
b.append(rect(228, y, 180, 34, "nj-jsonview-heap"))
b.append(text(240, y + 22, k, "nj-jsonview-mono", KEY))
b.append(text(396, y + 22, v, "nj-jsonview-mono", NUM if i < 2 else LINE, anchor="end"))
@@ -132,8 +130,9 @@ def layout():
b.append('<path class="nj-jsonview-sep" d="M624 %g V%g"/>' % (yt - 17, yt + 17))
b.append(text(601, yt + 5, "json", "nj-jsonview-mono", anchor="middle"))
b.append(text(647, yt + 5, "json", "nj-jsonview-mono", anchor="middle"))
b.append(curve(601, yt - 17, 706, 130, LINE, P, bend=-20))
b.append(curve(647, yt + 17, 706, 196, LINE, P, bend=20))
for x1, y1, y2 in ((601, yt - 17, 130), (647, yt + 17, 196)):
b.append('<path class="nj-jsonview-arr nj-jsonview-c-%s" d="M%g %g C%g %g %g %g %g %g" marker-end="url(#%s-%s)"/>'
% (LINE, x1, y1, x1, y2, x1 + 40, y2, 706, y2, P, LINE))
b.append(rect(708, 113, 126, 34, "nj-jsonview-heap"))
b.append(text(771, 135, "std::string eu", "nj-jsonview-mono nj-jsonview-sm", STR, anchor="middle"))
b.append(rect(708, 179, 126, 34, "nj-jsonview-heap"))
@@ -141,9 +140,10 @@ def layout():
# legend
b.append(rect(16, 186, 18, 14, "nj-jsonview-heap", rx=3))
b.append(text(42, 198, "a separate heap allocation", "nj-jsonview-note"))
# --- panel B: json_document::parse()
y0 = 252
b.append('<path class="nj-jsonview-sep" d="M16 %g H824"/>' % (y0 - 18))
def layout_index(b, P, y0):
"""panel B: json_document::parse(), y from y0 - 16 to y0 + 440"""
b.append(text(16, y0 + 10, "json_document::parse(): the source text stays where it is; one flat index of 16-byte nodes", "nj-jsonview-h"))
b.append(text(16, y0 + 38, "source text, 54 bytes (borrowed, or owned by the document)", "nj-jsonview-note"))
cw, rx0, ry = 14, 42, y0 + 48
@@ -185,6 +185,25 @@ def layout():
b.append(curve(vx + 105, vy, n6x, ny + nh, STRUCT, P))
b.append(text(30, ny + nh + 50, "integers are converted while parsing and kept in their node;", "nj-jsonview-note"))
b.append(text(30, ny + nh + 68, "floats and strings point back into the text", "nj-jsonview-note"))
TREE_DESC = ("The text {\"port\": 6379, \"price\": 19.90, \"tags\": [\"eu\", \"a\\\"b\"]} parsed by basic_json::parse(): "
"the root json value points to a std::map whose three nodes are separate heap allocations; the price is stored "
"as the double 19.9; the tags array is a std::vector of two json values, each pointing to its own std::string.")
INDEX_DESC = ("The same text parsed by json_document::parse(): it keeps the 54 bytes of source text and builds a flat index of "
"nine 16-byte nodes in document order: object, key port, unsigned integer 6379 (the converted value is in the "
"node), key price, float, key tags, array, string eu, and an escaped string. Keys, the float, and the plain "
"string point back into the source text; the escaped string points into the document's buffer of decoded "
"strings. A json_view is two pointers: one to the document and one to a node, here the array.")
def layout():
# both panels in one figure (features/json_view.md)
W, H, P = 840, 692, "jvl"
b = markers(P)
layout_tree(b, P)
b.append('<path class="nj-jsonview-sep" d="M16 234 H824"/>')
layout_index(b, P, 252)
write("json_view_layout.svg", W, H, "fig-jvl-title",
"The same J\u200bSON text parsed by basic_json::parse() and by json_document::parse()",
"The text {\"port\": 6379, \"price\": 19.90, \"tags\": [\"eu\", \"a\\\"b\"]}. Top: basic_json::parse() builds a tree: "
@@ -195,6 +214,16 @@ def layout():
"key tags, array, string eu, and an escaped string. Keys, the float, and the plain string point back into the "
"source text; the escaped string points into the document's buffer of decoded strings. A json_view is two "
"pointers: one to the document and one to a node, here the array.", b)
# each panel on its own (home/blog/how_3_13_0_got_faster.md), with their own marker ids
b = markers("jvlt")
layout_tree(b, "jvlt")
write("json_view_layout_tree.svg", W, 222, "fig-jvlt-title",
"A J\u200bSON text parsed by basic_json::parse()", TREE_DESC, b)
b = markers("jvli") + ['<g transform="translate(0 -236)">']
layout_index(b, "jvli", 252)
b.append('</g>')
write("json_view_layout_index.svg", W, H - 236, "fig-jvli-title",
"The same J\u200bSON text parsed by json_document::parse()", INDEX_DESC, b)
# ---------------------------------------------------------------- figure 2: lifetimes
+18 -12
View File
@@ -164,10 +164,10 @@ def overview():
desc.append("%s %s" % (label, fx(v).replace(TIMES, "x")))
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(1), top, X(1), axis_y))
b.append('<line class="nj-charts-zero" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(0), top, X(0), axis_y))
b.append('<text class="nj-charts-note" x="%g" y="%g">speedup over 3.12.0 (the line at 1%s is 3.12.0)</text>' % (L, 18, TIMES))
b.append('<text class="nj-charts-note" x="%g" y="%g">speedup over 3.12.0, more is better (the line at 1%s is 3.12.0)</text>' % (L, 18, TIMES))
write("perf_blog_overview.svg", W, axis_y + 28, "nj-charts--blog", "nj-blog-overview",
"Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang",
"Horizontal bars, longer is faster. " + "; ".join(desc) + ".", b)
"Horizontal bars of the speedup, more is better. " + "; ".join(desc) + ".", b)
# ---------- timeline: one panel per workload ----------
@@ -188,7 +188,7 @@ MONTHS = [("2025-04", "3.12.0"), ("2026-09", "Sep 2026"), ("2026-10", "Oct")]
def timeline():
rows = list(csv.DictReader((HERE / "data" / "perf_timeline.csv").open()))
n = len(rows)
W, H = 340, 252
W, H = 340, 270
L, R, T, B = 44, 330, 62, 208
for col, title, labels in TIMELINE:
vals = [float(r[col]) if r[col] else None for r in rows]
@@ -251,6 +251,7 @@ def timeline():
b.append('<line class="nj-charts-grid" stroke-dasharray="2 2" x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f"/>' % (x, ty + 4, x, y - 5))
b.append('<text class="nj-charts-note" x="%.1f" y="%.1f" text-anchor="middle">%s</text>' % (tx, ty, text))
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, B, R, B))
b.append('<text class="nj-charts-note" x="%g" y="%g">speedup over 3.12.0 (log scale), more is better</text>' % (8, H - 8))
final = rel[-1]
desc = ("%s: speedup over 3.12.0 at each of %d commits, ending at %s. Labeled steps: %s."
% (title, n, fx(final).replace(TIMES, "x"), ", ".join("#%s" % p for p in labels)))
@@ -284,19 +285,24 @@ def cliffs():
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(10 ** e), top - 10, X(10 ** e), axis_y))
lab = {-3: "1 µs", -2: "10 µs", -1: "0.1 ms", 0: "1 ms", 1: "10 ms", 2: "0.1 s", 3: "1 s", 4: "10 s"}[e]
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(10 ** e), axis_y + 16, lab))
b.append('<text class="nj-charts-tick" x="%g" y="%g">runtime (log scale), less is better</text>' % ((L + R) / 2, axis_y + 34))
b.append('<defs><marker id="nj-blog-cliffs-head" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="5" markerHeight="5" '
'orient="auto"><path class="nj-charts-head" d="M0 0 L10 5 L0 10 z"/></marker></defs>')
b.append('<circle class="nj-charts-ojson-dot" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">3.12.0</text>' % (L, L + 10))
b.append('<circle class="nj-charts-json-dot" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">3.13.0</text>' % (L + 80, L + 90))
for i, (op, old, new) in enumerate(CLIFFS):
y = top + i * pitch + 8
b.append('<text class="nj-charts-rowlabel" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 10, y + 4, esc(op)))
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(new), y, X(old), y))
# an arrow from the old time to the new one, ending just before the new dot
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g" marker-end="url(#nj-blog-cliffs-head)"/>'
% (X(old) - 6, y, X(new) + 7, y))
b.append('<circle class="nj-charts-ojson-dot" cx="%g" cy="%g" r="5"><title>%s, 3.12.0: %g ms</title></circle>' % (X(old), y, esc(op), old))
b.append('<circle class="nj-charts-json-dot" cx="%g" cy="%g" r="5"><title>%s, 3.13.0: %g ms</title></circle>' % (X(new), y, esc(op), new))
b.append('<text class="nj-charts-factor" x="%g" y="%g">%s</text>' % ((X(old) + X(new)) / 2, y - 7, fx(old / new)))
desc.append("%s: %g ms to %g ms" % (op, old, new))
write("perf_blog_cliffs.svg", W, axis_y + 28, "nj-charts--blog", "nj-blog-cliffs",
write("perf_blog_cliffs.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-cliffs",
"Operations that grew quadratically or worse: time with 3.12.0 and 3.13.0, log scale",
"Dot plot on a logarithmic time axis. " + "; ".join(desc) + ".", b)
"Dot plot on a logarithmic time axis, less is better; an arrow leads from each 3.12.0 time to the 3.13.0 time. " + "; ".join(desc) + ".", b)
# ---------- json_view: parse throughput ----------
@@ -304,13 +310,13 @@ def cliffs():
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]), fresh documents, from the table in "How it compares"
("json_document", "nj-charts-c1", [183, 364, 943, 22681]),
("nlohmann/json 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]),
("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
@@ -321,7 +327,6 @@ def view():
hi = math.ceil(hi * 2) / 2
X = lambda v: L + v / hi * (R - L)
bh, gap = 9, 2
top = 64
group_h = len(VIEW) * (bh + gap) + 14
b, desc = [], []
x, ly = 8, 10
@@ -332,13 +337,14 @@ def view():
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
top = ly + 34 # below the last row of the legend
axis_y = top + group_h * len(VIEW_FILES)
t = 0.5
while t <= hi + 1e-9:
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), top - 4, X(t), axis_y))
b.append('<text class="nj-charts-tick" x="%g" y="%g">%g</text>' % (X(t), axis_y + 16, t))
t += 0.5
b.append('<text class="nj-charts-tick" x="%g" y="%g">GB/s, longer is faster</text>' % ((L + R) / 2, axis_y + 34))
b.append('<text class="nj-charts-tick" x="%g" y="%g">GB/s, more is better</text>' % ((L + R) / 2, axis_y + 34))
for i, f in enumerate(VIEW_FILES):
y0 = top + i * group_h
b.append('<text class="nj-charts-rowlabel" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 8, y0 + group_h / 2, esc(f)))
@@ -349,8 +355,8 @@ 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 and six other document parsers, fresh documents, Apple M1 Max",
"Grouped horizontal bars in GB/s. " + "; ".join(desc) + ".", b)
"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)
if __name__ == "__main__":