mirror of
https://github.com/nlohmann/json.git
synced 2026-11-04 03:39:22 +00:00
docs: add three figures to the 3.13.0 post
- short strings: two overlapping 16-byte loads and stores - eight digits at a time: the three multiplications, lane by lane - validate on the 19 held-out files, per file, Mac and x86-64 The prose the figures replace is trimmed. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
6 files changed
+3606
-12
No files matched your search
@@ -391,10 +391,14 @@ vst1q_u8(d + n - 16, b); // the two stores overlap too, with the same bytes
|
||||
|
||||
<p class="nj-code-caption" markdown>Writing a string of 16 to 32 bytes with two overlapping loads and stores (NEON).</p>
|
||||
|
||||
Both loads lie inside the string, together they cover all of it, and all tests happen before the first store. Shorter
|
||||
strings use the same trick with two overlapping 8-, 4- or 2-byte loads, so no `memcpy` with a length known only at run
|
||||
time is left. On `twitter.json`,
|
||||
this cut the instructions of `dump()` by 21 %.
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
--8<-- "images/perf_blog_overlap.svg"
|
||||
</div>
|
||||
|
||||
<p class="nj-caption" markdown>The code above on `profile_link_color`, a key of `twitter.json`.</p>
|
||||
|
||||
Shorter strings use the same trick with two overlapping 8-, 4- or 2-byte loads, so no `memcpy` with a length known
|
||||
only at run time is left. On `twitter.json`, this cut the instructions of `dump()` by 21 %.
|
||||
|
||||
### Escapes from a table
|
||||
|
||||
@@ -476,11 +480,14 @@ std::uint32_t parse_eight_digits(std::uint64_t v) noexcept
|
||||
|
||||
<p class="nj-code-caption" markdown>fast_float's conversion of eight ASCII digits to their value, with three multiplications.</p>
|
||||
|
||||
The mask turns the characters into digit values. Multiplying by `10·2⁸ + 1` adds ten times each byte to the byte
|
||||
above it, so after the shift every second byte holds a two-digit number: `"12345678"` becomes 12, 34, 56 and 78. The
|
||||
second step does the same with pairs of bytes and a factor of 100 (1234 and 5678), the third with 32-bit halves and
|
||||
10,000. Whether all eight bytes are digits is one more expression: a digit is 0x30 to 0x39, so its high nibble must be
|
||||
3, and adding 6 must keep it 3. Integers of up to 18 digits and floats of up to 19 then need no overflow check at all.
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
--8<-- "images/perf_blog_digits.svg"
|
||||
</div>
|
||||
|
||||
<p class="nj-caption" markdown>`parse_eight_digits()` on `"12345678"`: multiplying by `10·2⁸ + 1` adds ten times each byte to the byte above it, and the shift and the next mask keep every second lane.</p>
|
||||
|
||||
Whether all eight bytes are digits is one more expression: a digit is 0x30 to 0x39, so its high nibble must be 3, and
|
||||
adding 6 must keep it 3. Integers of up to 18 digits and floats of up to 19 then need no overflow check at all.
|
||||
|
||||
### Clinger's fast path
|
||||
|
||||
@@ -1290,9 +1297,17 @@ The four files are the ones 3.13.0 was tuned on, so we also ran *validate*, *sum
|
||||
other files of simdjson's [`jsonexamples`](https://github.com/simdjson/simdjson-data/tree/master/jsonexamples). By
|
||||
geometric mean, `json_document` stays the fastest in *validate*, *minify* and *write* on every compiler, and in *sum*
|
||||
with Clang and on the Mac; with GCC, simdjson sums in 0.83 to 0.85 of its time. File by file, it is less
|
||||
clear-cut: on x86-64, `json_document` validates only 4 to 8 of the 19 files fastest (13 on the Mac). simdjson wins 5
|
||||
to 8 of the others, and Boost.JSON, without number conversion, validates the number-heavy `mesh.pretty`, `numbers`
|
||||
and `marine_ik` up to 1.5 times as fast. We know two causes, but so far each fix slowed down other files.
|
||||
clear-cut:
|
||||
|
||||
<div class="nj-fig-wrap" markdown>
|
||||
--8<-- "images/perf_blog_heldout.svg"
|
||||
</div>
|
||||
|
||||
<p class="nj-caption" markdown>*validate* on the 19 files: `json_document`'s fastest fully validating way against the fastest library's, per file; 1.0× means it is the fastest. Less is better. The right column names the fastest library on x86-64 (GCC 16.2).</p>
|
||||
|
||||
On x86-64, `json_document` validates only 4 to 8 of the 19 files fastest, against 13 on the Mac. Boost.JSON, without
|
||||
number conversion, validates the number-heavy `mesh.pretty`, `numbers` and `marine_ik` up to 1.5 times as fast. We
|
||||
know two causes, but so far each fix slowed down other files.
|
||||
|
||||
Every *validate* way also ran the 318 files of [JSONTestSuite](https://github.com/nst/JSONTestSuite). The fully
|
||||
validating ways pass, with a few exceptions listed in [Appendix E](#e-comparison-with-other-libraries), one of them
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 600 430" role="img" aria-labelledby="nj-blog-digits nj-blog-digits-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-blog-digits">Converting eight A​SCII digits to their value with three multiplications</title>
|
||||
<desc id="nj-blog-digits-d">The text 12345678 as one word. Masking gives the digit values 1 to 8, one per byte. Multiplying by 10 times 2 to the 8 plus 1 and shifting gives 12, 34, 56 and 78 in 16-bit lanes; multiplying by 100 times 2 to the 16 plus 1 gives 1234 and 5678 in 32-bit lanes; multiplying by 10000 times 2 to the 32 plus 1 gives 12345678.</desc>
|
||||
<text class="fg-h" x="40" y="20">eight A​SCII digits in one 64-bit word (byte 0 is the lowest)</text>
|
||||
<rect class="fg-cell" x="40" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="69" y="53" text-anchor="middle">1</text>
|
||||
<text class="nj-charts-tick" x="69" y="80">0x31</text>
|
||||
<rect class="fg-cell" x="104" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="133" y="53" text-anchor="middle">2</text>
|
||||
<text class="nj-charts-tick" x="133" y="80">0x32</text>
|
||||
<rect class="fg-cell" x="168" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="197" y="53" text-anchor="middle">3</text>
|
||||
<text class="nj-charts-tick" x="197" y="80">0x33</text>
|
||||
<rect class="fg-cell" x="232" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="261" y="53" text-anchor="middle">4</text>
|
||||
<text class="nj-charts-tick" x="261" y="80">0x34</text>
|
||||
<rect class="fg-cell" x="296" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="325" y="53" text-anchor="middle">5</text>
|
||||
<text class="nj-charts-tick" x="325" y="80">0x35</text>
|
||||
<rect class="fg-cell" x="360" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="389" y="53" text-anchor="middle">6</text>
|
||||
<text class="nj-charts-tick" x="389" y="80">0x36</text>
|
||||
<rect class="fg-cell" x="424" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="453" y="53" text-anchor="middle">7</text>
|
||||
<text class="nj-charts-tick" x="453" y="80">0x37</text>
|
||||
<rect class="fg-cell" x="488" y="30" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="517" y="53" text-anchor="middle">8</text>
|
||||
<text class="nj-charts-tick" x="517" y="80">0x38</text>
|
||||
<text class="fg-h" x="40" y="112">& 0x0F0F0F0F0F0F0F0F: one digit value per byte</text>
|
||||
<rect class="fg-cell" x="40" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="69" y="145" text-anchor="middle">1</text>
|
||||
<rect class="fg-cell" x="104" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="133" y="145" text-anchor="middle">2</text>
|
||||
<rect class="fg-cell" x="168" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="197" y="145" text-anchor="middle">3</text>
|
||||
<rect class="fg-cell" x="232" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="261" y="145" text-anchor="middle">4</text>
|
||||
<rect class="fg-cell" x="296" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="325" y="145" text-anchor="middle">5</text>
|
||||
<rect class="fg-cell" x="360" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="389" y="145" text-anchor="middle">6</text>
|
||||
<rect class="fg-cell" x="424" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="453" y="145" text-anchor="middle">7</text>
|
||||
<rect class="fg-cell" x="488" y="122" width="58" height="34" rx="4"/>
|
||||
<text class="fg-code" x="517" y="145" text-anchor="middle">8</text>
|
||||
<text class="fg-h" x="40" y="186">× (10 · 2⁸ + 1) >> 8, every second byte kept: two digits per 16 bits</text>
|
||||
<rect class="fg-cell" x="40" y="196" width="122" height="34" rx="4"/>
|
||||
<text class="fg-code" x="101" y="219" text-anchor="middle">12</text>
|
||||
<rect class="fg-cell" x="168" y="196" width="122" height="34" rx="4"/>
|
||||
<text class="fg-code" x="229" y="219" text-anchor="middle">34</text>
|
||||
<rect class="fg-cell" x="296" y="196" width="122" height="34" rx="4"/>
|
||||
<text class="fg-code" x="357" y="219" text-anchor="middle">56</text>
|
||||
<rect class="fg-cell" x="424" y="196" width="122" height="34" rx="4"/>
|
||||
<text class="fg-code" x="485" y="219" text-anchor="middle">78</text>
|
||||
<text class="fg-h" x="40" y="260">× (100 · 2¹⁶ + 1) >> 16, every second lane kept: four digits per 32 bits</text>
|
||||
<rect class="fg-cell" x="40" y="270" width="250" height="34" rx="4"/>
|
||||
<text class="fg-code" x="165" y="293" text-anchor="middle">1234</text>
|
||||
<rect class="fg-cell" x="296" y="270" width="250" height="34" rx="4"/>
|
||||
<text class="fg-code" x="421" y="293" text-anchor="middle">5678</text>
|
||||
<text class="fg-h" x="40" y="334">× (10000 · 2³² + 1) >> 32: the value</text>
|
||||
<rect class="fg-cell" x="40" y="344" width="506" height="34" rx="4"/>
|
||||
<rect class="nj-charts-c1" fill-opacity=".25" x="40" y="344" width="506" height="34" rx="4"/>
|
||||
<text class="fg-code" x="293" y="367" text-anchor="middle">12345678</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="400">Each step combines neighboring lanes, in all lanes of the word at once:</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="418">three multiplications instead of eight, and no branch.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -0,0 +1,98 @@
|
||||
<svg class="nj-fig nj-charts nj-charts--blog" viewBox="0 0 620 482" role="img" aria-labelledby="nj-blog-heldout nj-blog-heldout-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-blog-heldout">Validating 19 files 3.13.0 was not tuned on: json_document's time relative to the fastest library per file</title>
|
||||
<desc id="nj-blog-heldout-d">Dot plot per file, less is better; 1.0 means json_document is the fastest fully validating library. github_events: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); mesh: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); semanticscholar-corpus: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); twitter_api_compact_response: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); twitter_api_response: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); update-center: Mac 1.00, x86-64 1.00 (nlohmann/json json_document); apache_builds: Mac 1.15, x86-64 1.00 (nlohmann/json json_document); twitter_timeline: Mac 1.04, x86-64 1.02 (yyjson); twitterescaped: Mac 1.10, x86-64 1.08 (simdjson); gsoc-2018: Mac 1.00, x86-64 1.10 (Boost.J​SON); google_maps_api_compact_response: Mac 1.03, x86-64 1.12 (yyjson); tree-pretty: Mac 1.01, x86-64 1.14 (simdjson); repeat: Mac 1.00, x86-64 1.14 (simdjson); random: Mac 1.00, x86-64 1.17 (simdjson); instruments: Mac 1.00, x86-64 1.18 (simdjson); google_maps_api_response: Mac 1.01, x86-64 1.19 (simdjson); marine_ik: Mac 1.00, x86-64 1.23 (Boost.J​SON); numbers: Mac 1.00, x86-64 1.32 (Boost.J​SON); mesh.pretty: Mac 1.00, x86-64 1.49 (Boost.J​SON).</desc>
|
||||
<line class="nj-charts-grid" x1="262" y1="50" x2="262" y2="438"/>
|
||||
<text class="nj-charts-tick" x="262" y="454">1.0×</text>
|
||||
<line class="nj-charts-grid" x1="302.727" y1="50" x2="302.727" y2="438"/>
|
||||
<text class="nj-charts-tick" x="302.727" y="454">1.1×</text>
|
||||
<line class="nj-charts-grid" x1="343.455" y1="50" x2="343.455" y2="438"/>
|
||||
<text class="nj-charts-tick" x="343.455" y="454">1.2×</text>
|
||||
<line class="nj-charts-grid" x1="384.182" y1="50" x2="384.182" y2="438"/>
|
||||
<text class="nj-charts-tick" x="384.182" y="454">1.3×</text>
|
||||
<line class="nj-charts-grid" x1="424.909" y1="50" x2="424.909" y2="438"/>
|
||||
<text class="nj-charts-tick" x="424.909" y="454">1.4×</text>
|
||||
<line class="nj-charts-grid" x1="465.636" y1="50" x2="465.636" y2="438"/>
|
||||
<text class="nj-charts-tick" x="465.636" y="454">1.5×</text>
|
||||
<text class="nj-charts-tick" x="374" y="472">json_document’s time / the fastest library’s, less is better</text>
|
||||
<circle class="nj-charts-json-dot" cx="13" cy="14" r="5"/><text class="nj-charts-leg" x="23" y="18.5">Apple M1 Max</text>
|
||||
<circle class="nj-charts-ojson-dot" cx="134.2" cy="14" r="5"/><text class="nj-charts-leg" x="144.2" y="18.5">x86-64, G​CC 16.2</text>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="48">fastest on x86-64</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="68" text-anchor="end">github_events</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="60.5" r="4.5"><title>github_events, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="67.5" r="4.5"><title>github_events, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="68">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="88" text-anchor="end">mesh</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="80.5" r="4.5"><title>mesh, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="87.5" r="4.5"><title>mesh, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="88">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="108" text-anchor="end">semanticscholar-corpus</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="100.5" r="4.5"><title>semanticscholar-corpus, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="107.5" r="4.5"><title>semanticscholar-corpus, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="108">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="128" text-anchor="end">twitter_api_compact_response</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="120.5" r="4.5"><title>twitter_api_compact_response, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="127.5" r="4.5"><title>twitter_api_compact_response, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="128">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="148" text-anchor="end">twitter_api_response</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="140.5" r="4.5"><title>twitter_api_response, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="147.5" r="4.5"><title>twitter_api_response, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="148">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="168" text-anchor="end">update-center</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="160.5" r="4.5"><title>update-center, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="167.5" r="4.5"><title>update-center, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="168">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="188" text-anchor="end">apache_builds</text>
|
||||
<circle class="nj-charts-json-dot" cx="323.8" cy="180.5" r="4.5"><title>apache_builds, Apple M1 Max: 1.15× the time of simdjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="262.0" cy="187.5" r="4.5"><title>apache_builds, x86-64, G​CC 16.2: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l" x="500" y="188">json_document</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="208" text-anchor="end">twitter_timeline</text>
|
||||
<circle class="nj-charts-json-dot" cx="277.6" cy="200.5" r="4.5"><title>twitter_timeline, Apple M1 Max: 1.04× the time of yyjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="270.8" cy="207.5" r="4.5"><title>twitter_timeline, x86-64, G​CC 16.2: 1.02× the time of yyjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="208">yyjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="228" text-anchor="end">twitterescaped</text>
|
||||
<circle class="nj-charts-json-dot" cx="303.1" cy="220.5" r="4.5"><title>twitterescaped, Apple M1 Max: 1.10× the time of yyjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="293.5" cy="227.5" r="4.5"><title>twitterescaped, x86-64, G​CC 16.2: 1.08× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="228">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="248" text-anchor="end">gsoc-2018</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="240.5" r="4.5"><title>gsoc-2018, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="303.9" cy="247.5" r="4.5"><title>gsoc-2018, x86-64, G​CC 16.2: 1.10× the time of Boost.J​SON</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="248">Boost.J​SON</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="268" text-anchor="end">google_maps_api_compact_response</text>
|
||||
<circle class="nj-charts-json-dot" cx="274.9" cy="260.5" r="4.5"><title>google_maps_api_compact_response, Apple M1 Max: 1.03× the time of yyjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="310.6" cy="267.5" r="4.5"><title>google_maps_api_compact_response, x86-64, G​CC 16.2: 1.12× the time of yyjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="268">yyjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="288" text-anchor="end">tree-pretty</text>
|
||||
<circle class="nj-charts-json-dot" cx="265.6" cy="280.5" r="4.5"><title>tree-pretty, Apple M1 Max: 1.01× the time of simdjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="317.7" cy="287.5" r="4.5"><title>tree-pretty, x86-64, G​CC 16.2: 1.14× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="288">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="308" text-anchor="end">repeat</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="300.5" r="4.5"><title>repeat, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="319.3" cy="307.5" r="4.5"><title>repeat, x86-64, G​CC 16.2: 1.14× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="308">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="328" text-anchor="end">random</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="320.5" r="4.5"><title>random, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="333.3" cy="327.5" r="4.5"><title>random, x86-64, G​CC 16.2: 1.17× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="328">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="348" text-anchor="end">instruments</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="340.5" r="4.5"><title>instruments, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="334.2" cy="347.5" r="4.5"><title>instruments, x86-64, G​CC 16.2: 1.18× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="348">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="368" text-anchor="end">google_maps_api_response</text>
|
||||
<circle class="nj-charts-json-dot" cx="266.3" cy="360.5" r="4.5"><title>google_maps_api_response, Apple M1 Max: 1.01× the time of simdjson</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="341.1" cy="367.5" r="4.5"><title>google_maps_api_response, x86-64, G​CC 16.2: 1.19× the time of simdjson</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="368">simdjson</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="388" text-anchor="end">marine_ik</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="380.5" r="4.5"><title>marine_ik, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="356.9" cy="387.5" r="4.5"><title>marine_ik, x86-64, G​CC 16.2: 1.23× the time of Boost.J​SON</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="388">Boost.J​SON</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="408" text-anchor="end">numbers</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="400.5" r="4.5"><title>numbers, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="393.4" cy="407.5" r="4.5"><title>numbers, x86-64, G​CC 16.2: 1.32× the time of Boost.J​SON</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="408">Boost.J​SON</text>
|
||||
<text class="nj-charts-rowlabel nj-charts-code" x="252" y="428" text-anchor="end">mesh.pretty</text>
|
||||
<circle class="nj-charts-json-dot" cx="262.0" cy="420.5" r="4.5"><title>mesh.pretty, Apple M1 Max: 1.00× the time of the fastest (it is the fastest)</title></circle>
|
||||
<circle class="nj-charts-ojson-dot" cx="461.4" cy="427.5" r="4.5"><title>mesh.pretty, x86-64, G​CC 16.2: 1.49× the time of Boost.J​SON</title></circle>
|
||||
<text class="nj-charts-tick nj-charts-tick--l nj-charts-best" x="500" y="428">Boost.J​SON</text>
|
||||
<line class="nj-charts-ref" x1="262" y1="50" x2="262" y2="438"/>
|
||||
<text class="nj-charts-tick" x="262" y="44">fastest</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,72 @@
|
||||
<svg class="nj-fig nj-charts nj-charts--swar" viewBox="0 0 640 294" role="img" aria-labelledby="nj-blog-overlap nj-blog-overlap-d" xmlns="http://www.w3.org/2000/svg">
|
||||
<title id="nj-blog-overlap">Writing an 18-byte string with two overlapping 16-byte loads and stores</title>
|
||||
<desc id="nj-blog-overlap-d">The 18 bytes of profile_link_color. Load a covers bytes 0 to 15, load b covers bytes 2 to 17, so bytes 2 to 15 are in both. Neither contains a byte that needs escaping, so a is stored at the destination and b 2 bytes later; the second store writes bytes 2 to 15 again with the same values. This works for any length from 16 to 32 bytes without a loop.</desc>
|
||||
<text class="fg-h" x="40" y="20">a string of n = 18 bytes: too long for one 16-byte vector, too short for a loop</text>
|
||||
<rect class="fg-cell" x="40" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="53.5" y="58" text-anchor="middle">p</text>
|
||||
<rect class="fg-cell" x="71" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="84.5" y="58" text-anchor="middle">r</text>
|
||||
<rect class="fg-cell" x="102" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="102" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="115.5" y="58" text-anchor="middle">o</text>
|
||||
<rect class="fg-cell" x="133" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="133" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="146.5" y="58" text-anchor="middle">f</text>
|
||||
<rect class="fg-cell" x="164" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="164" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="177.5" y="58" text-anchor="middle">i</text>
|
||||
<rect class="fg-cell" x="195" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="195" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="208.5" y="58" text-anchor="middle">l</text>
|
||||
<rect class="fg-cell" x="226" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="226" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="239.5" y="58" text-anchor="middle">e</text>
|
||||
<rect class="fg-cell" x="257" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="257" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="270.5" y="58" text-anchor="middle">_</text>
|
||||
<rect class="fg-cell" x="288" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="288" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="301.5" y="58" text-anchor="middle">l</text>
|
||||
<rect class="fg-cell" x="319" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="319" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="332.5" y="58" text-anchor="middle">i</text>
|
||||
<rect class="fg-cell" x="350" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="350" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="363.5" y="58" text-anchor="middle">n</text>
|
||||
<rect class="fg-cell" x="381" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="381" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="394.5" y="58" text-anchor="middle">k</text>
|
||||
<rect class="fg-cell" x="412" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="412" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="425.5" y="58" text-anchor="middle">_</text>
|
||||
<rect class="fg-cell" x="443" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="443" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="456.5" y="58" text-anchor="middle">c</text>
|
||||
<rect class="fg-cell" x="474" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="474" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="487.5" y="58" text-anchor="middle">o</text>
|
||||
<rect class="fg-cell" x="505" y="34" width="27" height="36" rx="4"/>
|
||||
<rect class="nj-charts-c3" fill-opacity=".3" x="505" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="518.5" y="58" text-anchor="middle">l</text>
|
||||
<rect class="fg-cell" x="536" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="549.5" y="58" text-anchor="middle">o</text>
|
||||
<rect class="fg-cell" x="567" y="34" width="27" height="36" rx="4"/>
|
||||
<text class="fg-code" x="580.5" y="58" text-anchor="middle">r</text>
|
||||
<text class="nj-charts-tick" x="53.5" y="86">0</text>
|
||||
<text class="nj-charts-tick" x="115.5" y="86">2</text>
|
||||
<text class="nj-charts-tick" x="518.5" y="86">15</text>
|
||||
<text class="nj-charts-tick" x="580.5" y="86">17</text>
|
||||
<rect class="nj-charts-c1" fill-opacity=".22" x="40" y="100" width="492" height="22" rx="4"/>
|
||||
<rect class="nj-charts-c1" x="40" y="100" width="4" height="22" rx="2"/>
|
||||
<rect class="nj-charts-c1" x="528" y="100" width="4" height="22" rx="2"/>
|
||||
<text class="fg-code" x="286" y="116" text-anchor="middle" style="font-size:14px">a = load 16 bytes at p</text>
|
||||
<rect class="nj-charts-c2" fill-opacity=".22" x="102" y="130" width="492" height="22" rx="4"/>
|
||||
<rect class="nj-charts-c2" x="102" y="130" width="4" height="22" rx="2"/>
|
||||
<rect class="nj-charts-c2" x="590" y="130" width="4" height="22" rx="2"/>
|
||||
<text class="fg-code" x="348" y="146" text-anchor="middle" style="font-size:14px">b = load 16 bytes at p + n − 16</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="182">Both loads lie inside the string, and together they cover all of it; bytes 2 to 15 are in both.</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="204">Test a and b for a quote, a backslash, a control character or 0x7F: none, so write</text>
|
||||
<text class="fg-code" x="40" y="234">store a at d, store b at d + n − 16</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="262">The second store writes bytes 2 to 15 again, with the same values. For any n from 16 to 32:</text>
|
||||
<text class="fg-note fg-note--l" x="40" y="280">two loads, one test, two stores, no loop and no branch on the length.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
File diff suppressed because it is too large.
Load diff
@@ -7,7 +7,11 @@ Generated files:
|
||||
- perf_blog_timeline_<workload>.svg: speedup over 3.12.0 of eight workloads at every develop commit that changed
|
||||
json.hpp or json_view.hpp since 3.12.0, one panel each
|
||||
- perf_blog_swar.svg: the eight-byte string test on one word of input
|
||||
- perf_blog_overlap.svg: writing a short string with two overlapping 16-byte loads and stores
|
||||
- perf_blog_digits.svg: converting eight ASCII digits with three multiplications
|
||||
- perf_blog_cliffs.svg: operations that were quadratic or worse, 3.12.0 against 3.13.0 (log scale)
|
||||
- perf_blog_heldout.svg: validate on the 19 files we didn't tune on, json_document against the fastest library per
|
||||
file (data/perf_heldout_validate.json)
|
||||
- perf_blog_usecases_<platform>.svg: libraries x use cases, time relative to the fastest fully validating library
|
||||
(data/perf_usecases_<platform>.json); perf_blog_tables.py prints the tables of the appendix from the same data
|
||||
|
||||
@@ -43,6 +47,11 @@ def esc(s):
|
||||
return html.escape(s, quote=True).replace("&#", "&#")
|
||||
|
||||
|
||||
def esc_md(s):
|
||||
"""esc() for text with _ or *, which the page's Markdown pass would pair across text elements as emphasis"""
|
||||
return esc(s).replace("_", "_").replace("*", "*")
|
||||
|
||||
|
||||
def write(name, W, H, cls, tid, title, desc, body):
|
||||
s = ['<svg class="nj-fig nj-charts %s" viewBox="0 0 %g %g" role="img" aria-labelledby="%s %s-d" '
|
||||
'xmlns="http://www.w3.org/2000/svg">' % (cls, W, H, tid, tid),
|
||||
@@ -114,6 +123,81 @@ def swar():
|
||||
"at once, then the quote ends the string.", b)
|
||||
|
||||
|
||||
def span(b, x0, x1, y, cls, label):
|
||||
"""a bracket under the cells from x0 to x1, tinted, with a label to its right or inside"""
|
||||
b.append('<rect class="%s" fill-opacity=".22" x="%g" y="%g" width="%g" height="22" rx="4"/>' % (cls, x0, y, x1 - x0))
|
||||
b.append('<rect class="%s" x="%g" y="%g" width="4" height="22" rx="2"/>' % (cls, x0, y))
|
||||
b.append('<rect class="%s" x="%g" y="%g" width="4" height="22" rx="2"/>' % (cls, x1 - 4, y))
|
||||
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle" style="font-size:14px">%s</text>' % ((x0 + x1) / 2, y + 16, label))
|
||||
|
||||
|
||||
# ---------- short strings: two overlapping 16-byte loads ----------
|
||||
def overlap():
|
||||
text = "profile_link_color" # a key of twitter.json, 18 bytes
|
||||
n = len(text)
|
||||
W = 640
|
||||
L, cw, top = 40, 31, 34
|
||||
X = lambda i: L + i * cw
|
||||
b = ['<text class="fg-h" x="%g" y="20">a string of n = %d bytes: too long for one 16-byte vector, too short for a loop</text>' % (L, n)]
|
||||
for i, ch in enumerate(text):
|
||||
both = n - 16 <= i < 16
|
||||
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="36" rx="4"/>' % (X(i), top, cw - 4))
|
||||
if both:
|
||||
b.append('<rect class="nj-charts-c3" fill-opacity=".3" x="%g" y="%g" width="%g" height="36" rx="4"/>' % (X(i), top, cw - 4))
|
||||
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (X(i) + (cw - 4) / 2, top + 24, esc_md(ch)))
|
||||
for i in (0, n - 16, 15, n - 1):
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%d</text>' % (X(i) + (cw - 4) / 2, top + 52, i))
|
||||
y = top + 66
|
||||
span(b, X(0), X(15) + cw - 4, y, "nj-charts-c1", "a = load 16 bytes at p")
|
||||
span(b, X(n - 16), X(n - 1) + cw - 4, y + 30, "nj-charts-c2", "b = load 16 bytes at p + n " + MINUS + " 16")
|
||||
y += 82
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Both loads lie inside the string, and together they cover all of it; bytes %d to 15 are in both.</text>' % (L, y, n - 16))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Test a and b for a quote, a backslash, a control character or 0x7F: none, so write</text>' % (L, y + 22))
|
||||
b.append('<text class="fg-code" x="%g" y="%g">store a at d, store b at d + n %s 16</text>' % (L, y + 52, MINUS))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">The second store writes bytes %d to 15 again, with the same values. For any n from 16 to 32:</text>' % (L, y + 80, n - 16))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">two loads, one test, two stores, no loop and no branch on the length.</text>' % (L, y + 98))
|
||||
write("perf_blog_overlap.svg", W, y + 112, "nj-charts--swar", "nj-blog-overlap",
|
||||
"Writing an 18-byte string with two overlapping 16-byte loads and stores",
|
||||
"The 18 bytes of profile_link_color. Load a covers bytes 0 to 15, load b covers bytes 2 to 17, so bytes 2 to 15 "
|
||||
"are in both. Neither contains a byte that needs escaping, so a is stored at the destination and b 2 bytes "
|
||||
"later; the second store writes bytes 2 to 15 again with the same values. This works for any length from 16 to "
|
||||
"32 bytes without a loop.", b)
|
||||
|
||||
|
||||
# ---------- eight digits at a time: three multiplications ----------
|
||||
def digits():
|
||||
W = 600
|
||||
L, cw, h = 40, 64, 34
|
||||
X = lambda i: L + i * cw
|
||||
steps = [
|
||||
("eight ASCII digits in one 64-bit word (byte 0 is the lowest)", 1, list("12345678"), True),
|
||||
("& 0x0F0F0F0F0F0F0F0F: one digit value per byte", 1, list("12345678"), False),
|
||||
("× (10 · 2⁸ + 1) >> 8, every second byte kept: two digits per 16 bits", 2, ["12", "34", "56", "78"], False),
|
||||
("× (100 · 2¹⁶ + 1) >> 16, every second lane kept: four digits per 32 bits", 4, ["1234", "5678"], False),
|
||||
("× (10000 · 2³² + 1) >> 32: the value", 8, ["12345678"], False),
|
||||
]
|
||||
b = []
|
||||
y = 20
|
||||
for k, (head, width, cells, ascii_) in enumerate(steps):
|
||||
b.append('<text class="fg-h" x="%g" y="%g">%s</text>' % (L, y, esc(head)))
|
||||
for j, c in enumerate(cells):
|
||||
x = X(j * width)
|
||||
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="%g" rx="4"/>' % (x, y + 10, width * cw - 6, h))
|
||||
if k == len(steps) - 1:
|
||||
b.append('<rect class="nj-charts-c1" fill-opacity=".25" x="%g" y="%g" width="%g" height="%g" rx="4"/>' % (x, y + 10, width * cw - 6, h))
|
||||
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (x + (width * cw - 6) / 2, y + 10 + 23, esc(c)))
|
||||
if ascii_:
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">0x%02X</text>' % (x + (width * cw - 6) / 2, y + h + 26, ord(c)))
|
||||
y += h + (58 if ascii_ else 40)
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">Each step combines neighboring lanes, in all lanes of the word at once:</text>' % (L, y - 8))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">three multiplications instead of eight, and no branch.</text>' % (L, y + 10))
|
||||
write("perf_blog_digits.svg", W, y + 22, "nj-charts--swar", "nj-blog-digits",
|
||||
"Converting eight ASCII digits to their value with three multiplications",
|
||||
"The text 12345678 as one word. Masking gives the digit values 1 to 8, one per byte. Multiplying by 10 times 2 to "
|
||||
"the 8 plus 1 and shifting gives 12, 34, 56 and 78 in 16-bit lanes; multiplying by 100 times 2 to the 16 plus 1 "
|
||||
"gives 1234 and 5678 in 32-bit lanes; multiplying by 10000 times 2 to the 32 plus 1 gives 12345678.", b)
|
||||
|
||||
|
||||
# ---------- overview: speedup per workload (Google Benchmark rows, 3.12.0 time / 3.13.0 time) ----------
|
||||
# (group, label, speedup), copied from the table "The short version"
|
||||
OVERVIEW = [
|
||||
@@ -355,6 +439,60 @@ def cliffs():
|
||||
"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)
|
||||
|
||||
|
||||
# ---------- validating the files we didn't tune on, file by file ----------
|
||||
# data/perf_heldout_validate.json: per platform, file and library the fastest fully validating way of the validate
|
||||
# use case on the 19 other files of simdjson's jsonexamples (reused parsers not chosen), extracted from
|
||||
# summarize.py --json of the held-out run
|
||||
HELDOUT = [("mac", "Apple M1 Max", "nj-charts-json-dot"), ("x86-gcc", "x86-64, GCC 16.2", "nj-charts-ojson-dot")]
|
||||
|
||||
|
||||
def heldout():
|
||||
data = json.load((HERE / "data" / "perf_heldout_validate.json").open())
|
||||
files = sorted(data["mac"])
|
||||
rel, winner = {}, {}
|
||||
for plat, _, _ in HELDOUT:
|
||||
for f in files:
|
||||
libs = data[plat][f]
|
||||
best = min(libs, key=lambda l: libs[l]["us"])
|
||||
rel[plat, f] = libs["nlohmann json_document"]["us"] / libs[best]["us"]
|
||||
winner[plat, f] = UC_LIBS.get(best, best)
|
||||
files.sort(key=lambda f: (rel["x86-gcc", f], rel["mac", f]))
|
||||
W, L, R = 620, 262, 486
|
||||
lo, hi = 1.0, 1.55
|
||||
X = lambda r: L + (r - lo) / (hi - lo) * (R - L)
|
||||
top, pitch = 58, 20
|
||||
axis_y = top + pitch * len(files)
|
||||
b, desc = [], []
|
||||
for t in (1.0, 1.1, 1.2, 1.3, 1.4, 1.5):
|
||||
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), top - 8, X(t), axis_y))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%.1f%s</text>' % (X(t), axis_y + 16, t, TIMES))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">json_document’s time / the fastest library’s, less is better</text>' % ((L + R) / 2, axis_y + 34))
|
||||
x = 8
|
||||
for plat, name, cls in HELDOUT:
|
||||
b.append('<circle class="%s" cx="%g" cy="14" r="5"/><text class="nj-charts-leg" x="%g" y="18.5">%s</text>' % (cls, x + 5, x + 15, esc_md(name)))
|
||||
x += 30 + 7.6 * len(name)
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="%g" y="%g">fastest on x86-64</text>' % (R + 14, top - 10))
|
||||
for i, f in enumerate(files):
|
||||
y = top + i * pitch + 6
|
||||
b.append('<text class="nj-charts-rowlabel nj-charts-code" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 10, y + 4, esc_md(f)))
|
||||
for k, (plat, name, cls) in enumerate(HELDOUT):
|
||||
r = rel[plat, f]
|
||||
b.append('<circle class="%s" cx="%.1f" cy="%g" r="4.5"><title>%s, %s: %.2f%s the time of %s</title></circle>'
|
||||
% (cls, X(min(r, hi)), y - 3.5 + 7 * k, esc_md(f), esc_md(name), r, TIMES, esc_md(winner[plat, f]) if r > 1.0005 else "the fastest (it is the fastest)"))
|
||||
w = winner["x86-gcc", f]
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--l%s" x="%g" y="%g">%s</text>'
|
||||
% ("" if w.startswith("nlohmann") else " nj-charts-best", R + 14, y + 4, esc_md("json_document" if w.startswith("nlohmann") else w)))
|
||||
desc.append("%s: Mac %.2f, x86-64 %.2f (%s)" % (f, rel["mac", f], rel["x86-gcc", f], w))
|
||||
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(1), top - 8, X(1), axis_y))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">fastest</text>' % (X(1), top - 14))
|
||||
wins = {p: sum(rel[p, f] < 1.0005 for f in files) for p, _, _ in HELDOUT}
|
||||
print("heldout: json_document fastest on %s" % wins)
|
||||
write("perf_blog_heldout.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-heldout",
|
||||
"Validating 19 files 3.13.0 was not tuned on: json_document's time relative to the fastest library per file",
|
||||
"Dot plot per file, less is better; 1.0 means json_document is the fastest fully validating library. "
|
||||
+ "; ".join(desc) + ".", b)
|
||||
|
||||
|
||||
# ---------- the price: compile time of two programs against 3.12.0 ----------
|
||||
# CPU time of the compiler in ms, median of 9 interleaved rounds, C++20, M1 Max (the post's appendix G)
|
||||
# (3.12.0, 3.13.0, 3.13.0 with a precompiled header, 3.13.0 as a module)
|
||||
@@ -628,6 +766,9 @@ def heatmap(platform, title):
|
||||
|
||||
if __name__ == "__main__":
|
||||
swar()
|
||||
overlap()
|
||||
digits()
|
||||
heldout()
|
||||
if OVERVIEW:
|
||||
overview()
|
||||
distribution()
|
||||
|
||||
Reference in new issue
Block a user