docs: add the blog post "How nlohmann/json 3.13.0 got 3× faster" (#6022)
* docs: add the blog post "How 3.13.0 got faster" A post for the documentation (Home > Blog) on how 3.13.0 became faster: eight themes with the pull requests behind them, the ideas taken from other libraries, what did not work, how the fast paths are tested, and the compile-time cost. Every number comes from a run on 2026-10-27 (3.12.0 against develop plus the open non-draft PRs, Apple M1 Max) or from the linked PR. - docs/mkdocs/docs/home/blog/how_3_13_0_got_faster.md: the post. - docs/mkdocs/scripts/figures/perf_blog.py: draws its 12 figures (overview, eight timeline panels, the SWAR test, the cliffs, json_view throughput) as inline SVGs in the nj-charts style; data/perf_timeline.csv holds the timeline. - tests/benchmarks/history: history.cpp and history.py time one fixed program against the header of every commit that changed it, interleaved, and write one CSV row per commit with its PR. The timeline of the post comes from it. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: compare json_document with Glaze, sonic, RapidJSON and Rust parsers Extends the comparison in "How 3.13.0 got faster" from yyjson, simdjson and Boost.JSON to eleven engines: sonic-cpp, RapidJSON and Glaze (generic DOM, lazy_json, reading into structs) in C++, sonic-rs, simd-json and serde_json in Rust. Measured on an Apple M1 Max (Apple clang 21, Rust 1.99) and an x86-64 Haswell server (GCC 13, Clang 18). Every engine must return the same values, string bytes and bit-identical number sums before it is timed. The post now answers whether json_document is the fastest parser: it is the fastest document parser at parse+dump everywhere and at parsing on Apple silicon, ties with simdjson's DOM on x86-64, and loses to simdjson On-Demand and Glaze structs when only a few fields are read. tests/benchmarks/json_view/others holds the programs (bench_all.cpp, the Rust crate with its Cargo.lock), summarize.py and the pinned versions and checksums. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * 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> * docs: byline and licenses for the 3.13.0 post - author and date below the title, styled as .nj-byline; its link gets no external-link icon - the license of every library in the thanks section, checked against each project's license files; credit sonic-rs for QUOTE_TAB, which orjson adapted from it Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: dump comparison and split acknowledgments in the 3.13.0 post - a dump workload in bench_all and bench_rs: each engine writes a document parsed beforehand, and every output must read back with bit-identical numbers; an optional argument selects one workload - the post's comparison gains a write table, a throughput chart, a dump row for all three configurations, and the x86-64 cases it loses - the thanks section is split into adapted code and borrowed ideas Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: x86-64 dump numbers with #5908's branch-free token digits The dump of canada.json with GCC on x86-64 lost to yyjson by 0.78 because GCC compiled #5908's token-digit selections as branches;9fad526888fixed that. The post's x86-64 dump and parse+dump rows of canada.json are now measured with it (GCC 0.95, Clang 0.91 against yyjson), theme 5 tells the story, and "How we measured" says which rows include the commit. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Compare JSON libraries by use case in the json_view harness bench_all and bench_rs now time use cases (validate, sum, select, edit, minify, write) instead of library functions. Every library may solve a use case in every way it offers; each variant's result is checked, and three malformed inputs give its validation level (full, no UTF-8, partial). summarize.py reports each library's fastest fully validating variant and a faster one at a lower level, as text and as JSON. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: restructure the 3.13.0 post around themes and use cases - deeper technical detail and code in the eight themes; pull request numbers move to the appendix, timeline steps are labelled by theme - comparison with other libraries by use case, as heatmaps per platform, with validation levels and the caveats next to the results - appendix: test files, all 182 suite rows with a histogram, timeline steps, algorithmic fixes, per-file tables, behaviour changes, setup, pull requests by theme Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Measure each library's fastest modes in the json_view harness Address the points of a review from the other libraries' side: - simdjson 5.0.8 (On-Demand structs, key selectors) and Glaze 9.1.0 - number-skipping modes: yyjson and RapidJSON raw numbers, Boost.JSON number_precision::none - reused parsers and allocators for yyjson, RapidJSON and Boost.JSON - Boost.JSON parse_into, Glaze generic with double numbers, and the same struct types for nlohmann, Glaze, simdjson and serde - minified copies of twitter.json and citm_catalog.json - a fourth probe (trailing garbage) and Glaze "(strict)" variants - a new random variant order in every round, as a variant's time could depend on the one before it by up to 15 % on the Mac - --files for other test files and --conformance for JSONTestSuite, with conformance-rs.sh for the Rust program summarize.py also reports each library's best reused variant. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: rerun the library comparison of the 3.13.0 post with fairer rules The figures and Appendix E use the reruns with each library's fastest modes. Skipping number conversion while reading is now allowed for every library; copying number text is still not chosen when writing. The text now says who set the rules, where libraries that check less win select, how minified files change the picture, and that the reused jeopardy.json claim holds with every library reused. A new section covers 19 held-out files and JSONTestSuite, including where json_document loses, and lists what was not measured. Every comparison number was recomputed; Glaze is credited in the intro. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: measure the 3.13.0 post against develop with #5964 and #5908 The suite (Appendix B, the short-version table, the overview and distribution figures) and the timeline endpoint now measure developd20c4dcd89with #5964 and #5908 merged. The geometric mean stays 2.9x (2.95); Dump/signed_ints and Dump/unsigned_ints gain 1.5x and 2.1x from #5964; GetVectorDouble/floats drops from 10.3x to 7.0x because the old candidate's suite binary happened to compile that loop faster (a standalone build takes 0.97 ms with both headers). The timeline endpoint is the 10-27 value scaled by the ratio of the new to the old candidate, both measured on 10-30, so that it stays comparable with the other points of the timeline. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * 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> * docs: measure the 3.13.0 post against develop with all open pull requests The baseline is now develop9c349b1d7cwith every open non-draft pull request merged, including #5968, #5970, #5971, #5975, #5976, #5978, #5979, #5980, #5981 and #5982. The suite was rerun on 11-01 with every step repeated when the load rose above 5 while it ran; the comparison with other libraries and the held-out files were rerun on 10-31. - suite: 3.0x geometric mean (median 2.9x); Appendix B, the overview and the distribution regenerated - timeline endpoint, Appendix D and the cliffs figure updated - the held-out figure compares json_document with the fastest other library - new paragraphs for the pull requests listed above Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: measure the 3.13.0 post against develop with the open pull requests of 11-02 Suite, timeline endpoint, Appendix D and the scalar-run numbers now come from developb2674a4a2fwith #5990, #5991, #5992, #5996, #5997, #5998, #5999 and #6000 merged. The scalar runs are measured against a build without them on develop's code, which no longer checks for a scalar before entering the loop. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: measure the 3.13.0 post against develop with all open pull requests of 11-02 Suite, timeline endpoint, Appendix D and the scalar-run numbers now come from developb2674a4a2fwith #5990-#5992, #5996-#6006 and #6008 merged. With #6008, arrays of one element skip the scalar run, so nested arrays no longer pay for it. The suite ran three rounds per version; the round of 3.12.0 and of 3.13.0 that differed from the other two was dropped, as the setup table says. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: fix the facts the review of the 3.13.0 post found wrong or imprecise Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: re-measure the 3.13.0 post and apply the review Measure everything again against develop with the open pull requests of 11-03 (suite, timeline, comparison on the Mac and on x86-64, compile times, stream gap), add the suite on an Intel MacBook Pro as a check, mark the ways that keep number text as "N" in the use-case charts, move the loop-shape box to theme 5, and apply the style and wording fixes of the review. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: make the comparison of the 3.13.0 post fairer Three reviews of "How it compares" (a maintainer audit of the harness, a methodology review, a reader's red team) led to a full rerun on the Mac and x86-64 with simdjson 5.1.1 and new ways in the harness: - in-place parses with the copy made before the timer ("(copy untimed)", never chosen as a library's best) and json_document::parse_copy(); - RapidJSON through StringStream, and with default precision in validate, which reads no number; - BENCH_ONLY takes several prefixes. The post now gives the copy's real cost (11-14 us for twitter.json on the Mac, not 30), what yyjson gains without it, the run-to-run noise, the LTO check, the single-file losses that were missing, and qualifies the headline claim. Every number in the section and Appendix E is recomputed; the NUL-byte remark moved out of the body. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Format bench_all.cpp with astyle The amalgamation check runs astyle over tests/ and failed on bench_all.cpp. The variant tables keep one variant per line between *INDENT-OFF* and *INDENT-ON*; astyle formats the rest, and the list of use cases becomes a named array so the loop header stays on one line. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Print the history benchmark's results with a stream Flawfinder flagged the printf in history.cpp (CWE-134), although its format string is a constant. The stream prints the same text, so history.py reads it as before. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: address review comments on the performance blog post - fix wording: "are new", "for each input source", "the strings", "the last zero to seven bytes", "by" Danila Kutenin, "the result of that query" - introduce `json_document` where it first gets a detail, say that the `-mbranches` flag is not used, explain why the position and token bookkeeping overloads are empty, and say that a step's percentage is relative to the time before the step and that a median of 4 is the mean of the two middle values - write percentages without a space before `%` in the post and in the price figure (regenerated) Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: wrap the prose of the performance blog post at 120 columns Only line breaks change: the rendered page is identical after whitespace normalization. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: blog post: address the second round of review comments Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: blog post: note that Boost.JSON's tree lead comes from its arena The comparison builds Boost.JSON's tree in a monotonic_resource. With its default allocator and precise numbers, boost::json::parse() takes as long as json::parse() on twitter.json, 5% longer on citm_catalog.json and 17% less time on canada.json (M1, C++23 -O3, best of 3 x 30 runs; the arena saves Boost.JSON 28-41%). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: blog post: comparing already passes the depth; copying measured slower without the counter operator== walks the standard containers itself and passes the depth as an argument (#5840). A copy that does the same, inserting element by element, measured 4-16% slower on an M1 Max with Apple clang, so copying keeps the thread_local counter. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * docs: blog post: name every user of the depth counter and every input the document copies The "Bounded recursion" paragraph said only copying and equality for custom containers use the thread_local counter. Converting from another basic_json specialization and the ordering comparisons use it too; equality for the standard containers passes the depth instead. The "Strings stay in the input" bullet named only parse_copy() and an rvalue std::string as owning inputs. Streams, FILE* and other input that is not one contiguous block of bytes are read into an owned buffer as well. Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
6343775000
commit
2c7474affc
51 files changed
+73792
-18
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,183 @@
|
||||
benchmark,unit,3.12.0,3.13.0,speedup
|
||||
Accept/canada,ns,1.29488e+07,2.3494e+06,5.512
|
||||
Accept/citm_catalog,ns,6.53091e+06,923408,7.073
|
||||
Accept/floats,ns,1.15702e+08,2.26771e+07,5.102
|
||||
Accept/jeopardy,ns,2.20758e+08,5.92935e+07,3.723
|
||||
Accept/signed_ints,ns,1.17358e+08,2.82947e+07,4.148
|
||||
Accept/small_signed_ints,ns,5.75113e+07,1.80352e+07,3.189
|
||||
Accept/twitter,ns,2.51345e+06,483792,5.195
|
||||
Accept/unsigned_ints,ns,1.16297e+08,2.97181e+07,3.913
|
||||
BinaryToCbor/1024,ns,298.444,107.095,2.787
|
||||
BinaryToCbor/128,ns,248.661,116.711,2.131
|
||||
BinaryToCbor/16,ns,244.687,49.6325,4.930
|
||||
BinaryToCbor/16384,ns,952.115,413.62,2.302
|
||||
BinaryToCbor/2048,ns,328.419,125.183,2.624
|
||||
BinaryToCbor/256,ns,264.678,90.8937,2.912
|
||||
BinaryToCbor/32,ns,251.632,50.4059,4.992
|
||||
BinaryToCbor/32768,ns,1541.05,802.721,1.920
|
||||
BinaryToCbor/4096,ns,406.957,177.412,2.294
|
||||
BinaryToCbor/512,ns,289.876,102.063,2.840
|
||||
BinaryToCbor/64,ns,254.928,84.6434,3.012
|
||||
BinaryToCbor/8,ns,247.618,49.3761,5.015
|
||||
BinaryToCbor/8192,ns,514.281,256.456,2.005
|
||||
Copy/canada,ns,3.78116e+06,2.92734e+06,1.292
|
||||
Copy/citm_catalog,ns,1.7026e+06,1.51108e+06,1.127
|
||||
Copy/twitter,ns,840201,767400,1.095
|
||||
CopyAssign/canada,ns,3.86416e+06,2.94449e+06,1.312
|
||||
CopyAssign/citm_catalog,ns,1.76529e+06,1.58608e+06,1.113
|
||||
CopyAssign/twitter,ns,884985,790724,1.119
|
||||
CopyOnly/canada,ns,1.60229e+06,1.57507e+06,1.017
|
||||
CopyOnly/citm_catalog,ns,786244,817481,0.962
|
||||
CopyOnly/twitter,ns,423631,420649,1.007
|
||||
CopyRing/canada,ns,3.86433e+06,2.99657e+06,1.290
|
||||
CopyRing/citm_catalog,ns,1.84434e+06,1.60579e+06,1.149
|
||||
CopyRing/twitter,ns,951510,818035,1.163
|
||||
DestroyOnly/canada,ns,2.22138e+06,1.40157e+06,1.585
|
||||
DestroyOnly/citm_catalog,ns,926244,711471,1.302
|
||||
DestroyOnly/twitter,ns,416055,336082,1.238
|
||||
Diff/canada,ns,3.98055e+07,3.80466e+06,10.462
|
||||
Diff/citm_catalog,ns,7.1859e+06,1.12351e+06,6.396
|
||||
Diff/twitter,ns,5.11261e+06,661062,7.734
|
||||
Dump/canada / -,ns,6.95189e+06,2.33647e+06,2.975
|
||||
Dump/canada / 4,ns,9.09882e+06,3.10291e+06,2.932
|
||||
Dump/citm_catalog / -,ns,1.42117e+06,295678,4.806
|
||||
Dump/citm_catalog / 4,ns,1.98589e+06,422600,4.699
|
||||
Dump/floats / -,ns,6.4332e+07,2.37747e+07,2.706
|
||||
Dump/floats / 4,ns,7.25695e+07,2.46207e+07,2.947
|
||||
Dump/jeopardy / -,ns,2.06771e+08,3.17494e+07,6.513
|
||||
Dump/jeopardy / 4,ns,2.27967e+08,3.53626e+07,6.447
|
||||
Dump/signed_ints / -,ns,2.40551e+07,1.0736e+07,2.241
|
||||
Dump/signed_ints / 4,ns,3.25192e+07,1.1333e+07,2.869
|
||||
Dump/small_signed_ints / -,ns,1.81398e+07,8.12457e+06,2.233
|
||||
Dump/small_signed_ints / 4,ns,2.55296e+07,8.80796e+06,2.898
|
||||
Dump/twitter / -,ns,1.43584e+06,214252,6.702
|
||||
Dump/twitter / 4,ns,1.63183e+06,253042,6.449
|
||||
Dump/unsigned_ints / -,ns,2.39512e+07,8.11916e+06,2.950
|
||||
Dump/unsigned_ints / 4,ns,3.22761e+07,8.58925e+06,3.758
|
||||
Equal/canada,ns,473767,349284,1.356
|
||||
Equal/citm_catalog,ns,279548,263329,1.062
|
||||
Equal/twitter,ns,145555,131450,1.107
|
||||
Flatten/canada,ns,2.94475e+07,1.11184e+07,2.649
|
||||
Flatten/citm_catalog,ns,6.7155e+06,3.07325e+06,2.185
|
||||
Flatten/twitter,ns,3.66077e+06,2.10599e+06,1.738
|
||||
FlattenOrdered/citm_catalog,ns,2.62026e+08,1.42645e+06,183.691
|
||||
FlattenOrdered/twitter,ns,5.1275e+07,890275,57.595
|
||||
FromBinaryBuffer/bjdata / canada,ns,8.81972e+06,4.16727e+06,2.116
|
||||
FromBinaryBuffer/bjdata / twitter,ns,3.32045e+06,976266,3.401
|
||||
FromBinaryBuffer/bjdata_optimized / canada,ns,9.2386e+06,2.47996e+06,3.725
|
||||
FromBinaryBuffer/bjdata_optimized / twitter,ns,3.30526e+06,985625,3.353
|
||||
FromBinaryBuffer/bson / canada,ns,1.00372e+07,4.31554e+06,2.326
|
||||
FromBinaryBuffer/bson / citm_catalog,ns,4.07611e+06,1.60647e+06,2.537
|
||||
FromBinaryBuffer/bson / twitter,ns,3.25635e+06,936933,3.476
|
||||
FromBinaryBuffer/cbor / canada,ns,8.89562e+06,2.11517e+06,4.206
|
||||
FromBinaryBuffer/cbor / citm_catalog,ns,3.94234e+06,1.45242e+06,2.714
|
||||
FromBinaryBuffer/cbor / floats,ns,3.0473e+07,5.47969e+06,5.561
|
||||
FromBinaryBuffer/cbor / jeopardy,ns,3.73185e+08,1.14934e+08,3.247
|
||||
FromBinaryBuffer/cbor / signed_ints,ns,3.66673e+07,9.88892e+06,3.708
|
||||
FromBinaryBuffer/cbor / twitter,ns,3.23196e+06,953415,3.390
|
||||
FromBinaryBuffer/msgpack / canada,ns,8.85983e+06,2.12215e+06,4.175
|
||||
FromBinaryBuffer/msgpack / citm_catalog,ns,3.84901e+06,1.4503e+06,2.654
|
||||
FromBinaryBuffer/msgpack / jeopardy,ns,3.73143e+08,1.11034e+08,3.361
|
||||
FromBinaryBuffer/msgpack / twitter,ns,3.2397e+06,954811,3.393
|
||||
FromBinaryBuffer/ubjson / canada,ns,8.84059e+06,4.20402e+06,2.103
|
||||
FromBinaryBuffer/ubjson / citm_catalog,ns,4.0708e+06,1.78566e+06,2.280
|
||||
FromBinaryBuffer/ubjson / jeopardy,ns,3.79093e+08,1.17024e+08,3.239
|
||||
FromBinaryBuffer/ubjson / twitter,ns,3.29948e+06,981057,3.363
|
||||
FromBinaryBuffer/ubjson_optimized / canada,ns,8.88909e+06,2.42788e+06,3.661
|
||||
FromBinaryBuffer/ubjson_optimized / twitter,ns,3.29784e+06,974810,3.383
|
||||
FromBinaryFile/bjdata / twitter,ns,1.09208e+07,1.94678e+06,5.610
|
||||
FromBinaryFile/bson / twitter,ns,1.07209e+07,1.84971e+06,5.796
|
||||
FromBinaryFile/cbor / canada,ns,1.49218e+07,4.48832e+06,3.325
|
||||
FromBinaryFile/cbor / twitter,ns,1.03718e+07,1.57388e+06,6.590
|
||||
FromBinaryFile/ubjson / canada,ns,1.43414e+07,6.42996e+06,2.230
|
||||
FromBinaryFile/ubjson / twitter,ns,1.09266e+07,1.97275e+06,5.539
|
||||
FromBinaryShape/containers / bjdata,ns,1.46977e+07,7.23447e+06,2.032
|
||||
FromBinaryShape/containers / bson,ns,1.75596e+07,7.88867e+06,2.226
|
||||
FromBinaryShape/containers / cbor,ns,1.46488e+07,4.15792e+06,3.523
|
||||
FromBinaryShape/containers / msgpack,ns,1.45853e+07,3.89266e+06,3.747
|
||||
FromBinaryShape/containers / ubjson,ns,1.49773e+07,7.23987e+06,2.069
|
||||
FromBinaryShape/containers / ubjson_optimized,ns,1.54989e+07,4.55976e+06,3.399
|
||||
FromBinaryShape/nested / bjdata,ns,96825.9,38335.1,2.526
|
||||
FromBinaryShape/nested / bson,ns,101356,42620.2,2.378
|
||||
FromBinaryShape/nested / cbor,ns,94929.8,35845.6,2.648
|
||||
FromBinaryShape/nested / msgpack,ns,92610.2,35078.3,2.640
|
||||
FromBinaryShape/nested / ubjson,ns,96090.6,38285.6,2.510
|
||||
FromBinaryShape/scalars / bjdata,ns,2.52616e+07,1.15856e+07,2.180
|
||||
FromBinaryShape/scalars / cbor,ns,2.62118e+07,5.88743e+06,4.452
|
||||
FromBinaryShape/scalars / msgpack,ns,2.50706e+07,5.65159e+06,4.436
|
||||
FromBinaryShape/scalars / ubjson,ns,2.53402e+07,1.16191e+07,2.181
|
||||
FromCborChunkedString/10000 chunks,ns,91845.9,82875.5,1.108
|
||||
FromMsgpack/canada,ns,1.48853e+07,4.56225e+06,3.263
|
||||
FromMsgpack/citm_catalog,ns,9.3559e+06,2.26246e+06,4.135
|
||||
FromMsgpack/floats,ns,6.12575e+07,2.86709e+07,2.137
|
||||
FromMsgpack/jeopardy,ns,1.16767e+09,1.90153e+08,6.141
|
||||
FromMsgpack/signed_ints,ns,6.38812e+07,3.28867e+07,1.942
|
||||
FromMsgpack/small_signed_ints,ns,6.44688e+07,3.44227e+07,1.873
|
||||
FromMsgpack/twitter,ns,1.02787e+07,1.48541e+06,6.920
|
||||
FromMsgpack/unsigned_ints,ns,5.7784e+07,2.83078e+07,2.041
|
||||
"GetArray<std::array<int, 1000>>",ns,2274.63,654.431,3.476
|
||||
GetArray<std::deque<int>>,ns,8288.3,1175.75,7.049
|
||||
GetArray<std::set<int>>,ns,60017.4,42504.9,1.412
|
||||
GetArray<std::vector<int>>,ns,6785.73,681.915,9.951
|
||||
GetMap/citm_catalog,ns,3.60313e+06,2.48546e+06,1.450
|
||||
GetVectorDouble/floats,ns,6.83612e+06,656162,10.418
|
||||
GetVectorInt/signed_ints,ns,8.22365e+06,3.46495e+06,2.373
|
||||
Iterate/canada,ns,897083,328035,2.735
|
||||
Iterate/citm_catalog,ns,305421,171245,1.784
|
||||
Iterate/twitter,ns,89996.6,61975.8,1.452
|
||||
JsonPointerAt/citm_catalog,ns,1.89898e+06,1.17751e+06,1.613
|
||||
JsonPointerAt/twitter,ns,817946,611519,1.338
|
||||
JsonPointerContains/citm_catalog,ns,2.8177e+06,1.26796e+06,2.222
|
||||
JsonPointerContains/twitter,ns,1.33508e+06,628630,2.124
|
||||
JsonPointerParse/citm_catalog,ns,5.81355e+06,2.24831e+06,2.586
|
||||
JsonPointerParse/twitter,ns,2.47971e+06,1.02159e+06,2.427
|
||||
JsonPointerToString/citm_catalog,ns,6.7858e+06,1.93924e+06,3.499
|
||||
JsonPointerToString/twitter,ns,2.23096e+06,834416,2.674
|
||||
ParseFILE/canada,ns,5.41907e+07,1.46942e+07,3.688
|
||||
ParseFILE/citm_catalog,ns,3.59542e+07,7.58092e+06,4.743
|
||||
ParseFILE/twitter,ns,1.4087e+07,3.44991e+06,4.083
|
||||
ParseFile/canada,ns,1.82792e+07,6.46954e+06,2.825
|
||||
ParseFile/citm_catalog,ns,8.12979e+06,2.52336e+06,3.222
|
||||
ParseFile/floats,ns,1.31229e+08,4.81407e+07,2.726
|
||||
ParseFile/jeopardy,ns,3.38017e+08,1.62098e+08,2.085
|
||||
ParseFile/signed_ints,ns,1.28749e+08,4.62304e+07,2.785
|
||||
ParseFile/small_signed_ints,ns,6.47398e+07,3.34103e+07,1.938
|
||||
ParseFile/twitter,ns,3.43041e+06,1.37495e+06,2.495
|
||||
ParseFile/unsigned_ints,ns,1.24001e+08,4.74365e+07,2.614
|
||||
ParseIndented/canada / 4,ns,3.4977e+07,5.37149e+06,6.512
|
||||
ParseIndented/citm_catalog / 4,ns,7.52423e+06,1.81376e+06,4.148
|
||||
ParseIndented/jeopardy / 4,ns,3.45046e+08,1.33383e+08,2.587
|
||||
ParseIndented/twitter / 4,ns,3.72283e+06,1.12645e+06,3.305
|
||||
ParseStreamValues/ndjson,ns,7.15876e+06,3.76965e+06,1.899
|
||||
ParseStreamValues/numbers,ns,1.92619e+06,383138,5.027
|
||||
ParseString/canada,ns,1.55213e+07,4.62776e+06,3.354
|
||||
ParseString/citm_catalog,ns,7.56417e+06,1.77967e+06,4.250
|
||||
ParseString/floats,ns,1.21779e+08,2.83035e+07,4.303
|
||||
ParseString/jeopardy,ns,3.16817e+08,1.30897e+08,2.420
|
||||
ParseString/signed_ints,ns,1.22931e+08,3.19852e+07,3.843
|
||||
ParseString/small_signed_ints,ns,6.2685e+07,2.49764e+07,2.510
|
||||
ParseString/twitter,ns,3.2961e+06,1.04867e+06,3.143
|
||||
ParseString/unsigned_ints,ns,1.21229e+08,3.29241e+07,3.682
|
||||
ParseStringOrdered/canada,ns,1.5388e+07,4.5275e+06,3.399
|
||||
ParseStringOrdered/citm_catalog,ns,1.15204e+07,1.68115e+06,6.853
|
||||
ParseStringOrdered/jeopardy,ns,3.73533e+08,1.13397e+08,3.294
|
||||
ParseStringOrdered/twitter,ns,4.5979e+06,948606,4.847
|
||||
Patch/canada,ns,1.03684e+07,3.47719e+06,2.982
|
||||
Patch/citm_catalog,ns,2.74522e+06,1.74191e+06,1.576
|
||||
Patch/twitter,ns,1.57928e+06,888657,1.777
|
||||
SaxParse/canada,ns,1.31023e+07,3.26697e+06,4.011
|
||||
SaxParse/citm_catalog,ns,6.54642e+06,966806,6.771
|
||||
SaxParse/twitter,ns,2.53102e+06,483052,5.240
|
||||
ToCbor/canada,ns,1.41339e+06,556912,2.538
|
||||
ToCbor/citm_catalog,ns,1.04743e+06,259178,4.041
|
||||
ToCbor/floats,ns,9.04677e+06,1.90094e+06,4.759
|
||||
ToCbor/jeopardy,ns,7.39339e+07,2.20678e+07,3.350
|
||||
ToCbor/signed_ints,ns,1.15333e+07,2.827e+06,4.080
|
||||
ToCbor/small_signed_ints,ns,1.0394e+07,2.47974e+06,4.192
|
||||
ToCbor/twitter,ns,658566,143397,4.593
|
||||
ToCbor/unsigned_ints,ns,8.17966e+06,2.81588e+06,2.905
|
||||
ToJsonStrings/copy,ns,6.12e+06,5.65303e+06,1.083
|
||||
ToJsonStrings/move,ns,6.13061e+06,3.13303e+06,1.957
|
||||
Unflatten/canada,ns,4.25276e+07,1.10995e+07,3.831
|
||||
Unflatten/citm_catalog,ns,1.01866e+07,3.62185e+06,2.813
|
||||
Unflatten/twitter,ns,4.74536e+06,2.21103e+06,2.146
|
||||
|
@@ -0,0 +1,354 @@
|
||||
index,commit,date,pr,subject,parse_twitter,parse_citm,parse_canada,parse_citm_compact,parse_twitter_ifstream,accept_twitter,dump_twitter,dump_citm,dump_canada,dump4_citm,from_cbor_twitter,to_cbor_twitter,copy_destroy_citm,equal_citm,view_parse_twitter,view_parse_citm,view_parse_canada
|
||||
0,55f93686c0,2025-04-11,,Merge branch 'release/3.12.0',3571.487,8219.609,17049.073,4366.792,3846.006,2394.213,1441.213,1375.446,7510.989,1917.809,3463.281,695.524,1643.327,1956.891,,,
|
||||
1,1705bfe914,2025-04-11,4727,:bookmark: set version to 3.12.0 (#4727),3589.331,8245.422,17079.250,4422.711,3894.787,2397.597,1440.546,1377.745,7514.698,1922.371,3498.997,695.559,1655.240,1967.301,,,
|
||||
2,4cca3b9cb2,2025-04-13,4738,Fix warning and add emscripten CI step (#4738),3559.657,8195.105,17066.291,4373.011,3794.269,2388.900,1419.182,1355.724,7420.703,1912.038,3468.667,664.214,1631.610,1939.475,,,
|
||||
3,96c1b52f1c,2025-04-15,4742,Fix conversion to std::optional (#4742),3573.838,8157.276,16993.208,4383.656,3858.927,2395.092,1438.169,1372.208,7497.776,1925.481,3482.185,667.895,1633.619,1946.687,,,
|
||||
4,88c92e605c,2025-04-16,4744,Fix compilation failure and warnings with NVHPC (#4744),3563.149,8039.911,16922.739,4381.927,3768.560,2385.086,1407.564,1345.578,7370.063,1897.474,3462.010,662.955,1623.286,1925.804,,,
|
||||
5,c67d538274,2025-04-17,4749,Fix C4702 warning and extend MSVC CI job (#4749),3585.422,8251.057,17050.448,4400.542,3896.586,2390.655,1440.391,1371.722,7453.474,1921.277,3478.523,667.911,1636.206,1939.531,,,
|
||||
6,756ca22ec5,2025-04-23,4736,Provide fallback for missing `char8_t` support (#4736),3559.146,8139.703,17085.114,4387.658,3856.745,2392.849,1424.997,1370.599,7477.537,1907.661,3484.427,665.541,1634.156,1957.401,,,
|
||||
7,6b9199382b,2025-04-27,4763,Add missing header (#4763),3541.323,8077.761,17011.636,4359.183,3842.380,2396.686,1421.116,1363.737,7431.375,1902.909,3474.250,664.442,1625.644,1934.732,,,
|
||||
8,3b02afb9d9,2025-04-28,4760,Specialize char_traits for std::byte to fix from_msgpack (fixes #4756) (#4760),3583.070,8198.146,17134.698,4381.743,3899.872,2409.185,1440.233,1380.810,7504.838,1921.781,3500.125,666.078,1657.207,1966.036,,,
|
||||
9,eef76c200e,2025-04-28,4764,Make library work with C++20 modules (#4764),3528.529,8080.458,16936.656,4330.570,3764.287,2363.848,1407.851,1358.079,7356.239,1897.423,3455.287,665.194,1632.255,1937.675,,,
|
||||
10,dff2b4756c,2025-04-29,4765,fix: BJData size calculation overflow (#4765),3553.706,8141.375,17047.511,4360.144,3797.070,2389.756,1417.737,1364.718,7454.313,1921.962,3479.878,666.456,1644.760,1944.696,,,
|
||||
11,9110918cf8,2025-05-04,4748,Fix typos (#4748),3563.682,8176.427,17239.354,4398.055,3891.669,2399.782,1441.669,1387.133,7516.073,1925.323,3483.271,669.348,1647.760,1957.747,,,
|
||||
12,46e7cd3dc2,2025-05-16,4775,Replace deprecated std::is_trivial in C++26 (#4775),3565.242,8195.396,17135.646,4373.479,3851.604,2392.258,1418.425,1370.958,7464.854,1909.844,3485.046,665.606,1643.155,1952.329,,,
|
||||
13,828c891427,2025-05-16,4786,Extend type_name() to invalid type (#4786),3549.573,8103.761,17066.198,4359.911,3804.849,2389.121,1428.584,1366.405,7424.838,1914.434,3452.497,667.452,1632.750,1928.324,,,
|
||||
14,4b17f90f65,2025-05-22,4609,Add `ignore_trailing_commas` option (#4609),3544.662,8132.052,16997.375,4344.592,3825.765,2382.755,1408.435,1367.468,7460.448,1924.522,3434.062,733.089,1631.356,1891.572,,,
|
||||
15,b19f058465,2025-06-01,4802,Encode infinity and NaN as float for MsgPack and CBOR (#4802),3550.020,8126.438,17350.885,4327.596,3825.419,2389.356,1409.422,1376.649,7363.802,1921.226,3441.081,683.190,1624.144,1886.388,,,
|
||||
16,cf16c5ab9f,2025-06-02,4805,Use binary_t::value_type (#4805),3551.735,8143.521,17153.291,4309.477,3829.229,2387.640,1428.550,1385.585,7415.271,1932.347,3425.838,657.735,1631.586,1888.954,,,
|
||||
17,d70e46bc65,2025-06-25,4830,:bug: add missing header to input_adapters.hpp (#4830),3546.448,8157.469,17062.364,4335.300,3805.221,2382.796,1422.863,1382.581,7411.401,1928.676,3433.190,691.842,1632.972,1892.453,,,
|
||||
18,30d27df61c,2025-07-31,4871,Fix CI (#4871),3570.015,8150.859,17070.625,4330.078,3806.505,2400.329,1434.947,1381.065,7425.718,1931.556,3429.632,656.545,1633.515,1892.916,,,
|
||||
19,efcf9efb4f,2025-08-02,4873,Fixes #4854 Explicitly handle nullptr in sax_parse (#4873),3520.381,8050.719,16883.042,4331.820,3861.906,2368.069,1408.435,1375.954,7363.651,1898.466,3432.992,653.988,1634.141,1894.948,,,
|
||||
20,4106af8d92,2025-08-20,4896,":rotating_light: suppress cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator (#4896)",3540.599,8175.265,17010.438,4345.182,3866.833,2393.935,1435.100,1389.496,7453.724,1945.791,3433.169,657.446,1638.434,1900.360,,,
|
||||
21,a63795caf1,2025-10-22,4791,:rotating_light: avoid deprecation warning (#4791),3550.057,8174.646,16983.177,4363.521,3888.336,2393.305,1423.434,1376.334,7469.407,1936.013,3447.279,666.706,1645.354,1903.707,,,
|
||||
22,1cc56b2dcd,2025-10-23,4957,Address CWG issue 2521 (#4957),3557.396,8119.651,17072.730,4351.881,3834.739,2386.097,1442.100,1393.245,7474.463,1932.315,3446.883,660.187,1638.983,1896.000,,,
|
||||
23,54be9b04f0,2025-10-23,4960,:page_facing_up: update REUSE (#4960),3554.625,8098.287,17115.219,4324.578,3809.950,2390.791,1424.488,1376.715,7422.828,1913.208,3424.693,659.030,1623.405,1892.756,,,
|
||||
24,29913ca760,2025-10-25,4963,Add char8_t* overload for _json and _json_pointer (#4963),3544.899,8169.203,17007.844,4353.594,3797.630,2392.108,1423.032,1375.216,7349.787,1909.897,3428.771,655.625,1635.273,1891.018,,,
|
||||
25,515d994acb,2026-01-01,5044,:page_facing_up: adjust year (#5044),3524.610,8059.521,16949.416,4313.508,3773.750,2364.742,1410.427,1372.988,7382.438,1915.502,3403.159,643.968,1618.972,1884.213,,,
|
||||
26,8f75700141,2026-01-11,4958,support types convertible to string_view as JSON keys (#4958),3546.757,8142.599,17103.386,4327.739,3825.990,2388.540,1420.515,1379.309,7413.062,1924.540,3433.677,658.266,1628.079,1890.759,,,
|
||||
27,457bc283ff,2026-01-12,5039,fix(cbor): reject overflowing negative integers (#5039),3508.883,8077.291,16930.011,4305.982,3785.698,2378.693,1425.526,1366.111,7407.042,1929.142,3478.909,657.722,1636.304,1944.681,,,
|
||||
28,e3014f162a,2026-01-13,5052,Fix conversion to std::optional (#5052),3547.995,8140.052,17010.031,4321.914,3797.807,2385.856,1430.414,1386.202,7407.260,1930.403,3462.213,657.829,1629.579,1932.066,,,
|
||||
29,5ed07097fa,2026-01-13,5050,Fix -Wtautological-constant-out-of-range-compare in serializer (#5050),3544.136,8180.208,17033.209,4339.591,3799.779,2391.940,1427.870,1387.871,7368.765,1922.321,3454.938,659.367,1630.707,1959.722,,,
|
||||
30,25f48639c7,2026-01-23,5016,Reference tuple from json (#5016),3563.180,8209.037,17030.969,4388.675,3895.086,2392.088,1430.666,1393.853,7528.567,1934.347,3481.351,677.234,1645.418,1957.591,,,
|
||||
31,f8eee1bb79,2026-02-07,5071,Annotate unreachable comment-scanner switch paths to satisfy C26819 (#5071),3508.000,8128.750,16958.959,4315.235,3797.237,2371.963,1425.146,1374.867,7453.381,1930.211,3456.508,658.568,1629.188,1909.736,,,
|
||||
32,fd17b0889e,2026-05-08,5139,Remove nullptr safety check from sax_parse functions (#5139),3544.101,8033.021,16963.292,4334.102,3800.736,2382.583,1419.050,1361.745,7357.073,1907.153,3429.315,657.041,1618.815,1937.829,,,
|
||||
33,62f3b41b30,2026-05-08,5090,fix: treat single-element brace-init as copy/move instead of wrapping in array (#5074) (#5090),3550.323,8168.713,17060.031,4349.417,3794.110,2380.583,1416.822,1361.182,7369.651,1897.717,3466.731,659.297,1631.463,1941.905,,,
|
||||
34,4fad446897,2026-05-10,5162,docs: add IDs to @requirement tags to fix Doxygen autolinking (#5162),3545.440,8031.891,17069.448,4324.698,3802.862,2383.513,1422.768,1384.602,7325.776,1917.606,3469.787,659.011,1631.296,1940.370,,,
|
||||
35,a0a4e7cc0b,2026-05-13,5152,Add front methods to json_pointers (implements #4889) (#5152),3582.898,8215.010,17034.448,4345.515,3891.513,2396.572,1432.733,1395.714,7554.119,1934.008,3484.859,659.298,1642.314,1957.356,,,
|
||||
36,93e49decbd,2026-05-14,5167,Fix incomplete-type error in set_parents with ordered_json (#5167),3555.224,8147.771,17017.073,4320.846,3831.318,2386.750,1435.840,1385.578,7436.864,1927.483,3466.508,658.409,1632.724,1939.528,,,
|
||||
37,7192763f15,2026-05-14,5163,Fix compile error when using nlohmann ordered_map with WITH_DEFAULT macros (#5163),3520.675,8039.145,16892.291,4303.448,3769.198,2363.337,1410.030,1364.679,7380.797,1913.285,3437.278,660.130,1630.738,1943.235,,,
|
||||
38,5a05627b1f,2026-05-14,5169,:rotating_light: fix warning (#5169),3600.555,8160.854,16979.031,4324.070,3887.823,2389.157,1430.983,1387.106,7509.984,1912.601,3473.713,663.279,1652.982,1958.774,,,
|
||||
39,bb5404bb86,2026-05-15,5164,Fix GCC C++20 modules compilation #5103 (#5164),3543.823,8120.266,17015.395,4349.300,3794.880,2364.178,1414.408,1374.548,7484.218,1920.495,3444.266,699.326,1626.241,1954.688,,,
|
||||
40,b1bb9fce0c,2026-05-15,3929,Fix for printing long doubles bug in dump_float (#3929),3549.378,8089.891,16934.927,4313.310,3824.802,2386.958,1412.164,1385.425,7417.869,1930.513,3461.151,651.557,1618.735,1944.450,,,
|
||||
41,cba5dc0ed8,2026-05-16,4563,New macros for the named JSON convertor generation (#4563),3544.657,8168.182,16990.886,4327.688,3806.963,2370.975,1421.629,1390.206,7454.151,1919.284,3452.456,677.413,1623.622,1941.921,,,
|
||||
42,47202c804a,2026-05-18,5171,Add missing overload to ordered_map::find (#5171),3527.542,8168.312,17141.989,4409.456,3887.378,2397.007,1428.765,1387.033,7495.604,1935.710,3485.088,660.155,1648.977,1951.430,,,
|
||||
43,58cfecf7f7,2026-05-18,5151,Serialize enum (#5151),3521.302,8100.104,16805.489,4288.463,3763.971,2381.494,1408.713,1383.059,7328.261,1915.202,3440.372,648.726,1617.661,1922.608,,,
|
||||
44,584e6b1cfb,2026-05-22,5187,Fix: update() parent pointers not updated after recursive merge with JSON_DIAGNOSTICS (#5187),3550.639,8083.463,17055.198,4326.833,3804.257,2381.519,1432.039,1381.986,7377.844,1915.159,3460.750,656.873,1631.527,1940.953,,,
|
||||
45,02dfbea39d,2026-06-17,5209,added explicit instantiations of 'has_from_json' and 'has_to_json' for std_fs::path (#5209),3552.209,8215.474,17167.760,4338.404,3845.144,2398.026,1425.012,1387.629,7458.614,1931.388,3475.343,658.183,1644.329,1958.324,,,
|
||||
46,fc1df0b7db,2026-06-23,5172,:recycle: remove unnecessary if (#5172),3562.088,8175.531,17044.042,4336.583,3863.651,2404.695,1425.872,1389.434,7523.855,1914.128,3481.000,653.259,1639.515,1957.649,,,
|
||||
47,c5b2b26fdc,2026-06-29,5217,:memo: fix docs (#5217),3526.825,8052.307,17000.011,4343.963,3793.412,2388.194,1416.706,1374.177,7361.646,1904.008,3463.919,658.322,1627.765,1921.887,,,
|
||||
48,b7566c6293,2026-06-30,5161,Harden JSON_HAS_RANGES detection for incomplete C++20 ranges implementations (#5161),3538.995,8071.787,17120.751,4318.797,3772.445,2384.008,1421.440,1385.239,7419.292,1898.929,3431.466,647.948,1602.258,1928.644,,,
|
||||
49,adf78d3a76,2026-06-30,5215,Minor: unique_ptr template resolution workaround for MSVC (#5215),3550.380,8138.026,17036.802,4366.062,3842.430,2389.536,1426.658,1385.609,7428.787,1915.233,3467.188,658.332,1636.158,1942.556,,,
|
||||
50,272411c5e6,2026-06-30,5218,Overwork project infrastructure (#5218),3547.487,8087.250,16962.198,4341.969,3793.831,2387.509,1420.888,1381.072,7450.078,1930.003,3466.193,659.676,1631.329,1943.043,,,
|
||||
51,730b57775d,2026-07-01,5222,:bug: avoid assertion in patch (#5222),3539.912,8169.771,17027.229,4345.151,3790.753,2376.552,1421.263,1386.717,7399.985,1923.237,3455.722,653.609,1630.914,1934.028,,,
|
||||
52,ca49ab6123,2026-07-02,5223,Extend value to arrays when using JSON pointers (#5223),3550.341,8113.787,16951.313,4346.805,3793.097,2391.224,1409.695,1380.075,7374.073,1926.401,3458.438,659.382,1629.387,1941.306,,,
|
||||
53,8d7e0046f4,2026-07-02,5224,Add std::format and fmt support (#5224),3546.935,8170.406,16968.927,4346.906,3814.956,2387.612,1424.861,1386.542,7350.765,1900.376,3461.177,662.476,1633.858,1930.434,,,
|
||||
54,31dd15b258,2026-07-02,5221,Fix ambiguous static_cast (#5221),3551.945,8213.000,17131.271,4373.620,3845.763,2393.074,1438.633,1385.769,7471.146,1927.804,3486.568,662.015,1631.810,1958.901,,,
|
||||
55,eed1587000,2026-07-05,5234,Reconstruct lexer diagnostics lazily for seekable input (#120) (#5234),3145.909,5311.094,15381.843,4292.961,3851.260,1966.833,1422.598,1365.461,7443.276,1920.467,3467.060,702.832,1637.587,1905.758,,,
|
||||
56,83c87cb9e0,2026-07-05,5233,Read binary strings/blobs in bulk chunks with a memcpy fast path (#5233),3141.867,5259.485,15454.959,4326.664,3797.198,1987.623,1406.492,1372.765,7424.729,1899.726,2363.895,667.502,1630.097,1888.392,,,
|
||||
57,acf076a677,2026-07-06,5238,Fix ADL leak of nlohmann::detail through basic_json's default base class (#5238),3152.153,5277.073,15291.407,4338.828,3839.331,1995.524,1429.960,1365.917,7456.776,1907.928,2398.016,670.257,1627.590,1897.997,,,
|
||||
58,c05c5e229b,2026-07-07,5241,Add missing copyright notices to SBOM (#5241),3147.485,5268.865,15319.584,4321.823,3796.972,1981.167,1432.689,1371.264,7465.416,1918.083,2388.154,667.119,1630.745,1891.583,,,
|
||||
59,366f3d26e5,2026-07-08,5235,Replace snprintf with a branch-free writer for \uXXXX escapes (#5235),3127.641,5272.302,15425.239,4340.459,3850.357,1997.957,1459.603,1356.461,7509.703,1899.916,2366.966,668.383,1624.981,1889.145,,,
|
||||
60,f8e99e856c,2026-07-09,5248,Fix nvcc CUDA 12.0/12.1 C++20 ranges parse error (#3907) (#5248),3132.099,5226.375,15164.510,4301.901,3769.651,1967.647,1456.759,1365.810,7530.724,1908.635,2381.610,683.815,1616.699,1879.795,,,
|
||||
61,855f511db4,2026-07-09,5250,Fix stale Clang -Weverything suppression comments; drop -Wno-missing-noreturn (#5250),3126.792,5208.338,15352.520,4293.596,3800.544,1969.497,1458.601,1329.851,7372.849,1876.404,2368.894,662.173,1603.881,1874.673,,,
|
||||
62,d0a43141ea,2026-07-09,5253,Fix #3868: Remove operator!= to enable P2468R2 rewritten candidate synthesis (#5253),3165.182,5270.458,15479.031,4302.729,3845.646,1989.231,1474.135,1343.312,7443.282,1887.909,2392.523,670.395,1634.871,1894.474,,,
|
||||
63,b630f5e9c7,2026-07-10,5260,Fix container input_adapter SFINAE for lvalue-only ADL begin/end (#5260),3128.117,5263.807,15375.677,4330.544,3819.953,1982.196,1454.088,1339.062,7364.683,1877.699,2361.482,666.486,1616.514,1920.626,,,
|
||||
64,c60217e801,2026-07-11,5205,fix: support constructing json from C++20 range views (#4916) (#5205),3117.539,5206.552,15308.166,4320.513,3798.713,1983.458,1447.072,1350.950,7357.213,1875.632,2340.731,662.905,1633.357,1934.261,,,
|
||||
65,fe2bcc080f,2026-07-11,5266,Custom BinaryType direct assignment (#5266),3174.528,5284.562,15383.645,4328.120,3895.086,1996.913,1478.427,1355.569,7512.115,1899.236,2398.490,672.118,1642.910,1967.660,,,
|
||||
66,ca76c37650,2026-07-11,5265,Add iterator+sentinel tests and docs for binary deserializers (#5265),3134.265,5218.021,15352.521,4306.284,3791.612,1967.824,1451.953,1358.685,7508.828,1891.697,2377.848,665.474,1631.495,1934.907,,,
|
||||
67,c197feff81,2026-07-12,5268,Extend memcpy fast path to sized sentinels (e.g. std::counted_iterator) (#5268),3116.271,5207.146,15415.771,4272.443,3815.851,1984.966,1451.103,1341.093,7328.037,1865.385,2383.169,664.494,1617.967,1915.428,,,
|
||||
68,1c5a953de5,2026-07-19,5276,reject unpaired UTF-16 surrogates in wide-string input (#5276),3155.360,5299.631,15419.812,4302.089,3853.104,1987.259,1468.653,1349.665,7549.432,1911.365,2457.555,680.311,1653.282,1955.673,,,
|
||||
69,3565f40229,2026-07-20,5284,reject negative UBJSON/BJData string length (#5284),3170.456,5301.698,15404.416,4351.226,3893.594,1997.034,1470.907,1358.245,7491.480,1909.601,2401.384,671.260,1639.865,1963.899,,,
|
||||
70,9a3ebb9456,2026-07-23,5287,validate BSON document size against the bytes read (#5287),3157.646,5264.062,15305.271,4338.672,3839.643,1987.196,1461.356,1351.630,7444.791,1890.626,2398.503,665.262,1655.798,1930.268,,,
|
||||
71,8ec98e2c9e,2026-07-27,5313,adding cleanups to bson writer (#5313),3150.448,5268.948,15445.927,4308.612,3805.005,1989.643,1466.348,1349.591,7326.453,1895.842,2393.278,708.164,1644.025,1946.652,,,
|
||||
72,2e23687092,2026-07-28,5314,to_bson() silently emits corrupt documents when a length exceeds INT32_MAX (#5314),3146.534,5254.547,15445.250,4304.008,3798.620,1986.260,1459.735,1345.534,7517.651,1903.996,2395.155,674.344,1644.565,1952.682,,,
|
||||
73,868506dcc0,2026-07-30,5335,Fix CBOR half-float assertion bounds (#5335),3167.086,5267.068,15397.979,4351.011,3883.135,2003.345,1468.939,1360.483,7455.230,1909.055,2406.305,679.942,1643.646,1945.639,,,
|
||||
74,dd24e2dffd,2026-07-30,5332,check all BSON reads and add an EOF check for booleans (#5332),3138.315,5284.833,15399.166,4310.513,3847.630,1980.682,1464.104,1344.108,7445.146,1901.512,2400.532,670.850,1635.196,1900.946,,,
|
||||
75,fd72ecfc8c,2026-07-31,5301,validate ndarray element types in write_bjdata_ndarray (#5301),3164.662,5262.141,15399.010,4287.271,3849.318,1988.186,1460.688,1353.767,7458.380,1893.669,2398.485,668.466,1644.018,1921.615,,,
|
||||
76,bc48951128,2026-07-31,5323,Fix UBJSON high-precision floating-point overflow handling (#5323),3155.628,5289.864,15474.375,4324.253,3888.966,2015.068,1477.846,1354.622,7480.730,1905.566,2415.428,668.997,1641.776,1911.819,,,
|
||||
77,d94cbd99dc,2026-07-31,5274,reject CBOR array/map length equal to the indefinite-length marker (#5274),3144.041,5272.193,15466.980,4338.735,3848.849,1999.231,1459.129,1358.119,7507.307,1901.807,2394.972,667.016,1635.960,1899.878,,,
|
||||
78,2222d386c9,2026-07-31,5339,fix: check CBOR tagged subtype reads (#5339),3095.768,5137.792,15064.146,4258.977,3755.229,1965.900,1454.890,1338.066,7399.068,1883.624,2358.193,660.190,1618.172,1939.713,,,
|
||||
79,585929bff9,2026-08-03,5289,Fix Clang deprecation warning for json_pointer operator== with ordered_json (#5289),3142.341,5259.360,15258.271,4275.479,3807.672,1969.704,1453.688,1337.633,7451.037,1879.447,2364.966,661.560,1635.617,1945.709,,,
|
||||
80,5f121d8c50,2026-08-03,5336,avoid sign extension in char_traits<signed char>::to_int_type (#5336),3145.000,5264.880,15441.521,4269.632,3796.781,1983.497,1440.810,1325.232,7427.750,1880.047,2361.899,663.772,1621.595,1912.378,,,
|
||||
81,68f0722a19,2026-08-03,5342,remove discarded array from parent object in end_array (#5342),3161.273,5269.907,15312.469,4335.433,3840.510,1995.965,1465.745,1355.934,7474.901,1895.483,2401.197,657.397,1634.791,1901.902,,,
|
||||
82,dca9d49a33,2026-08-05,5348,reject out-of-range code points in UTF-32 wide-string input (#5348),3119.753,5210.979,15209.260,4273.984,3799.034,1995.297,1459.456,1342.982,7431.646,1891.478,2370.364,653.618,1633.585,1882.753,,,
|
||||
83,9a091d2b82,2026-08-05,5362,Do not write BJData ndarrays whose size overflows std::size_t (#5362),3137.381,5257.312,15286.084,4308.500,3805.325,1995.140,1468.138,1354.729,7510.088,1893.036,2384.577,659.394,1628.260,1890.245,,,
|
||||
84,d5647e6a3b,2026-08-05,5355,Resolve the TODO(niels) in get_ubjson_string (#5355),3121.278,5249.927,15246.011,4292.737,3800.490,1967.087,1443.762,1333.226,7368.953,1862.131,2347.852,644.647,1623.909,1889.958,,,
|
||||
85,bacdabd176,2026-08-05,5361,Fix start_pos() for strings containing escape sequences (#5361),3114.653,5251.619,15253.907,4331.818,3786.156,1960.676,1442.388,1330.247,7354.724,1863.306,2351.588,650.781,1623.543,1886.671,,,
|
||||
86,1c136a66c4,2026-08-06,5363,Move the CBOR doc block to the function it describes (#5363),3124.274,5209.615,15411.897,4293.320,3812.156,1982.854,1457.653,1345.680,7422.343,1884.848,2387.050,656.076,1627.620,1878.737,,,
|
||||
87,6285225fd0,2026-08-12,5211,Fix integer comparison bug (#5211),3159.557,5291.323,15395.395,4329.836,3867.200,1989.476,1456.052,1359.795,7526.860,1879.642,2396.137,659.077,1638.176,1900.416,,,
|
||||
88,b5378e8deb,2026-08-19,5331,Fix CBOR tag handlers not recognizing tags 0-5 and 21-23 (#5331),3172.476,5239.812,15479.917,4295.539,3871.289,2003.439,1473.447,1343.742,7516.875,1888.412,2400.572,645.588,1641.621,1886.531,,,
|
||||
89,2f025f401e,2026-08-25,5380,Throw other_error.502 when UBJSON use_type is set without use_size (#5380),3155.873,5190.312,15144.406,4286.388,3793.805,1968.199,1442.240,1340.929,7373.610,1860.543,2370.570,648.906,1631.207,1893.750,,,
|
||||
90,35705d79d8,2026-08-28,5414,Fix update(merge_objects=true) throwing on primitive-to-object merge (#5414),3169.029,5252.578,15387.292,4340.690,3893.646,1979.616,1472.286,1361.543,7491.302,1903.909,2401.404,659.396,1641.697,1912.409,,,
|
||||
91,137a40b9aa,2026-09-05,5459,Compare integers with floats exactly instead of widening the integer (#5459),3134.229,5259.349,15404.541,4300.146,3846.646,1992.155,1467.919,1351.774,7467.146,1887.255,2391.467,660.347,1631.735,1891.751,,,
|
||||
92,3c875683a5,2026-09-05,5461,Make diff() linear when an array shrinks (#5461),3141.068,5259.000,15271.166,4319.659,3797.088,1983.450,1455.354,1354.676,7444.860,1891.687,2389.333,657.163,1632.998,1887.016,,,
|
||||
93,09b6b6b5ba,2026-09-05,5455,Fix to_bjdata() emitting unparsable output when _ArraySize_ is not an array (#5455),3161.542,5253.047,15311.718,4291.388,3834.264,1992.744,1472.685,1357.680,7409.479,1889.287,2389.501,698.680,1628.237,1888.705,,,
|
||||
94,faa35cc647,2026-09-09,5484,Skip integer conversion in accept()/SAX validation when the value is unused (#5484),3103.654,5222.453,15458.573,4215.765,3804.320,1935.161,1468.660,1353.499,7452.052,1883.191,2383.524,654.441,1631.700,1885.664,,,
|
||||
95,6d86cc0f6b,2026-09-09,5490,Speed up whitespace skipping in the lexer (#5490),3181.328,5276.318,15307.312,4262.771,3877.401,1977.062,1465.196,1356.119,7594.177,1906.814,2388.615,684.926,1636.950,1893.526,,,
|
||||
96,c05347dd54,2026-09-09,5475,Undefine the four JSON_HEDLEY_* macros that leak after including json.hpp (#5475),3147.932,5156.625,15347.990,4217.505,3871.812,1982.807,1458.787,1354.934,7639.328,1879.823,2370.342,674.625,1637.257,1903.903,,,
|
||||
97,d6660cf718,2026-09-09,5485,Route hand-rolled diagnostic pragmas through Hedley (#5485),3116.151,5215.531,15257.499,4189.979,3835.023,1974.111,1459.363,1342.996,7553.802,1887.698,2379.999,669.934,1635.350,1877.492,,,
|
||||
98,c9477ccf91,2026-09-09,5496,Throw when JSON Patch remove's target path resolves through a primitive or null parent (#5496),3138.841,5258.401,15315.417,4201.008,3874.682,1967.630,1446.393,1335.060,7542.708,1870.111,2390.141,668.484,1634.138,1886.981,,,
|
||||
99,8c38e270b5,2026-09-09,5497,Reject JSON Patch move when from is a proper prefix of path (#5497),3183.820,5280.000,15346.969,4222.164,3839.596,1970.753,1470.428,1351.838,7515.344,1895.809,2389.731,673.696,1633.247,1889.546,,,
|
||||
100,a316738cfa,2026-09-09,5471,Add JSON_HEDLEY_WARN_UNUSED_RESULT to the current accept() overloads (#5471),3175.891,5281.302,15397.062,4240.576,3934.333,1981.765,1475.890,1353.387,7625.104,1896.181,2401.097,669.729,1646.133,1895.638,,,
|
||||
101,c9f1d2d646,2026-09-09,5477,Broaden JSON_HEDLEY_WARN_UNUSED_RESULT coverage to pure query functions (#5477),3171.706,5286.880,15430.844,4264.242,3880.943,1979.990,1472.289,1357.283,7569.854,1904.026,2407.487,671.673,1641.521,1889.053,,,
|
||||
102,8e26b9d4b3,2026-09-09,5495,Make contains(json_pointer) return false instead of throwing on unrepresentable array-index tokens (#5495),3163.789,5240.755,15337.698,4226.154,3880.956,1971.912,1475.322,1357.125,7632.281,1904.060,2401.190,678.863,1638.371,1903.385,,,
|
||||
103,b17c272f46,2026-09-09,5472,Reserve capacity in from_json() object conversion when the target container supports it (#5472),3152.899,5257.645,15401.000,4210.846,3885.123,1989.159,1476.637,1359.851,7639.396,1898.981,2408.243,670.075,1633.528,1894.086,,,
|
||||
104,3e2de32226,2026-09-10,5516,Remove unused iomanip include (#5516),3141.349,5253.657,15364.074,4203.969,3847.620,1968.422,1455.035,1352.754,7582.494,1882.051,2371.814,663.504,1630.172,1870.223,,,
|
||||
105,d69fb8654d,2026-09-10,5501,Return the parsed value by move from from_cbor() and friends (#5501),3133.485,5231.662,15309.926,4183.200,3835.662,1971.125,1462.447,1349.563,7479.136,1904.202,1595.991,661.519,1630.278,1883.994,,,
|
||||
106,4a93aa4e2f,2026-09-10,5283,"Speed up parsing of contiguous input (numbers, strings, UTF-8) (#5283)",1963.879,4221.308,11609.531,3278.497,3857.880,927.779,1483.726,1357.793,7483.343,1906.916,1481.419,676.438,1643.746,1895.551,,,
|
||||
107,bfb07786cd,2026-09-10,5473,Fix to_bjdata() silently truncating out-of-range _ArrayData_ elements (#5473),1941.894,4204.971,11726.688,3264.055,3808.784,923.797,1453.071,1351.760,7458.125,1891.470,1473.508,662.164,1633.043,1888.548,,,
|
||||
108,ff80ed3295,2026-09-11,5285,"Speed up dump(), and keep it from overflowing the stack (#5285)",1939.289,4175.541,11781.291,3233.302,3816.101,914.071,441.200,540.473,6895.041,852.214,1478.197,656.635,1632.675,1885.303,,,
|
||||
109,da42a627dc,2026-09-11,5449,Stop dump() from heap-allocating its output adapter per call (#5449),1937.658,4200.966,11639.198,3235.493,3827.695,909.901,448.948,537.008,6909.036,839.027,1479.968,659.210,1643.621,1878.065,,,
|
||||
110,1dc1d09fc6,2026-09-11,5457,Do not search a container for the value the callback rejected (#5457),1937.459,4140.078,11576.803,3271.838,3845.193,924.316,450.148,539.031,6848.776,844.624,1470.333,671.563,1645.624,1900.347,,,
|
||||
111,fae364db24,2026-09-11,5458,Move the scanned string into the value instead of copying it (#5458),1986.146,4110.787,11757.157,3150.932,3830.550,918.517,442.629,539.606,6913.104,843.920,1417.037,655.259,1628.224,1892.991,,,
|
||||
112,dd50f0eb16,2026-09-11,5502,Stop CBOR indefinite-length strings from recursing per chunk (#5502),1987.853,4033.182,11613.834,3116.378,3841.164,915.943,442.366,539.480,6864.130,836.458,1431.035,656.146,1599.574,1885.858,,,
|
||||
113,4bb2de8cc5,2026-09-11,5503,Reject a nested BJData ndarray dimension vector where it is read (#5503),1981.298,4086.276,11569.240,3141.539,3829.870,923.087,444.038,539.863,6800.724,835.434,1429.637,655.448,1628.999,1879.300,,,
|
||||
114,44f8ec30e9,2026-09-11,5504,Bound UBJSON optimized arrays of a valueless type (#5504),2005.265,4092.265,11730.198,3130.635,3863.992,925.033,448.222,542.323,6893.078,849.901,1437.855,662.171,1638.306,1896.324,,,
|
||||
115,0dd8ca9023,2026-09-11,5505,Read MessagePack containers without recursing per nesting level (#5505),2019.983,4105.305,11862.979,3142.581,3891.601,927.092,447.942,543.936,6939.963,845.634,1442.889,656.578,1637.512,1897.815,,,
|
||||
116,91ab3e81f5,2026-09-11,5506,Read CBOR containers and tags without recursing per nesting level (#5506),1986.334,4039.961,11554.094,3118.761,3783.101,912.504,440.410,534.894,6831.943,834.661,1439.061,655.287,1615.619,1869.912,,,
|
||||
117,a14619b354,2026-09-11,5507,Read UBJSON and BJData containers without recursing per nesting level (#5507),2011.959,4095.868,11782.688,3135.264,3873.604,926.014,447.638,541.304,6905.838,846.051,1468.512,664.161,1629.083,1898.772,,,
|
||||
118,0452641c18,2026-09-11,5508,Read BSON documents without recursing per nesting level (#5508),1974.160,4043.887,11662.938,3095.011,3832.744,916.007,439.914,534.149,6904.453,835.615,1450.792,648.298,1616.917,1874.133,,,
|
||||
119,aa391dc0a5,2026-09-11,5520,Fix two develop CI regressions: dump() nodiscard warning and binary-reader const-correctness (#5520),2003.010,4068.010,11771.364,3137.266,3825.247,924.668,442.416,539.478,6847.083,841.996,1460.659,649.378,1633.738,1885.897,,,
|
||||
120,a50c2537eb,2026-09-12,5476,Reserve capped array capacity in json_sax_dom_parser::start_array() for definite-length binary arrays (#5476),1986.488,4063.883,11588.333,3077.995,3827.479,908.419,440.959,539.114,6806.177,833.555,1452.851,662.422,1627.995,1915.388,,,
|
||||
121,c0b2878a44,2026-09-13,5493,Swap diagnostic positions in basic_json::swap() (#5493),2010.881,4081.057,11734.730,3130.919,3882.258,925.490,450.092,542.953,6925.188,848.486,1480.051,698.636,1643.508,1933.941,,,
|
||||
122,1da2f68992,2026-09-14,5522,Only reserve array capacity if the array type supports it (#5522),1972.122,4048.622,11775.062,3107.938,3803.528,909.385,441.204,535.885,6793.927,842.843,1446.330,658.787,1619.239,1899.164,,,
|
||||
123,6487678bc5,2026-09-15,5464,Fix swap(array_t&)/swap(object_t&) to update parent pointers under JSON_DIAGNOSTICS (#5464),2023.028,4116.169,11737.438,3165.172,3893.266,924.912,448.959,541.529,6970.438,852.039,1483.231,689.631,1635.240,1937.356,,,
|
||||
124,c72f37a40d,2026-09-15,5443,Support custom object/array types and improve template parameter handling (#5443),2001.617,4076.547,11666.583,3109.756,3918.206,923.197,450.592,542.266,6901.703,846.558,1468.284,660.116,1641.586,1905.840,,,
|
||||
125,502e9d66f6,2026-09-16,5479,Fix to_bjdata() emitting the Draft-3-only 'B' marker in default Draft-2 mode (#5479),1970.935,4018.060,11445.500,3079.409,3809.050,910.459,444.217,539.291,6851.407,833.755,1444.697,698.040,1626.601,1889.024,,,
|
||||
126,c41152e620,2026-09-16,5494,Fall back to plain-object encoding when to_bjdata()'s _ArrayType_ annotation is not a string (#5494),1979.481,4054.688,11734.292,3085.542,3819.351,916.992,445.126,539.870,6853.005,833.190,1457.166,665.391,1629.586,1888.734,,,
|
||||
127,e564136c22,2026-09-22,5465,Make diff() account for member order in ordered_json objects (#5465),1970.519,4063.744,11605.198,3087.497,3848.867,915.695,447.051,539.711,6835.172,841.402,1452.004,664.560,1640.751,1890.473,,,
|
||||
128,e485441123,2026-09-22,5466,Restore a duplicate key's prior value when the callback rejects its new value (#5466),2012.920,4099.265,11796.895,3156.818,3913.812,931.464,451.403,541.419,6981.041,846.536,1469.521,704.138,1633.327,1905.709,,,
|
||||
129,a2b19d6158,2026-09-22,5467,Honor allow_exceptions=false for excessive array/object size (out_of_range.408) (#5467),1996.478,4084.422,11734.208,3129.099,3850.854,923.499,446.555,539.379,6949.427,842.029,1453.166,694.200,1631.133,1888.865,,,
|
||||
130,d2c1a6a272,2026-09-22,5468,"Reject array insert(pos, first, last) iterators not pointing into an array (#5468)",1983.767,4066.651,11618.667,3128.505,3848.427,914.900,447.603,541.973,6915.265,844.307,1458.762,677.699,1638.789,1892.443,,,
|
||||
131,0b20b7e622,2026-09-22,5469,Reject MessagePack/BSON binary subtypes that don't fit their wire format (#5469),2010.548,4097.476,11681.218,3121.010,3866.146,925.619,448.533,540.786,6957.000,843.349,1463.518,658.302,1630.857,1902.522,,,
|
||||
132,1054b2097e,2026-09-23,5286,Speed up binary writing: value-type output sink + byte-swap number encoding (#5286),1989.739,4101.393,12034.438,3157.240,3853.987,910.115,449.084,555.970,6884.386,864.526,1471.905,656.635,1661.806,1926.233,,,
|
||||
133,ed513715a8,2026-09-24,5534,Document that a NUL byte in the input is treated as end of input (#5534),2016.236,4104.763,11906.323,3141.138,3936.240,916.611,455.397,562.053,6987.917,871.110,1475.622,657.877,1676.934,1936.557,,,
|
||||
134,56b3ee566c,2026-09-24,5389,Fix stack overflow when copying a deeply nested value (#5387) (#5389),1998.356,4051.206,11660.865,3101.107,3834.672,910.072,452.943,544.464,6908.974,849.212,1460.691,638.644,1650.749,1914.423,,,
|
||||
135,918da64657,2026-09-24,5542,Keep BJData ndarray annotations that would not survive a round trip as objects (#5542),2003.009,4042.969,11517.375,3095.122,3815.360,908.444,448.415,539.423,6911.041,840.044,1449.543,671.530,1651.709,1908.408,,,
|
||||
136,8699de3064,2026-09-24,5555,Stop allocating the BJData excluded-marker list per container (#5555),2001.718,4071.333,11686.427,3122.065,3796.757,900.895,447.123,539.918,6860.765,844.752,1444.435,646.608,1644.943,1879.295,,,
|
||||
137,2e91641de2,2026-09-24,5544,"Test JSON_BRACE_INIT_COPY_SEMANTICS for real, and fix one-element tuples under it (#5544)",2004.785,4083.914,11662.270,3119.602,3917.914,922.465,454.869,547.631,6987.234,853.010,1469.612,649.946,1672.246,1913.098,,,
|
||||
138,7c90ec2323,2026-09-24,5546,Hash deeply nested values without recursing per nesting level (#5546),1952.912,4071.159,11594.927,3117.497,3793.052,900.729,444.245,539.787,6854.406,841.264,1457.530,643.139,1638.578,1890.482,,,
|
||||
139,4daca40d7b,2026-09-24,5547,Merge deeply nested objects without recursing per nesting level (#5547),2008.226,4104.399,11619.542,3148.604,3918.175,921.207,457.191,547.553,6942.265,855.352,1464.974,651.924,1665.232,1915.869,,,
|
||||
140,01b53c8c15,2026-09-25,5552,Keep JSON_DIAGNOSTICS parent pointers of ordered_json members after erase() and update() (#5552),1979.354,4061.378,11603.480,3098.586,3875.258,919.125,455.911,546.269,6940.026,849.511,1461.751,648.841,1660.978,1917.254,,,
|
||||
141,abbe52d6de,2026-09-25,5344,Add JSON_PRECISE_STREAM_POSITION to leave the character that terminates a number in the stream (#5344),2001.170,4081.617,11653.531,3131.331,3876.208,915.153,453.436,546.720,6971.864,848.900,1463.182,647.946,1662.943,1906.246,,,
|
||||
142,02dd3e67f2,2026-09-25,5390,Fix stack overflow and exponential runtime when comparing nested values (#5390),1987.861,4074.039,11596.000,3161.284,3901.497,919.541,447.553,543.948,6910.162,845.668,1455.759,664.224,1652.074,1930.575,,,
|
||||
143,465407f3ce,2026-09-25,2818,Improve error message for const fields (#2818),1975.274,4118.565,11863.448,3130.541,3880.764,910.767,452.904,545.363,6906.890,843.118,1459.728,645.770,1654.265,1934.900,,,
|
||||
144,632a5812a8,2026-09-25,5272,Support zero-member types in NLOHMANN_DEFINE_TYPE_* macros (#4041) (#5272),1963.323,4021.526,11747.959,3102.006,3784.896,904.545,444.355,543.748,6840.604,841.416,1438.306,639.223,1649.816,1930.274,,,
|
||||
145,d19f7f5dce,2026-09-25,5185,Fix BSON conformance issue (#5185),1958.606,4048.536,11541.011,3086.805,3817.875,900.452,446.001,544.071,6824.323,837.078,1971.245,641.271,1651.209,1934.647,,,
|
||||
146,c60a0bc336,2026-09-25,5573,Allocate the deep copy's key scratch space with the provided allocator (#5573),1965.216,4021.459,11630.855,3074.078,3807.258,902.782,444.394,542.562,6919.969,840.942,1975.668,645.827,1637.429,1918.607,,,
|
||||
147,1e44262091,2026-09-25,5560,Make JSON_STRICT_NUL_HANDLING part of the ABI tag (#5560),1961.862,4069.617,11594.083,3117.500,3817.758,909.186,448.820,544.420,6845.802,844.016,1977.909,645.864,1651.269,1937.217,,,
|
||||
148,95e9a5931c,2026-09-25,5553,"Write BSON in linear time, without recursing per nesting level (#5553)",1965.832,4033.394,11589.364,3120.422,3792.091,905.110,446.984,543.328,6794.244,844.943,1991.659,640.188,1647.675,1928.562,,,
|
||||
149,fe4a544c7e,2026-09-27,5515,handled when size exceed uint32 (#5515),1998.244,4047.208,11755.209,3091.776,3815.000,908.733,447.990,546.295,6903.084,850.946,1993.351,645.487,1654.343,1933.385,,,
|
||||
150,4fa95d9810,2026-09-27,5583,Remove unreachable branches from the binary writer (#5583),1983.323,4038.331,11666.480,3092.841,3844.935,910.149,449.697,541.110,6840.583,830.604,1979.750,653.542,1650.670,1928.883,,,
|
||||
151,6178982b8d,2026-09-27,5582,Compare unordered objects by key below the nesting bound (#5582),1971.706,4073.498,11600.646,3132.700,3830.323,910.231,448.982,538.812,6836.770,846.149,2007.607,657.180,1653.089,1934.675,,,
|
||||
152,f7972970a4,2026-09-27,5584,Throw instead of writing MessagePack lengths beyond UINT32_MAX (#5584),1969.417,4013.021,11602.447,3083.552,3842.495,904.223,447.444,542.170,6862.735,839.628,2000.766,655.034,1653.006,1939.922,,,
|
||||
153,6bd106893a,2026-09-27,5559,Fix CBOR tag handling in cbor_tag_handler_t::store for non-binary items (#5559),1969.250,4034.693,11691.500,3119.171,3827.860,916.053,455.026,542.577,6886.360,839.718,2012.919,653.031,1651.090,1931.698,,,
|
||||
154,1e101ecac1,2026-09-27,2998,Add BON8 support (#2998),1975.804,4082.375,11658.542,3192.828,3758.141,907.029,444.920,556.470,6844.698,849.276,1977.153,649.181,1645.306,1920.836,,,
|
||||
155,9e1a09eec0,2026-09-28,5594,Name the key type when rejecting non-string CBOR/MessagePack map keys (#5594),2006.582,4151.784,11788.532,3156.156,3845.052,915.647,454.027,557.846,6814.282,864.094,2021.072,654.095,1663.051,1947.078,,,
|
||||
156,fc03b9912e,2026-09-28,5597,"Look up the locale decimal point at conversion time, not lexer construction (#5597)",2020.431,4172.916,12716.958,3196.958,3909.774,910.001,449.314,547.334,6900.968,852.306,2048.019,665.843,1696.937,1982.586,,,
|
||||
157,5b9ffae8bb,2026-09-30,5616,Move the float conversion chain out of the lexer (#5616),1992.332,4167.328,12638.573,3212.515,3842.885,906.649,446.941,539.674,6952.672,839.042,2021.057,695.813,1684.689,1967.216,,,
|
||||
158,d268eaa693,2026-09-30,5617,Convert floats with Eisel-Lemire when std::from_chars is unavailable (#5617),1987.608,4086.125,11507.062,3170.013,3830.425,898.856,445.077,542.854,6919.568,839.210,2021.918,666.925,1701.466,1951.211,,,
|
||||
159,65af260117,2026-09-30,5609,Move instead of deep-copy ordered_json values when an object grows (#5609),1998.981,4134.057,11592.855,3192.779,3863.005,904.702,446.575,539.685,6850.886,840.845,2035.646,680.331,1682.755,1968.744,,,
|
||||
160,6a8a7735ed,2026-09-30,5614,Do not throw in contains() for an empty array reference token (#5614),2008.447,4144.024,11612.176,3165.468,3842.060,905.045,443.941,539.755,6846.042,846.248,1998.713,669.752,1684.717,1953.487,,,
|
||||
161,0050d0f7a4,2026-09-30,5637,Share one nesting depth limit between all bounded descents (#5637),2021.078,4170.581,11589.886,3224.963,3937.021,906.411,448.033,541.177,6911.391,848.641,2040.978,670.005,1703.593,1984.639,,,
|
||||
162,68beba727c,2026-09-30,5679,Fix from_json() for enums with underlying type bool (#5679),1986.468,4139.033,11632.833,3201.351,3798.006,888.464,438.471,535.903,6843.110,836.030,1996.109,685.053,1672.430,1940.598,,,
|
||||
163,fc4c9c3446,2026-09-30,5680,Fix clear() to also reset the subtype of a binary value (#5680),1972.561,4094.867,11540.157,3155.722,3833.925,893.243,445.764,539.739,6848.562,843.068,2016.293,664.788,1685.759,1965.342,,,
|
||||
164,678fd3017b,2026-09-30,5681,Fix element path for map/unordered_map JSON_DIAGNOSTICS errors (#5681),2014.783,4164.471,11563.614,3219.865,3891.917,892.727,445.945,542.044,6900.807,844.422,2034.323,669.901,1688.051,1981.601,,,
|
||||
165,6d7845d207,2026-09-30,5683,Fix deprecated json_pointer/string operator== warning in value() (#5683),1965.197,4105.789,11501.364,3157.544,3800.289,898.122,445.399,539.685,6900.433,834.541,2000.133,652.354,1670.945,1960.876,,,
|
||||
166,42f89e3130,2026-09-30,5684,Let to_json(std::optional<T>) propagate exceptions from T's to_json (#5684),2016.899,4156.430,11476.489,3216.315,3895.245,908.714,444.300,541.764,6923.422,839.459,2018.934,672.859,1689.306,1987.428,,,
|
||||
167,6218aa212b,2026-09-30,5687,Throw std::length_error for operator[](SIZE_MAX) instead of corrupting the array (#5687),1989.158,4149.156,11547.229,3193.015,3845.187,905.308,446.389,541.290,6853.266,843.028,2037.245,661.213,1681.390,1966.649,,,
|
||||
168,1151826508,2026-09-30,5691,Take diff()'s fast path unless the object type reorders members (#5691),1991.280,4147.341,11570.312,3171.182,3847.333,904.510,441.250,539.803,6885.776,836.303,2018.693,665.307,1685.990,1970.057,,,
|
||||
169,e444a66276,2026-09-30,5693,Copy values before inserting an initializer list into an array (#5693),2000.774,4175.507,11546.979,3189.357,3841.169,897.455,442.384,539.493,6839.688,836.213,2014.519,667.390,1685.418,1968.991,,,
|
||||
170,bfea6f36d3,2026-09-30,5694,Fix to_msgpack() reading the inactive number union member (#5694),1997.465,4144.279,11549.781,3224.287,3855.120,899.475,441.995,539.924,6903.776,839.550,2019.396,664.487,1688.249,1954.211,,,
|
||||
171,5b11a0282c,2026-09-30,5697,Exchange the CustomBaseClass subobject in basic_json::swap() (#5697),1987.983,4074.349,11483.114,3174.632,3841.604,893.256,438.279,535.885,6866.641,834.328,1996.396,660.828,1676.300,1936.210,,,
|
||||
172,44a88d85be,2026-09-30,5698,Fix NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json message (#5698),1972.237,4125.945,11373.917,3158.716,3810.039,890.097,438.075,534.577,6867.432,842.045,2028.150,664.206,1681.353,1936.231,,,
|
||||
173,bfe0f32d71,2026-09-30,5699,Fix std::terminate and null pointer access in input_stream_adapter (#5699),2014.371,4159.779,11667.416,3200.425,3876.135,911.716,448.788,543.198,6932.657,852.397,2056.197,668.764,1699.573,1984.479,,,
|
||||
174,4bb1b14b06,2026-09-30,5702,Trim the compiler-appended NUL from wide/UTF string literals too (#5702),1979.723,4105.685,11603.562,3180.932,3846.698,906.188,443.969,534.534,6837.479,840.588,2006.043,654.851,1672.289,1965.408,,,
|
||||
175,5bd766aa50,2026-09-30,5703,Move to_bson's binary subtype check into calc_bson_sizes (#5703),1999.606,4183.386,11588.646,3192.771,3844.425,900.169,446.795,541.406,6888.114,847.107,2022.637,663.480,1686.702,1974.777,,,
|
||||
176,6ae17630a4,2026-09-30,5705,"Reject integral keys for contains(), find(), and count() at compile time (#5705)",2000.405,4157.120,11551.656,3197.417,3891.646,903.558,448.544,541.553,6914.203,848.561,2042.578,663.661,1691.910,1974.341,,,
|
||||
177,7fd6895788,2026-09-30,5706,Hide a discarded container's content from the parser callback (#5706),1971.987,4075.362,11463.219,3164.909,3797.453,889.534,443.974,535.026,6857.323,835.793,2025.343,651.970,1687.670,1951.428,,,
|
||||
178,66877675b1,2026-09-30,5719,"Check the iterator range for binary values in basic_json(first, last) (#5719)",1970.369,4104.886,11534.635,3168.601,3796.291,897.271,444.655,538.917,6826.990,842.445,2016.962,650.099,1673.940,1953.693,,,
|
||||
179,2ea6d8c127,2026-09-30,5720,Require the found key to equal the looked-up key when comparing objects (#5720),2015.556,4188.886,11567.125,3251.890,3863.818,903.970,448.691,540.422,6912.255,843.774,2044.479,653.832,1676.634,1951.959,,,
|
||||
180,67435c9c7e,2026-09-30,5721,Give a deep copy its type only after its container exists (#5721),1994.257,4160.658,11600.553,3218.367,3880.128,900.769,449.260,541.607,6899.448,841.635,2043.909,666.759,1694.646,1974.861,,,
|
||||
181,6fc0d501f3,2026-09-30,5610,Move the user-defined string literals to <nlohmann/json_literals.hpp> and add JSON_NO_AUTOMATIC_UDLS (#5610),2021.715,4187.888,11647.594,3209.388,3925.060,911.591,450.961,544.303,6975.265,845.109,2049.853,670.295,1697.019,1987.428,,,
|
||||
182,fdcc569eee,2026-09-30,5692,Use only documented StringType members in json_pointer (#5692),1965.264,4147.273,11378.188,3159.364,3787.758,889.399,447.397,535.062,6809.698,835.116,2015.202,656.241,1689.072,1955.238,,,
|
||||
183,6a073dbae4,2026-09-30,5695,Give operator>> a strong exception-safety guarantee (#5695),2010.979,4211.982,11698.218,3205.401,3897.172,898.499,445.961,545.225,6898.870,847.042,2051.316,664.716,1706.401,1981.247,,,
|
||||
184,3b6ae43c53,2026-09-30,5598,Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions (#5598),2025.122,4195.468,11682.199,3204.529,3924.068,904.766,448.209,544.669,7041.276,849.103,2047.488,665.592,1695.987,1984.755,,,
|
||||
185,7d7055ec50,2026-09-30,5723,Fix stack overflow converting deep values between specializations (#5723),1985.310,4117.099,11457.052,3157.591,3832.175,895.910,442.225,535.237,6864.375,833.653,2001.760,679.826,1674.819,1956.998,,,
|
||||
186,35802e78d6,2026-09-30,5735,Remove dead Makefile targets; document macro_builder; tidy serve_header (#5735),2004.498,4163.065,11590.594,3184.810,3902.229,906.494,447.394,539.542,6923.969,845.596,2044.457,666.187,1692.019,1977.030,,,
|
||||
187,c261578431,2026-09-30,5730,Deduplicate binary reader/writer helpers and fix stale comments (#5730),1968.723,4154.789,11441.718,3160.367,3870.578,889.545,443.139,535.314,6850.886,837.281,2024.650,660.842,1691.628,1978.000,,,
|
||||
188,1d675cdb46,2026-09-30,5733,Fix CI jobs that check less than they claim; move arm64 to GitHub (#5733),1995.704,4206.185,11691.125,3227.622,3966.104,909.748,449.770,541.566,6951.938,852.506,2009.592,663.701,1686.265,1983.285,,,
|
||||
189,a32f61eb98,2026-09-30,5678,Fix update() and merge_patch() when the argument is *this or one of its members (#5678),2014.810,4157.101,11636.135,3210.326,3924.659,899.344,448.133,541.371,6913.401,841.487,2038.263,667.515,1697.503,1980.686,,,
|
||||
190,18dd5663b0,2026-10-01,5548,Diff deeply nested values without recursing per nesting level (#5548),1990.931,4152.500,11469.697,3204.740,3985.593,903.248,448.981,540.974,6929.740,847.493,2040.504,665.352,1698.903,1981.438,,,
|
||||
191,3926fcaac3,2026-10-01,5729,"Deduplicate serializer dump code; fix stale includes, docs, and lint (#5729)",1999.556,4178.489,11581.000,3208.657,3876.755,891.669,452.445,538.525,6893.078,846.721,2042.010,662.154,1689.653,1975.503,,,
|
||||
192,cff0a61369,2026-10-01,5731,Share DOM SAX position handling; fix stale parser and lexer comments (#5731),2017.231,4112.604,11588.291,3157.047,3890.343,902.329,458.713,539.539,7020.568,847.995,2073.873,654.562,1696.823,1978.381,,,
|
||||
193,e400780533,2026-10-01,5745,Re-amalgamate single_include (#5745),1980.338,4100.659,11418.854,3166.896,3835.432,885.298,452.886,538.053,6888.203,824.666,2031.410,650.846,1668.952,1949.107,,,
|
||||
194,6aec1a085f,2026-10-02,5677,Report BON8 input that ends after a UTF-8 lead byte as truncated (#5677),2003.321,4099.066,11614.364,3159.029,3849.857,899.995,459.542,539.436,6904.474,843.221,2071.503,652.303,1685.702,1972.556,,,
|
||||
195,4d46bce4e1,2026-10-02,5750,Fix CI on develop (#5750),1962.685,4025.677,11277.718,3103.052,3785.213,894.610,448.583,533.887,6870.062,834.856,2020.231,658.339,1674.874,1954.242,,,
|
||||
196,63c10a51fc,2026-10-02,5638,"Review and extend the documentation, and check it in CI (#5638)",1968.954,4036.851,11425.135,3104.359,3797.852,902.519,451.067,537.668,6910.375,852.438,2043.889,674.938,1701.314,1971.711,,,
|
||||
197,6d0867a85f,2026-10-02,5751,Make comparisons with scalars noexcept only when the conversion is (#5751),2008.360,4091.453,11376.562,3144.575,3820.110,903.850,455.980,538.035,6851.885,841.549,2010.128,667.182,1690.586,1970.957,,,
|
||||
198,d11e89471b,2026-10-04,5606,Assert on missing array indices in const operator[] and document the JSON pointer case (#5606),2000.121,4075.695,11475.520,3139.456,3837.211,900.437,453.703,538.895,6921.432,845.064,2027.417,663.969,1679.148,1964.082,,,
|
||||
199,df27cc3d4c,2026-10-04,5682,Add scalar-on-left overloads for legacy discarded comparisons in C++20 (#5682),2010.838,4092.432,11495.625,3125.726,3873.167,911.281,456.807,538.386,6911.630,844.451,2033.630,688.219,1691.407,1971.697,,,
|
||||
200,6f2048cd5d,2026-10-04,5685,Accept lvalues in ordered_map::emplace's value parameter (#5685),1999.816,4095.006,11445.740,3136.685,3924.146,918.692,458.336,542.423,6968.520,848.783,2037.096,667.772,1708.274,2002.449,,,
|
||||
201,0d01d6ae90,2026-10-04,5686,Classify leaves with operator<=> itself past the nesting bound (#5686),1983.320,4116.981,11466.250,3192.969,3923.208,914.596,456.625,539.558,6975.537,849.252,2056.035,701.221,1716.493,1983.908,,,
|
||||
202,b730946432,2026-10-04,5689,Fix key types convertible to std::string_view breaking lookups (#5689),1990.288,4060.487,11377.709,3107.537,3803.857,892.191,451.727,538.045,6896.480,844.989,2018.884,658.649,1676.566,2023.638,,,
|
||||
203,49cd427196,2026-10-04,5690,"Copy-construct the base class of a deep copy's elements, not assign it (#5690)",1983.320,4033.156,11333.843,3138.547,3882.878,894.785,454.473,538.337,6918.619,841.205,2072.151,655.193,1693.871,1977.288,,,
|
||||
204,756b28c2b8,2026-10-04,5696,Keep a NUL byte ending a // comment as the end of input (#5696),1985.931,4099.331,11579.875,3148.560,3872.422,896.276,451.436,536.774,6901.156,845.631,2014.820,648.054,1685.199,1971.762,,,
|
||||
205,1edf0ef041,2026-10-04,5700,"Fix value(json_pointer, default) aborting under JSON_NOEXCEPTION (#5700)",1987.233,4076.133,11442.625,3124.099,3888.688,898.266,454.349,539.423,6950.140,852.803,2030.279,654.586,1691.751,1978.197,,,
|
||||
206,a212d3b2e4,2026-10-04,5722,Preserve the object comparator's state in a deep copy past the nesting bound (#5722),2000.138,4113.471,11391.854,3151.006,3866.904,905.695,455.384,539.504,6929.818,842.213,2029.619,674.438,1697.044,1983.856,,,
|
||||
207,1df1e8a845,2026-10-04,5591,Make cross-string-type basic_json conversion explicit without implicit conversions (#5591),2000.533,4107.994,11370.989,3160.854,3881.635,897.877,455.201,540.307,6927.167,840.130,2053.458,664.118,1697.618,1982.876,,,
|
||||
208,38a2db260c,2026-10-04,5728,Remove dead metaprogramming and duplicated code in traits and pointers (#5728),1971.450,4040.828,11319.270,3109.521,3819.505,903.606,451.137,538.725,6825.640,843.951,2016.652,663.160,1684.596,1958.896,,,
|
||||
209,c5650eaa3c,2026-10-04,5704,Reject malformed UTF-16/UTF-32 units in wide-string input (#5704),2006.689,4133.594,11469.209,3180.930,3881.633,902.924,456.572,540.557,6992.385,850.474,2025.267,652.367,1680.025,1957.468,,,
|
||||
210,40021f38fb,2026-10-04,5589,Add basic_json::as_base_class and document name conflicts with custom base classes (#5589),2012.673,4147.193,11453.250,3167.448,3892.542,910.149,457.238,541.642,6998.084,852.247,2049.759,652.868,1688.229,1972.508,,,
|
||||
211,73e9eae3c1,2026-10-04,5746,Add an error_handler parameter for UTF-8 to the binary readers and writers (#5746),2013.845,4130.237,11456.041,3135.688,3818.956,892.111,449.408,538.308,6825.213,835.872,1495.468,697.054,1679.760,1970.285,,,
|
||||
212,d8d47be4a5,2026-10-04,5754,Fix CI on develop after merging the ready-to-merge PRs (#5754),2013.191,4119.948,11573.656,3173.029,3941.703,912.201,459.208,541.264,7013.364,848.908,1514.681,699.273,1685.391,1984.652,,,
|
||||
213,6b4b825af2,2026-10-04,5607,Handle numbers that do not fit narrow number types in the binary readers (#5607),2009.190,4044.127,11362.677,3127.688,3827.841,892.131,449.386,534.731,6915.360,829.562,1487.640,697.206,1688.237,1952.157,,,
|
||||
214,8c1f60a45e,2026-10-04,5600,Store maps with enum keys as objects (opt-in) (#5600),2008.560,4128.059,11523.011,3187.763,3843.177,912.520,456.427,537.514,6859.010,839.685,1501.515,696.508,1688.848,1968.910,,,
|
||||
215,c5a7a4b46d,2026-10-04,5688,"Add deprecated from_bon8/from_bjdata(ptr, len) overloads (#5688)",2030.310,4108.505,11412.907,3141.836,3899.435,904.756,455.298,541.069,6926.151,846.240,1504.193,700.820,1693.983,1987.713,,,
|
||||
216,23d3b373e1,2026-10-04,5755,Add JSON_DELETE_DEPRECATED_FUNCTIONS to delete the deprecated functions (#5755),2018.708,4106.015,11533.729,3134.945,3826.409,899.623,452.833,538.544,6846.443,830.555,1509.060,705.724,1692.819,1971.476,,,
|
||||
217,8a142bc436,2026-10-06,5764,"Fix CI on develop after #5600, #5607, and #5755 (#5764)",2017.533,4151.854,11526.334,3195.240,3884.953,907.457,456.697,540.114,6891.136,844.145,1517.241,699.051,1690.344,1972.104,,,
|
||||
218,5379e04ce4,2026-10-06,5761,Throw type_error.321 when serializing discarded values to binary formats (#5761),1999.156,4055.300,11427.521,3153.581,3836.060,891.927,455.413,540.938,6883.093,853.094,1510.099,701.888,1686.695,1982.806,,,
|
||||
219,0a365865f9,2026-10-06,5762,Make basic_json destruction allocation-free and non-recursive (#5762),2024.289,4081.646,10719.428,3112.958,3900.503,924.900,462.081,540.765,6965.453,850.019,1511.381,669.802,1620.269,1912.078,,,
|
||||
220,5ecb704f6b,2026-10-06,5592,Speedup; check for the expected separator before the lexer's token switch (#5592),1920.428,3801.979,10139.250,2891.862,3833.159,823.859,451.951,540.310,6885.672,843.570,1512.778,668.793,1608.501,1885.206,,,
|
||||
221,6d4543e743,2026-10-06,5767,Fix destroy() for ObjectTypes without reverse iteration (#5767),1929.030,3843.266,10232.541,2911.458,3926.867,830.030,450.002,542.043,6938.890,846.589,1515.211,675.264,1622.245,1904.006,,,
|
||||
222,9b179cee1e,2026-10-06,5770,Handle all value_t enumerators in has_no_children() (#5770),1931.275,3794.497,10155.125,2891.927,3871.831,829.432,446.176,535.126,6909.625,833.114,1498.945,677.571,1615.785,1884.043,,,
|
||||
223,69874e4544,2026-10-06,5760,Fix NUL bytes in UBJSON/BJData high-precision numbers (#5760),1924.896,3853.081,10247.750,2926.515,3872.041,835.227,453.025,541.002,6919.037,842.240,1521.169,674.487,1607.441,1880.884,,,
|
||||
224,162e13b86f,2026-10-06,5758,Add with_*_t alias templates to create basic_json types with changed template parameters (#5758),1938.268,3842.126,10289.968,2914.104,3962.414,834.967,455.536,543.630,6969.266,850.082,1530.064,678.054,1635.303,1916.763,,,
|
||||
225,21a69230bd,2026-10-06,5585,Create a value before giving it its type (#5585),1918.165,3829.354,10247.656,2914.619,3874.909,832.287,451.252,543.791,6873.995,839.514,1521.088,699.604,1615.742,1894.449,,,
|
||||
226,ff6f3d7d4a,2026-10-07,5766,Reject nested indefinite-length CBOR string chunks (#5766),1926.074,3868.810,10256.823,2919.802,3957.807,832.129,457.241,543.640,7024.745,847.770,1522.612,705.623,1634.212,1918.402,,,
|
||||
227,1c754cfe31,2026-10-07,5701,Copy a pair-shaped array value under JSON_BRACE_INIT_COPY_SEMANTICS (#5701),1930.652,3828.195,10263.927,2921.570,3901.404,832.628,455.652,541.701,6909.037,843.563,1512.309,704.354,1623.254,1909.917,,,
|
||||
228,24dd7c63f0,2026-10-07,5777,Re-amalgamate after #5740 (#5777),1908.632,3833.930,10278.146,2905.443,3935.422,838.465,454.491,545.605,6905.047,839.087,1519.816,709.223,1618.643,1886.706,,,
|
||||
229,30e542e52a,2026-10-07,5776,Declare the namespace-scope constants in to_chars.hpp inline (#5776),1934.934,3823.724,10229.636,2916.698,3929.565,829.102,452.279,543.038,6951.995,837.059,1524.049,720.722,1619.823,1903.938,,,
|
||||
230,367336c83d,2026-10-07,5779,Fix CI on develop after #5585 (#5779),1928.921,3780.927,10153.395,2883.604,3877.750,824.488,451.999,543.662,6927.395,835.495,1506.387,694.058,1622.903,1907.732,,,
|
||||
231,069ace74af,2026-10-07,5707,"Round-trip BJData ND-array annotations exactly (single precision, key order) (#5707)",1937.387,3843.716,10184.302,2923.323,3936.570,827.610,456.123,543.169,6907.756,847.020,1515.229,696.202,1626.001,1901.142,,,
|
||||
232,43fe8928e1,2026-10-07,5781,Stop binary writers overflowing the stack on deep values (#5781),1961.046,3868.274,10300.573,2899.792,3982.526,845.594,461.395,543.298,7059.093,846.696,1522.728,697.717,1623.846,1921.370,,,
|
||||
233,a5f5d3059b,2026-10-07,5772,Make std::hash<basic_json> consistent with operator== for numbers (#5772),1949.220,3857.159,10170.427,2890.052,3981.349,840.234,459.334,541.947,6953.786,843.495,1509.713,703.339,1627.086,1911.653,,,
|
||||
234,a269794db7,2026-10-08,5782,Use MSVC intrinsics for full multiplication (#5782),1931.869,3817.742,10159.666,2902.820,3903.263,840.740,455.827,540.621,6884.562,843.272,1513.776,702.028,1614.459,1901.008,,,
|
||||
235,69a0c1b82c,2026-10-09,5328,Avoid allocating temporary basic_json for cbor and msgpack object keys (#5328),1909.579,3777.560,10065.682,2852.732,3897.659,833.289,459.856,540.631,6882.354,833.998,1498.288,314.059,1609.343,1906.714,,,
|
||||
236,374dfe4f0f,2026-10-09,5791,Keep converted object keys alive while writing UBJSON and BJData (#5791),1911.274,3827.188,10159.553,2886.568,3890.388,833.632,459.800,542.649,6954.547,838.507,1509.324,314.357,1613.655,1892.838,,,
|
||||
237,44e8597701,2026-10-09,5792,Flatten deeply nested values without recursing per nesting level (#5792),1940.103,3811.779,10139.396,2865.050,3874.896,835.001,459.686,544.065,6866.943,836.862,1496.298,314.617,1614.837,1891.741,,,
|
||||
238,2913e96433,2026-10-09,5793,Unflatten in time and memory linear in the pointer depth (#5793),1908.453,3785.099,10262.147,2878.961,3920.657,845.619,459.806,543.998,6874.813,832.659,1486.901,312.175,1589.620,1863.981,,,
|
||||
239,84ee12a67c,2026-10-09,5797,Make UTF8_ACCEPT/UTF8_REJECT inline variables to avoid TU-local exposure in modules (#5797),1922.691,3792.849,10162.656,2871.562,3887.719,836.308,456.522,542.577,6912.807,840.369,1497.447,313.683,1609.988,1899.591,,,
|
||||
240,1649d9eda4,2026-10-11,5783,Use and extend the detail helpers to remove duplicated code (#5783),1916.258,3804.242,10297.344,2913.118,3847.662,836.519,453.270,538.750,6953.015,832.774,1506.068,324.715,1596.974,1875.878,,,
|
||||
241,2cca04ae6f,2026-10-11,5800,Report one-character non-numeric array indices like longer ones (#5800),1932.327,3803.750,10135.438,2881.041,3894.622,840.016,458.569,538.037,6842.948,829.444,1499.722,324.811,1607.194,1875.851,,,
|
||||
242,74a03dec84,2026-10-11,5802,Throw type_error.321 for discarded values in to_bon8 (#5802),1924.695,3814.854,10084.239,2873.180,3848.498,839.406,450.575,534.181,6893.005,834.300,1503.369,324.389,1607.323,1887.871,,,
|
||||
243,e8b747e4bc,2026-10-11,5808,Re-amalgamate single_include after #5795 and #5806 (#5808),1937.995,3840.622,10221.990,2896.024,3885.568,834.394,458.874,539.771,6906.182,839.793,1517.689,324.800,1609.838,1890.885,,,
|
||||
244,40a62947d3,2026-10-12,4965,support JSON Merge Patch (RFC 7396) diff creation (#4965),1932.021,3822.188,10248.416,2924.560,3980.331,842.462,459.010,540.237,6978.526,838.941,1529.508,326.435,1636.153,1917.472,,,
|
||||
245,f23830b65e,2026-10-13,5809,Derive the lexer position lazily for seekable input (#5809),1814.075,3368.028,9974.755,2807.532,3943.229,647.639,457.018,551.206,6954.166,843.355,1522.762,315.716,1618.953,1903.816,,,
|
||||
246,aa9620fb15,2026-10-13,5810,Skip the indentation after a newline 8 bytes at a time (#5810),1719.629,2959.344,10139.771,2799.555,3939.292,592.867,465.821,545.858,6968.068,849.167,1519.774,315.385,1629.981,1907.253,,,
|
||||
247,e839bbd1c0,2026-10-13,5813,"Export client-facing headers from json.hpp for IWYU / include-cleaner, and check clients in CI (#5813)",1725.742,2949.070,10136.603,2821.591,3919.927,589.957,463.642,544.851,6987.427,843.151,1517.562,314.425,1619.671,1903.613,,,
|
||||
248,5b4c8f9b00,2026-10-14,5738,"Speed up the lexer: own float parser, string scan, and \u table (#5738)",1615.668,2934.565,8763.651,2794.503,3928.286,559.107,374.921,516.391,6937.140,815.776,1513.238,325.043,1625.226,1912.905,,,
|
||||
249,91a7a94cc6,2026-10-14,5634,"Write doubles with the shortest digits (Żmij), digits in registers (#5634)",1613.126,2929.599,8708.599,2783.954,3874.248,548.449,363.632,468.127,2421.176,745.466,1511.406,323.743,1614.195,1900.392,,,
|
||||
250,a6e9785ab6,2026-10-15,5831,Look up the key only once in the callback parser's key() (#5831),1589.309,2938.557,8798.823,2767.872,3882.154,547.301,364.257,467.833,2395.851,744.716,1506.830,316.192,1623.771,1899.458,,,
|
||||
251,0c4e7c103c,2026-10-15,5834,Make flatten() linear for ordered_json (#5834),1625.754,2936.203,8755.088,2793.081,3879.740,557.529,366.745,468.359,2418.388,746.210,1524.325,315.954,1614.677,1898.544,,,
|
||||
252,0a4b3a84ee,2026-10-15,5836,"Speed up JSON pointer parsing, formatting, comparison and lookup (#5836)",1622.914,2915.901,8819.073,2783.990,3922.758,558.429,366.216,470.019,2427.606,747.168,1526.881,316.972,1625.611,1912.601,,,
|
||||
253,6ba53e63dd,2026-10-15,5833,Speed up array-to-container from_json (#5833),1626.155,2920.747,8777.989,2782.870,3988.206,560.154,367.695,469.892,2427.262,749.301,1529.474,316.399,1631.810,1915.217,,,
|
||||
254,ca7740fef2,2026-10-15,5837,Move elements when converting rvalue containers to JSON (#5837),1615.747,2928.778,8765.792,2773.062,3926.456,561.034,367.498,469.807,2424.344,748.423,1523.215,316.339,1624.374,1894.455,,,
|
||||
255,4530d9681c,2026-10-15,5832,Fix quadratic parent updates for ordered_json with JSON_DIAGNOSTICS (#5832),1618.937,2911.378,8794.094,2763.191,3886.974,555.789,366.475,469.275,2415.231,746.755,1512.590,315.856,1618.226,1899.284,,,
|
||||
256,91869983a0,2026-10-15,5840,Make the value lifecycle inline-friendly (#5840),1595.075,2832.274,8420.390,2690.050,3876.841,555.209,366.118,469.783,2424.335,747.931,1485.914,314.048,1549.787,1775.823,,,
|
||||
257,6a27b9acb2,2026-10-15,5838,Construct remaining hot-path exceptions out of line so core functions inline (#5838),1589.535,2824.360,8466.755,2699.690,3888.990,557.917,364.879,471.601,2422.995,746.543,1498.371,314.978,1539.656,1797.752,,,
|
||||
258,4f11512641,2026-10-15,5835,"Speed up container destruction, iterator access and diff() (#5835)",1515.750,2714.756,8639.213,2574.698,3805.860,561.827,366.793,469.680,2421.769,748.727,1383.744,317.248,1446.525,1705.789,,,
|
||||
259,ed86019a21,2026-10-15,5839,Move binary reader error construction out of line (#5839),1507.907,2766.774,8597.870,2622.289,3767.638,553.026,362.644,468.482,2408.731,744.936,1362.080,324.833,1445.531,1703.216,,,
|
||||
260,6261d1e432,2026-10-15,5842,Construct the JSON Patch exceptions out of line (#5842),1532.015,2756.867,8670.677,2617.989,3869.133,558.865,365.834,469.932,2435.279,750.295,1380.628,327.010,1453.340,1705.232,,,
|
||||
261,ce28c722bc,2026-10-15,5815,Allow the same type for number_integer_t and number_unsigned_t (#5815),1533.045,2775.807,8543.755,2615.412,3776.721,553.127,365.866,471.174,2433.384,745.309,1372.372,328.405,1452.848,1716.649,,,
|
||||
262,91b9ee2602,2026-10-15,5829,Update cppcheck to 1.5.2 (Cppcheck 2.20) and fix its new findings (#5829),1516.450,2748.961,8571.521,2599.870,3807.744,557.303,367.220,472.209,2421.389,743.889,1379.405,326.087,1451.926,1710.506,,,
|
||||
263,dcb96e82fb,2026-10-15,5822,Escape characters below 0x60 from a table straight into the write buffer (#5822),1525.777,2734.963,8524.771,2588.289,3790.726,557.907,360.057,463.574,2430.626,743.382,1375.816,325.308,1439.947,1695.307,,,
|
||||
264,b41228c227,2026-10-15,5843,Fix AppVeyor failures from the Zmij double writer (#5843),1497.922,2690.614,8406.906,2582.482,3726.195,548.374,352.932,459.663,2398.953,737.639,1347.507,322.827,1429.640,1682.775,,,
|
||||
265,4da73dc5ff,2026-10-15,5858,Fix compiler warnings on develop from the API performance stack (#5858),1523.138,2731.825,8474.073,2593.149,3782.769,553.758,359.180,462.915,2380.246,739.049,1346.755,324.909,1441.408,1698.043,,,
|
||||
266,5683f5e024,2026-10-15,5859,Define less_general() only without three-way comparison (#5859),1504.689,2739.172,8603.693,2605.159,3797.057,560.213,358.865,464.429,2423.456,742.207,1374.000,326.702,1447.488,1712.379,,,
|
||||
267,cd6b428ef0,2026-10-16,5860,Fix CI failures on develop from the API performance stack (#5860),1510.160,2732.695,8564.510,2603.242,3810.518,556.015,362.409,466.047,2437.364,745.153,1377.439,325.753,1444.892,1699.255,,,
|
||||
268,cc8334113c,2026-10-19,5866,Do not use Qt's keyword macros as identifiers (#5866),1498.858,2732.644,8535.328,2587.258,3787.993,548.267,362.607,464.487,2403.147,735.633,1368.831,323.997,1442.709,1686.963,,,
|
||||
269,4da932f518,2026-10-19,5828,Make parsing from std::istream and FILE* fast (#5828),1499.289,2723.605,8397.787,2597.237,1956.330,553.182,363.501,458.898,2397.342,733.054,1362.816,320.346,1429.314,1698.294,,,
|
||||
270,122d718330,2026-10-21,5620,"Add json_document and json_view: node index, parser, and document (#5620)",1520.651,2751.099,8527.135,2588.494,1994.466,560.384,362.257,461.917,2393.611,741.198,1362.167,328.620,1441.211,1691.238,230.700,389.375,976.277
|
||||
271,43e97b629b,2026-10-21,5622,"Add element access, iteration, values, and JSON pointers to json_view (#5622)",1493.875,2687.307,8383.354,2567.078,1986.311,547.934,353.938,462.380,2400.331,737.098,1374.560,322.012,1445.504,1686.421,231.353,386.679,958.441
|
||||
272,4c3a3eb5b5,2026-10-21,5624,Add dump() and comparisons to json_view (#5624),1502.926,2714.747,8522.161,2608.565,2001.856,552.014,359.510,462.656,2393.110,732.091,1366.524,324.313,1442.119,1682.564,228.836,393.082,976.976
|
||||
273,3ff37ead75,2026-10-21,5628,Scan json_view strings with SIMD and index large objects (#5628),1514.580,2728.619,8406.562,2609.758,2041.176,556.017,357.330,462.573,2383.158,733.939,1368.057,324.391,1442.711,1700.884,177.833,367.806,950.071
|
||||
274,823eee3b59,2026-10-21,5630,"Add editable json_documents: set, push_back, insert, and erase (#5630)",1498.134,2754.810,8537.062,2588.474,1994.441,556.670,353.931,463.646,2392.987,740.023,1357.930,324.129,1441.622,1698.022,181.404,376.470,962.253
|
||||
275,4971200b54,2026-10-21,5632,Add images of json_documents: save() and load() (#5632),1494.231,2681.211,8425.834,2543.276,1984.849,548.146,354.762,460.440,2414.747,734.679,1363.841,321.349,1421.806,1670.134,177.777,368.631,949.292
|
||||
276,4155e2938f,2026-10-21,5633,Write json_view's dump() without a call or conversion per token (#5633),1500.247,2712.357,8612.193,2597.211,2012.860,558.559,359.889,462.371,2412.896,739.048,1372.456,324.070,1441.546,1697.571,180.320,371.514,954.088
|
||||
277,08d7fbb0a1,2026-10-21,5874,Read FILE* input with std::fgetc under MemorySanitizer (#5874),1543.124,2758.211,8565.730,2584.453,2046.255,558.522,358.865,464.542,2421.435,743.715,1374.005,324.687,1462.572,1700.819,180.714,372.601,965.361
|
||||
278,0cbe95ffa2,2026-10-21,5824,"Speed up writing CBOR and MessagePack, above all integer arrays (#5824)",1501.550,2706.534,8707.120,2584.807,2039.728,551.688,360.692,466.024,2397.182,742.777,1361.847,201.488,1429.223,1682.436,178.641,371.038,946.389
|
||||
279,bd5227c2ec,2026-10-21,5805,Fix silent wrong results for custom number types (#5805),1511.036,2733.325,8786.406,2588.906,2000.483,553.456,360.458,465.989,2398.381,743.338,1370.524,201.168,1444.051,1701.345,179.776,372.557,954.733
|
||||
280,e13e976801,2026-10-21,5851,Accumulate number digits while scanning them (#5851),1501.737,2667.570,7762.365,2523.289,1987.518,545.368,359.336,462.056,2407.652,739.226,1368.104,200.632,1440.390,1688.117,178.721,374.278,956.353
|
||||
281,5e13f834c1,2026-10-21,5852,Copy the text of float tokens only when a SAX handler asks for it (#5852),1512.318,2655.312,7314.354,2515.044,2019.288,547.993,362.038,463.788,2410.262,745.839,1364.898,208.969,1450.422,1713.902,179.198,371.996,968.699
|
||||
282,e9970066c5,2026-10-21,5853,"Scan strings with SSE2, SSSE3, or NEON (#5853)",1488.705,2654.404,7339.589,2551.050,2015.716,486.719,341.381,475.591,2434.369,756.973,1376.754,208.797,1449.981,1706.044,182.358,379.153,968.355
|
||||
283,fa37b952df,2026-10-21,5854,Match literals without a stack array and keep parser states in bytes (#5854),1471.894,2619.164,7285.000,2485.883,1949.380,471.534,347.785,475.287,2413.552,751.487,1374.254,207.522,1443.177,1699.611,181.643,377.971,977.268
|
||||
284,52fecc1fab,2026-10-21,5855,Move object keys into the value when parsing (#5855),1392.599,2628.688,7362.562,2485.293,1882.663,471.968,339.711,473.663,2414.903,751.376,1319.857,200.185,1448.057,1705.675,179.410,371.865,963.306
|
||||
285,6aefd8c662,2026-10-21,5878,Copy short printable-ASCII strings without starting the scanner (#5878),1399.384,2664.401,7232.557,2535.425,1922.431,470.185,320.230,418.440,2446.082,696.786,1317.889,201.955,1447.217,1701.135,180.860,376.217,968.215
|
||||
286,7c26e99ac5,2026-10-21,5879,Copy ASCII strings in the view's dump with ensure_ascii (#5879),1361.839,2610.182,7187.115,2471.708,1853.592,464.274,313.821,414.316,2388.840,687.851,1318.253,200.399,1434.986,1697.487,178.601,368.595,947.799
|
||||
287,3e031b06a5,2026-10-21,5876,"Use standard library helpers where available, with C++11 fallbacks (#5876)",1381.599,2592.122,7336.719,2499.994,1848.434,467.895,315.257,415.788,2430.769,692.250,1311.164,200.424,1444.303,1698.311,180.149,374.484,961.091
|
||||
288,9bf531436f,2026-10-21,5861,"Speed up flatten(), unflatten(), diff() and patch() (#5861)",1379.301,2613.219,7170.433,2472.628,1853.035,467.161,315.217,412.303,2406.597,683.062,1298.512,198.681,1434.089,1682.912,177.511,368.116,947.255
|
||||
289,9855db81f3,2026-10-22,5881,Silence macro-to-enum for the endianness macros (#5881),1369.150,2613.547,7209.787,2476.232,1841.347,467.780,316.011,416.187,2415.504,686.920,1304.263,200.868,1441.243,1694.603,178.739,368.123,948.579
|
||||
290,aa0b371f7c,2026-10-23,5884,"Faster std::istream input: inline get-area path, binary reads, unbuffered streambufs (#5884)",1375.030,2569.362,7218.375,2484.425,1743.476,470.240,319.245,403.750,2436.034,679.759,1319.508,201.531,1443.354,1698.057,180.133,372.206,946.488
|
||||
291,86d5c56c54,2026-10-23,5886,"Speed up flatten(), unflatten(), diff() and patch() further (#5886)",1386.169,2622.331,7281.551,2495.923,1700.794,472.317,317.282,403.416,2409.097,682.507,1320.319,200.963,1444.908,1697.678,179.138,375.751,954.573
|
||||
292,dec0e9b749,2026-10-23,5883,"Write strings, scalars and indentation in dump() with fewer calls (#5883)",1383.235,2621.847,7151.412,2491.644,1732.469,473.034,211.016,288.685,2276.953,416.068,1318.490,200.574,1452.099,1701.256,180.064,372.324,960.583
|
||||
293,6fa14d8f95,2026-10-23,5885,Write binary formats through reserved sink space and number runs (#5885),1366.956,2600.914,7176.994,2465.343,1691.333,462.351,210.662,285.259,2301.553,417.589,1324.173,136.601,1429.240,1687.947,179.319,368.881,962.518
|
||||
294,0b924f5375,2026-10-23,5887,Split and print JSON pointers in one pass (#5887),1377.526,2597.394,7242.688,2464.445,1739.841,466.382,211.716,288.202,2319.771,418.288,1318.592,138.744,1441.983,1706.639,179.684,372.087,976.078
|
||||
295,e9c4fe3cdf,2026-10-24,5889,json_view: indented and ensure_ascii dumps through the fast writer (#5889),1393.007,2627.226,7248.287,2491.551,1769.642,469.976,211.665,291.327,2305.655,420.168,1319.431,139.577,1457.965,1712.927,182.274,377.741,983.284
|
||||
296,dd7686a269,2026-10-24,5888,"json_view: faster reading, indexing and C-stream parsing (#5888)",1382.444,2607.026,7161.365,2472.635,1701.277,468.438,209.963,287.564,2276.329,415.511,1311.194,137.875,1439.700,1696.646,177.624,367.131,977.802
|
||||
297,9c50bdd140,2026-10-24,5882,Make the DOM parser cheaper per container and per member (#5882),1392.673,2461.082,6068.625,2334.706,1696.950,475.550,209.313,291.776,2300.287,416.349,1317.581,138.194,1441.209,1707.720,178.751,367.339,978.031
|
||||
298,01139dc192,2026-10-24,5905,Silence an Infer false positive in json_view materialize (#5905),1381.470,2463.013,6078.010,2335.216,1709.088,475.718,211.023,291.212,2275.302,418.098,1320.441,137.572,1443.434,1696.436,175.969,365.658,975.272
|
||||
299,fe5e401870,2026-10-25,5901,Consolidate duplicated detail helpers and bodies (#5891) (#5901),1395.881,2462.765,6066.698,2327.708,1706.745,474.184,212.683,289.321,2283.842,417.657,1314.153,138.084,1442.796,1696.588,177.144,364.092,961.847
|
||||
300,3eae5680d6,2026-10-25,5902,"from_json: number-first dispatch for arithmetic types, loop for std::array (#5902)",1397.343,2477.060,6080.864,2340.781,1711.774,481.523,213.618,289.360,2289.503,417.517,1313.541,138.271,1440.822,1695.785,178.731,367.293,983.555
|
||||
301,2a56afc714,2026-10-25,5916,Fix VS 2015 build of the DOM parser (#5882) (#5916),1373.929,2476.139,6056.797,2341.890,1749.167,482.883,215.107,290.053,2292.495,417.441,1320.640,137.868,1445.227,1702.064,177.912,367.669,984.794
|
||||
302,d6431a9104,2026-10-26,5918,Throw out_of_range.411 for JSON Patch add into a null parent (#5917) (#5918),1371.635,2445.905,6017.636,2314.178,1696.447,478.134,210.996,287.397,2278.718,414.186,1291.197,137.374,1436.212,1682.197,175.790,361.130,962.070
|
||||
303,81d66291c5,2026-10-26,5358,Create objects for pointer tokens that cannot be array indices (#5358),1382.909,2465.649,6052.114,2332.556,1711.721,479.927,213.359,289.913,2289.412,417.201,1311.695,137.572,1437.168,1696.302,177.495,367.526,963.924
|
||||
304,d5da84249f,2026-10-26,5927,"Skip CBOR tags in front of map keys, validate indefinite text chunks, fix CBOR docs (#5927)",1374.553,2476.464,6076.834,2346.075,1744.224,483.375,211.423,291.148,2287.800,420.247,1320.015,137.369,1449.068,1704.785,177.459,365.004,963.908
|
||||
305,0c3570d44a,2026-10-26,5929,Validate the UBJSON/BJData container type marker for count 0; fix UBJSON docs (#5929),1381.462,2462.578,6055.183,2329.970,1713.086,484.962,210.683,290.024,2260.371,416.895,1319.093,137.782,1453.495,1706.801,177.031,361.025,962.952
|
||||
306,dc768a7d5d,2026-10-26,5930,Fix BSON binary subtype 0x02 and check the declared document size earlier (#5930),1386.856,2463.400,6054.255,2337.105,1746.441,485.425,214.508,290.954,2314.702,418.769,1325.164,139.255,1452.125,1718.313,179.005,367.327,977.054
|
||||
307,60107eda3f,2026-10-26,5931,"Read BJData ND-arrays of float16, restrict ND-array char to 0..127, correct BJData docs (#5931)",1389.051,2464.457,6049.084,2336.727,1710.473,483.159,213.007,288.990,2285.073,417.663,1317.537,137.893,1443.301,1697.126,178.706,364.051,962.202
|
||||
308,731f1b5bfb,2026-10-26,5919,"json_view: view_mode enum instead of bool Editable, node_kind for node::kind (#5919)",1381.664,2428.529,5978.713,2333.485,1746.571,479.163,211.036,288.957,2281.592,416.990,1308.904,137.486,1447.665,1691.427,175.453,363.704,963.371
|
||||
309,4cdfa6d0f4,2026-10-26,5920,json_view: no save() and load() on big-endian targets (#5920),1390.901,2477.841,6102.474,2337.925,1777.003,485.382,214.373,290.946,2303.147,421.178,1321.976,139.942,1446.726,1704.816,179.928,367.825,976.532
|
||||
310,5a2819c940,2026-10-26,5921,json_view: one SIMD macro set with the library (#5921),1393.409,2479.841,6073.011,2350.336,1785.087,485.658,214.651,292.044,2304.448,418.026,1326.212,138.942,1468.981,1719.505,179.174,368.704,982.764
|
||||
311,e5fe4ebdd2,2026-10-26,5922,json_view: from_json() of the macros reads views directly (#5922),1384.612,2467.078,6056.328,2337.309,1742.751,482.554,213.389,289.543,2299.118,417.521,1309.673,138.237,1448.628,1704.550,177.925,365.163,984.351
|
||||
312,9e67bfa115,2026-10-26,5923,json_view: the library's std conversions read views directly (#5923),1395.103,2482.517,6066.604,2350.538,1751.603,482.504,213.399,290.185,2306.188,420.406,1317.415,138.730,1444.367,1708.720,178.016,369.111,975.875
|
||||
313,21ec9bd801,2026-10-27,5915,json_view: fewer allocations when parsing small documents (#5915),1388.282,2469.118,6066.495,2340.391,1744.901,478.745,214.934,292.970,2309.264,422.842,1323.237,138.541,1454.151,1707.314,178.058,366.514,958.110
|
||||
314,2bb2feeef4,2026-10-27,5942,"Fix the red CI on develop (json_view pointer tokens, bson, from_json tests, Infer, IWYU) (#5942)",1391.981,2468.266,6068.495,2335.707,1751.527,482.908,214.285,291.291,2300.453,417.876,1328.089,138.010,1454.934,1701.845,178.250,367.182,964.917
|
||||
315,78a0687147,2026-10-27,5940,Strong exception guarantee for operator[](json_pointer) (#5940),1379.414,2467.492,6109.136,2335.309,1723.090,480.260,216.197,292.075,2313.798,415.444,1314.530,138.314,1449.629,1698.792,177.628,364.844,965.314
|
||||
316,091c10d4a5,2026-10-28,5936,Fix self-aliasing in json_pointer::operator/= and patch_inplace (#5936),1389.195,2462.409,6052.125,2321.091,1722.944,473.064,214.421,290.952,2279.997,416.589,1315.370,138.531,1437.996,1683.844,176.596,363.105,952.473
|
||||
317,54f6b3ef06,2026-10-28,5945,json_view: source positions in materialize() with JSON_DIAGNOSTIC_POSITIONS (#5945),1417.895,2496.591,6325.787,2377.105,1737.749,478.133,213.209,293.150,2304.971,422.648,1348.357,139.793,1490.556,1735.758,178.445,368.380,990.587
|
||||
318,0115bb47b3,2026-10-30,5965,Name the source and license of adapted code in the file comments (#5965),1378.289,2456.731,6043.011,2330.780,1711.965,470.960,212.371,290.798,2298.443,419.433,1323.072,137.982,1441.316,1690.457,176.197,363.182,977.928
|
||||
319,0b91f9ddd8,2026-10-30,5926,json_view: check_utf8 skips well-formed runs with the parser's string scan (#5926),1400.777,2488.449,6137.021,2359.856,1747.026,473.449,213.226,290.736,2320.524,420.950,1325.039,139.324,1452.907,1703.426,177.699,364.500,988.981
|
||||
320,ea03d601af,2026-10-30,5890,json_view: comparison without temporaries and a faster image float check (#5890),1388.958,2477.531,6127.547,2357.032,1781.238,477.111,216.144,293.938,2340.267,424.058,1337.149,139.387,1459.923,1723.919,,,
|
||||
321,755bb16d7a,2026-10-30,5966,Fix the red CI on develop: remove the duplicate is_editable in basic_json_view (#5966),1411.867,2497.560,6085.938,2326.880,1726.740,480.376,212.294,292.134,2312.521,420.608,1325.345,138.544,1465.640,1744.928,177.785,367.385,992.034
|
||||
322,4fe670b5f4,2026-10-31,5969,json_view: decode chains of unicode escapes in a loop (#5969),1390.866,2466.769,6026.817,2328.995,1736.168,475.935,212.530,291.166,2284.708,418.661,1323.436,137.513,1495.099,1736.832,176.566,365.541,963.794
|
||||
323,9c349b1d7c,2026-10-31,5964,Write integers of 17 to 20 digits eight digits at a time in dump() (#5964),1390.500,2469.332,6079.698,2359.276,1718.121,470.647,209.615,289.143,2300.836,419.976,1331.637,138.488,1450.106,1703.483,176.731,365.394,953.483
|
||||
324,3fd3e0fdaa,2026-11-01,5908,json_view: dump and read canada.json-style floats faster (batched float decisions) (#5908),1366.359,2456.409,6058.422,2329.066,1713.347,470.784,209.895,289.318,2294.111,417.490,1319.403,138.100,1435.053,1698.647,176.006,363.191,954.196
|
||||
325,76001c6b4c,2026-11-01,5968,"BSON reader: find C-string terminators 8 bytes at a time, skip array element names (#5968)",1408.222,2488.159,6124.287,2363.039,1759.751,477.558,216.880,294.011,2317.898,420.892,1345.718,138.602,1460.432,1713.978,179.721,370.205,970.525
|
||||
326,1a018577cc,2026-11-01,5970,json_view: accept() checks the text without writing an index (#5970),1427.279,2506.345,6160.916,2368.009,1765.595,480.552,214.060,293.093,2341.368,419.303,1330.990,138.625,1463.731,1724.021,181.150,373.171,964.666
|
||||
327,162eda2574,2026-11-01,5971,json_view: skip the digits of a fraction 16 bytes at a time (SSE2) (#5971),1404.191,2474.144,6049.006,2363.726,1711.013,471.608,211.613,289.736,2290.230,418.673,1322.822,138.556,1441.219,1697.559,178.814,370.881,956.959
|
||||
328,6c3ab966d3,2026-11-01,5975,CBOR reader: read runs of scalar array elements in one loop (#5975),1385.800,2466.923,6050.480,2325.901,1725.552,474.248,210.034,289.350,2296.399,418.689,1327.626,137.722,1440.577,1698.622,178.627,367.797,953.174
|
||||
329,aecbef3949,2026-11-01,5976,Binary readers: swap the bytes of floats with a single byteswap (#5976),1393.659,2479.298,6092.110,2337.421,1718.218,472.539,211.337,289.638,2307.378,417.589,1324.038,137.341,1447.860,1701.387,179.160,369.448,956.324
|
||||
330,edf8d17601,2026-11-01,5980,MessagePack reader: read runs of scalar array elements in one loop (#5980),1422.081,2486.171,6157.302,2360.678,1733.503,477.472,211.189,289.309,2307.724,419.448,1334.857,138.914,1449.345,1721.126,180.127,369.693,967.370
|
||||
331,fb515ddc34,2026-11-01,5981,UBJSON/BJData readers: read optimized arrays of numbers in one loop (#5981),1387.633,2470.528,6067.657,2345.342,1721.303,476.141,212.198,288.466,2292.649,416.597,1324.486,139.598,1441.019,1705.957,179.190,367.903,959.677
|
||||
332,517444b504,2026-11-01,5978,accept() checks strings without copying them (#5978),1385.026,2453.809,5975.744,2322.357,1711.222,475.186,210.256,288.348,2282.444,415.256,1321.012,138.726,1434.772,1698.120,178.106,365.411,976.135
|
||||
333,9742edc294,2026-11-01,5979,"BSON writer: write to_bson(j) in one pass, with sizes written afterwards (#5979)",1418.816,2514.802,6091.854,2380.269,1772.646,474.067,211.598,290.653,2316.886,421.043,1346.324,139.213,1469.659,1754.493,180.269,372.201,982.753
|
||||
334,f022e3c59c,2026-11-01,5982,Binary readers and writers: faster UTF-8 checks of strings (#5982),1399.836,2474.703,6060.781,2341.409,1707.583,468.692,209.824,290.357,2290.034,418.739,1312.448,138.360,1458.779,1707.575,178.911,369.303,968.200
|
||||
335,ddc34f546a,2026-11-01,5974,json_view: exceptions name the path and the bytes of the value (#5974),1394.263,2489.906,6017.599,2345.632,1728.593,473.672,210.364,289.980,2306.608,420.394,1327.301,138.827,1448.846,1707.037,177.406,368.436,978.755
|
||||
336,b2674a4a2f,2026-11-01,5984,BSON reader: check array element names in place in strict mode (#5984),1392.028,2460.989,5975.355,2357.154,1726.291,472.389,209.872,289.219,2301.092,417.632,1309.441,138.779,1438.270,1709.943,177.580,366.368,973.214
|
||||
337,76dbe8f9c9,2026-11-02,6009,"Fix the red CI on develop: Visual Studio 2017 build of the BSON writer, Valgrind timeouts (#6009)",1387.812,2461.244,5975.843,2323.693,1713.572,469.489,209.863,289.058,2291.892,415.935,1306.729,138.322,1447.714,1694.220,177.698,363.994,972.289
|
||||
338,03d408aafa,2026-11-02,6003,JSON_DIAGNOSTIC_POSITIONS: comparing a value-initialized iterator throws instead of crashing (#6003),1385.014,2455.146,5981.995,2380.493,1732.039,466.575,209.272,289.474,2295.226,416.844,1301.454,138.016,1445.840,1703.494,176.691,365.416,967.929
|
||||
339,66e2eeeec0,2026-11-02,6000,Do not construct the base class when destroying a container (#6000),1403.795,2457.426,6001.495,2323.510,1718.268,471.022,210.474,288.385,2308.462,417.187,1313.263,138.770,1437.867,1705.586,179.168,363.523,966.701
|
||||
340,bdc737db6d,2026-11-02,5999,json_view: dump() without StringType::capacity() (#5999),1378.656,2452.954,6020.464,2339.908,1724.630,470.774,211.638,288.939,2303.773,418.311,1312.024,139.010,1446.709,1704.406,177.291,363.859,966.602
|
||||
341,494a74c242,2026-11-02,5996,"insert(): strong guarantee for single elements, basic guarantee for the rest (#5996)",1390.153,2478.991,6032.084,2342.171,1727.040,469.799,213.660,291.104,2307.193,419.623,1329.285,139.000,1461.294,1718.750,178.995,366.898,974.652
|
||||
342,bfe69c73c2,2026-11-02,5992,"json_view: get<T>() of a boolean throws for the exact number types, as basic_json does (#5992)",1387.497,2452.207,6023.042,2335.261,1720.938,471.966,212.162,288.851,2310.949,417.260,1315.155,137.821,1448.762,1710.153,175.990,366.239,970.052
|
||||
343,ff0bdfdef3,2026-11-02,5990,Keep the byte range in exceptions about the root value (#5990),1386.358,2469.197,6037.812,2344.775,1768.382,479.285,214.375,290.939,2329.486,421.838,1332.654,138.666,1455.905,1720.376,178.637,368.500,972.955
|
||||
344,1d69ef9ab4,2026-11-02,5997,"Raise line coverage to 99.9 %: fix the measurement, remove unreachable code, add tests (#5997)",1404.481,2456.447,6166.942,2338.226,1749.981,478.338,211.609,289.387,2304.532,419.095,1321.195,140.055,1460.574,1706.842,179.067,369.688,982.029
|
||||
345,5c4f585ac2,2026-11-02,6004,"Lexer, parser, stream adapter, SAX: remove checks that invariants make dead (#6004)",1386.586,2468.772,6188.662,2373.328,1775.098,483.139,211.476,291.250,2315.874,420.854,1321.718,138.268,1464.254,1709.146,180.316,367.994,965.010
|
||||
346,100f676b3e,2026-11-02,6012,Restore the two commits of #6005 that the stack merge dropped (fixes the build of develop) (#6012),1369.597,2437.356,6122.282,2305.291,1691.485,472.217,208.716,288.666,2291.034,416.120,1300.906,137.896,1439.300,1688.769,176.641,366.389,972.368
|
||||
347,590b622d48,2026-11-02,5991,parse(): propagate std::bad_alloc instead of crashing on a half-constructed member (#5991),1377.480,2425.219,6113.438,2306.435,1716.697,474.315,209.052,288.883,2292.776,417.291,1305.336,137.989,1453.044,1704.638,179.096,368.072,978.198
|
||||
348,6d5581c4e8,2026-11-02,6008,CBOR/MessagePack readers: leave one-element arrays to the general path (#6008),1400.456,2439.163,6140.448,2328.635,1743.039,480.725,212.470,295.268,2348.332,427.202,1340.319,139.121,1489.584,1736.380,184.949,371.567,995.731
|
||||
349,b18b6fc7e6,2026-11-02,6013,Build the parser's syntax error prefix with one concat() (#6013),1370.175,2435.337,6098.834,2320.728,1726.256,472.914,210.817,289.786,2292.841,419.186,1306.593,139.277,1481.709,1714.543,177.065,366.270,971.330
|
||||
350,07876e2292,2026-11-02,6015,json_view: a value that is not found has no bytes in its exception context (#6015),1361.297,2435.980,6080.718,2305.853,1707.733,474.621,210.382,291.568,2337.276,424.783,1329.556,139.590,1450.506,1690.804,178.472,366.370,977.807
|
||||
351,baba5db36f,2026-11-02,6016,"Fix the MSVC and GCC builds of develop (C4127, -Weffc++) (#6016)",1381.280,2440.908,6116.068,2303.611,1713.472,476.121,210.492,290.105,2319.878,420.598,1318.037,139.554,1471.388,1729.097,177.078,369.621,959.145
|
||||
352,candidate,,,develop + open pull requests,1392.967,2469.204,6110.380,2348.760,1730.819,474.089,212.339,290.760,2284.428,420.179,1320.938,137.755,1441.341,1697.486,176.758,364.547,955.117
|
||||
|
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
|
||||
@@ -0,0 +1,795 @@
|
||||
"""Draws the figures of home/blog/how_3_13_0_got_faster.md as inline SVGs into docs/images/.
|
||||
|
||||
Generated files:
|
||||
|
||||
- perf_blog_overview.svg: speedup of 3.13.0 over 3.12.0 per workload (Google Benchmark suite)
|
||||
- perf_blog_distribution.svg: how many of the suite's benchmarks got how much faster (data/perf_suite.csv)
|
||||
- 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
|
||||
|
||||
The numbers are copied from the tables of the post (the timeline from data/perf_timeline.csv, which
|
||||
`tests/benchmarks/history/history.py summarize` writes); the tables stay on the page as the accessible fallback. Update both together.
|
||||
Like the figures of charts.py, the SVGs are not images: the page includes their text with
|
||||
`--8<-- "images/<name>.svg"`, so they follow the colors and fonts of the page (`nj-charts` rules in
|
||||
docs/css/fig-charts.css, `nj-fig` rules in docs/css/brand.css). Run `python3 scripts/figures/perf_blog.py` from
|
||||
docs/mkdocs after changing data or drawing, and commit the generated files.
|
||||
"""
|
||||
import csv
|
||||
import html
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
OUT = HERE.parents[1] / "docs" / "images"
|
||||
MINUS = "−"
|
||||
TIMES = "×"
|
||||
|
||||
# words the abbreviation extension (includes/glossary.md) would wrap in <abbr> inside the SVG text
|
||||
GLOSSARY = re.findall(r"^\*\[([^\]]+)\]", (HERE.parents[1] / "includes" / "glossary.md").read_text(), re.M)
|
||||
ABBR = re.compile(r"(?<![\w;])(%s)(?!\w)" % "|".join(sorted(map(re.escape, GLOSSARY), key=len, reverse=True)))
|
||||
|
||||
|
||||
def protect(text):
|
||||
return ABBR.sub(lambda m: m.group(1)[0] + "​" + m.group(1)[1:], text)
|
||||
|
||||
|
||||
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),
|
||||
'<title id="%s">%s</title>' % (tid, esc(title)),
|
||||
'<desc id="%s-d">%s</desc>' % (tid, esc(desc))]
|
||||
s += body
|
||||
s.append('</svg>')
|
||||
text = protect("\n".join(s)) + "\n"
|
||||
assert "\n\n" not in text # a blank line would end the raw HTML block
|
||||
(OUT / name).write_text(text)
|
||||
|
||||
|
||||
def hbar(x0, x1, y, h, r=4):
|
||||
"""Horizontal bar from the baseline x0 to x1, rounded only at the data end."""
|
||||
if abs(x1 - x0) < 0.5:
|
||||
return "M%g %g h0.5 v%g h-0.5 Z" % (x0, y, h)
|
||||
r = min(r, h / 2, abs(x1 - x0))
|
||||
s = 1 if x1 > x0 else -1
|
||||
return ("M%g %g H%g Q%g %g %g %g V%g Q%g %g %g %g H%g Z"
|
||||
% (x0, y, x1 - s * r, x1, y, x1, y + r, y + h - r, x1, y + h, x1 - s * r, y + h, x0))
|
||||
|
||||
|
||||
def fx(v):
|
||||
"""speedup factor for labels: 2 significant digits below 10, integers above"""
|
||||
if v >= 100:
|
||||
return "%d%s" % (round(v), TIMES)
|
||||
if v >= 10:
|
||||
return "%.0f%s" % (v, TIMES)
|
||||
return "%.1f%s" % (v, TIMES) if v >= 1.995 else "%.2f%s" % (v, TIMES)
|
||||
|
||||
|
||||
# ---------- SWAR: one word of a string ----------
|
||||
def swar():
|
||||
text = 'witter",'
|
||||
W, H = 640, 312
|
||||
L, cw, top = 40, 70, 34
|
||||
b = []
|
||||
b.append('<text class="fg-h" x="%g" y="20">eight input bytes, loaded as one 64-bit word (byte 0 is the lowest)</text>' % L)
|
||||
for i, ch in enumerate(text):
|
||||
x = L + i * cw
|
||||
special = ch == '"'
|
||||
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="40" rx="4"/>' % (x, top, cw - 6))
|
||||
if special:
|
||||
b.append('<rect class="nj-charts-c2" fill-opacity=".25" x="%g" y="%g" width="%g" height="40" rx="4"/>' % (x, top, cw - 6))
|
||||
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>' % (x + (cw - 6) / 2, top + 26, esc(ch)))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">0x%02X</text>' % (x + (cw - 6) / 2, top + 58, ord(ch)))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">byte %d</text>' % (x + (cw - 6) / 2, top + 74, i))
|
||||
# result row
|
||||
y2 = top + 112
|
||||
b.append('<text class="fg-h" x="%g" y="%g">swar_string_special(): the high bit of each byte that needs handling</text>' % (L, y2 - 14))
|
||||
for i, ch in enumerate(text):
|
||||
x = L + i * cw
|
||||
special = ch == '"'
|
||||
b.append('<rect class="fg-cell" x="%g" y="%g" width="%g" height="34" rx="4"/>' % (x, y2, cw - 6))
|
||||
if special:
|
||||
b.append('<rect class="nj-charts-c2" fill-opacity=".25" x="%g" y="%g" width="%g" height="34" rx="4"/>' % (x, y2, cw - 6))
|
||||
b.append('<text class="fg-code" x="%g" y="%g" text-anchor="middle">%s</text>'
|
||||
% (x + (cw - 6) / 2, y2 + 23, "0x80" if special else "0x00"))
|
||||
# conclusion
|
||||
y3 = y2 + 70
|
||||
b.append('<text class="fg-code" x="%g" y="%g">count_trailing_zeros(0x0080000000000000) = 55</text>' % (L, y3))
|
||||
b.append('<text class="fg-code" x="%g" y="%g">55 / 8 = 6: copy bytes 0 to 5 in one go, then handle the quote</text>' % (L, y3 + 26))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">No branch per byte: a few subtractions, ANDs and ORs per word,</text>' % (L, y3 + 56))
|
||||
b.append('<text class="fg-note fg-note--l" x="%g" y="%g">then one count of trailing zeros.</text>' % (L, y3 + 74))
|
||||
write("perf_blog_swar.svg", W, H, "nj-charts--swar", "nj-blog-swar",
|
||||
"Finding the end of a run of ordinary string characters eight bytes at a time",
|
||||
"The eight bytes w, i, t, t, e, r, quote and comma are loaded as one word. The test sets the high bit only in "
|
||||
"byte 6, the quote. Counting trailing zero bits gives 55, divided by eight gives 6: bytes 0 to 5 are copied "
|
||||
"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 = [
|
||||
("Parsing", "twitter.json", 3.14),
|
||||
("Parsing", "citm_catalog.json", 4.25),
|
||||
("Parsing", "canada.json", 3.35),
|
||||
("Parsing", "canada.json, indented", 6.51),
|
||||
("Parsing", "citm, ordered_json", 6.85),
|
||||
("Parsing", "twitter, std::ifstream", 2.50),
|
||||
("Parsing", "citm, FILE*", 4.74),
|
||||
("Parsing", "citm, accept()", 7.07),
|
||||
("Writing", "dump() twitter", 6.70),
|
||||
("Writing", "dump() canada", 2.98),
|
||||
("Writing", "dump(4) citm", 4.70),
|
||||
("Writing", "to_cbor() twitter", 4.59),
|
||||
("Reading CBOR", "twitter, memory", 3.39),
|
||||
("Reading CBOR", "twitter, FILE*", 6.59),
|
||||
("Values", "diff() canada", 10.46),
|
||||
("Values", "iterate canada", 2.73),
|
||||
("Values", "copy + destroy citm", 1.13),
|
||||
("Values", "== citm", 1.06),
|
||||
]
|
||||
|
||||
|
||||
def overview():
|
||||
W, L, R = 560, 190, 520
|
||||
hi = max(v for _, _, v in OVERVIEW)
|
||||
hi = math.ceil(hi + 0.5)
|
||||
X = lambda v: L + v / hi * (R - L)
|
||||
pitch, bh, top = 24, 15, 8
|
||||
b, desc = [], []
|
||||
y = top
|
||||
group = None
|
||||
rows = []
|
||||
for g, label, v in OVERVIEW:
|
||||
if g != group:
|
||||
if group is not None:
|
||||
y += 10
|
||||
b.append('<text class="nj-charts-panel" x="%g" y="%g">%s</text>' % (8, y + 12, esc(g)))
|
||||
y += 22
|
||||
group = g
|
||||
rows.append((label, v, y))
|
||||
y += pitch
|
||||
axis_y = y + 2
|
||||
for t in range(1, hi + 1):
|
||||
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), top, X(t), axis_y))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%d%s</text>' % (X(t), axis_y + 16, t, TIMES))
|
||||
for label, v, yy in rows:
|
||||
b.append('<text class="nj-charts-rowlabel nj-charts-tick--r" x="%g" y="%g" text-anchor="end">%s</text>' % (L - 8, yy + bh - 3, esc(label)))
|
||||
b.append('<path class="nj-charts-c1" d="%s"><title>%s: %s</title></path>' % (hbar(X(0), X(v), yy, bh), esc(label), fx(v)))
|
||||
b.append('<text class="nj-charts-val" x="%g" y="%g">%s</text>' % (X(v) + 5, yy + bh - 3, fx(v)))
|
||||
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-tick" x="%g" y="%g">speedup over 3.12.0 (3.12.0 = 1%s), more is better</text>'
|
||||
% ((L + R) / 2, axis_y + 34, TIMES))
|
||||
write("perf_blog_overview.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-overview",
|
||||
"Speedup of 3.13.0 over 3.12.0 per workload, Apple M1 Max, Apple clang",
|
||||
"Horizontal bars of the speedup, more is better. " + "; ".join(desc) + ".", b)
|
||||
|
||||
|
||||
# ---------- distribution: how many of the suite's benchmarks got how much faster ----------
|
||||
# bins of the speedup (3.12.0 time / 3.13.0 time) over all rows of data/perf_suite.csv
|
||||
BINS = [(0, 1, "below 1" + TIMES), (1, 1.5, "1 to 1.5" + TIMES), (1.5, 2, "1.5 to 2" + TIMES),
|
||||
(2, 3, "2 to 3" + TIMES), (3, 5, "3 to 5" + TIMES), (5, 10, "5 to 10" + TIMES), (10, 1e9, "10" + TIMES + " or more")]
|
||||
|
||||
|
||||
def distribution():
|
||||
rows = list(csv.DictReader((HERE / "data" / "perf_suite.csv").open()))
|
||||
s = sorted(float(r["speedup"]) for r in rows)
|
||||
n = len(s)
|
||||
counts = [sum(lo <= v < hi for v in s) for lo, hi, _ in BINS]
|
||||
geo = math.exp(sum(math.log(v) for v in s) / n)
|
||||
med = (s[(n - 1) // 2] + s[n // 2]) / 2
|
||||
W, H = 560, 250
|
||||
L, R, T, B = 52, 548, 16, 196
|
||||
hi = 10 * math.ceil(max(counts) / 10 + 0.4)
|
||||
Y = lambda c: B - c / hi * (B - T)
|
||||
slot = (R - L) / len(BINS)
|
||||
b, desc = [], []
|
||||
for t in range(0, hi + 1, 20):
|
||||
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, Y(t), R, Y(t)))
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--r" x="%g" y="%g">%d</text>' % (L - 6, Y(t) + 4, t))
|
||||
for k, ((lo, _, label), c) in enumerate(zip(BINS, counts)):
|
||||
x = L + k * slot + 8
|
||||
w = slot - 16
|
||||
cls = "nj-charts-c2" if lo < 1 else "nj-charts-c1"
|
||||
b.append('<rect class="%s" x="%.1f" y="%.1f" width="%.1f" height="%.1f" rx="3"><title>%s: %d</title></rect>'
|
||||
% (cls, x, Y(c), w, B - Y(c), label, c))
|
||||
b.append('<text class="nj-charts-val" x="%.1f" y="%.1f" text-anchor="middle">%d</text>' % (x + w / 2, Y(c) - 5, c))
|
||||
b.append('<text class="nj-charts-tick" x="%.1f" y="%.1f">%s</text>' % (x + w / 2, B + 16, label))
|
||||
desc.append("%s: %d" % (label.replace(TIMES, "x"), c))
|
||||
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-tick" x="%g" y="%g">speedup over 3.12.0, more is better</text>' % ((L + R) / 2, H - 10))
|
||||
b.append('<text class="nj-charts-tick" transform="rotate(-90)" x="%g" y="14">number of benchmarks</text>' % (-(T + B) / 2))
|
||||
print("distribution: median %s, geometric mean %s" % (fx(med), fx(geo)))
|
||||
write("perf_blog_distribution.svg", W, H, "nj-charts--blog", "nj-blog-dist",
|
||||
"Speedup of 3.13.0 over 3.12.0 for all %d benchmarks of the suite" % n,
|
||||
"Bars counting the benchmarks per speedup range: " + "; ".join(desc)
|
||||
+ ". Median %s, geometric mean %s." % (fx(med).replace(TIMES, "x"), fx(geo).replace(TIMES, "x")), b)
|
||||
|
||||
|
||||
# ---------- timeline: one panel per workload ----------
|
||||
# (column in perf_timeline.csv, panel title, [(PR, label)]): each labeled step shows the number of the theme that
|
||||
# explains it ("U" for the UTF-8 check of the binary readers that came and went); the appendix maps steps to PRs
|
||||
TIMELINE = [
|
||||
("parse_citm", "parse() citm_catalog.json", [(5234, "4"), (5283, "1"), (5592, "4"), (5809, "4"), (5810, "2"), (5882, "4")]),
|
||||
("parse_canada", "parse() canada.json", [(5234, "4"), (5283, "1"), (5617, "3"), (5738, "3"), (5851, "3"), (5882, "4")]),
|
||||
("accept_twitter", "accept() twitter.json", [(5234, "4"), (5283, "1"), (5592, "4"), (5809, "4"), (5810, "2"), (5853, "2")]),
|
||||
("parse_twitter_ifstream", "parse() twitter.json, std::ifstream", [(5828, "1"), (5884, "1")]),
|
||||
("dump_twitter", "dump() twitter.json", [(5285, "6"), (5738, "2"), (5878, "2"), (5883, "2")]),
|
||||
("dump_canada", "dump() canada.json", [(5285, "6"), (5634, "3")]),
|
||||
("from_cbor_twitter", "from_cbor() twitter", [(5233, "1"), (5501, "4"), (5185, "U"), (5746, "U")]),
|
||||
("to_cbor_twitter", "to_cbor() twitter", [(5328, "4"), (5824, "6"), (5885, "6")]),
|
||||
]
|
||||
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, 270
|
||||
L, R, T, B = 44, 330, 66, 208
|
||||
for col, title, labels in TIMELINE:
|
||||
vals = [float(r[col]) if r[col] else None for r in rows]
|
||||
base = vals[0]
|
||||
rel = [base / v if v else None for v in vals] # speedup over 3.12.0
|
||||
hi = max(x for x in rel if x)
|
||||
top = 2 ** math.ceil(math.log2(hi * 1.3))
|
||||
Y = lambda s: B - math.log2(s) / math.log2(top) * (B - T)
|
||||
X = lambda i: L + i / (n - 1) * (R - L)
|
||||
b = ['<text class="nj-charts-panel" x="%g" y="18">%s</text>' % (8, esc(title))]
|
||||
t = 1
|
||||
while t <= top:
|
||||
b.append('<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (L, Y(t), R, Y(t)))
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--r" x="%g" y="%g">%d%s</text>' % (L - 6, Y(t) + 4, t, TIMES))
|
||||
t *= 2
|
||||
# month ticks: first commit of the month
|
||||
seen = set()
|
||||
for i, r in enumerate(rows):
|
||||
m = r["date"][:7]
|
||||
for key, name in MONTHS:
|
||||
if m == key and key not in seen:
|
||||
seen.add(key)
|
||||
b.append('<line class="nj-charts-axis" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(i), B, X(i), B + 4))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(i), B + 17, name))
|
||||
# a step line: each commit's value holds until the next commit
|
||||
pts, prev = [], None
|
||||
for i, s in enumerate(rel):
|
||||
if s is None:
|
||||
continue
|
||||
if prev is not None:
|
||||
pts.append("%.1f,%.1f" % (X(i), Y(prev)))
|
||||
pts.append("%.1f,%.1f" % (X(i), Y(s)))
|
||||
prev = s
|
||||
b.append('<polyline class="nj-charts-json" points="%s"/>' % " ".join(pts))
|
||||
# labels for named steps: a dot at the commit and its PR number above it; PRs a few commits apart share a
|
||||
# label, and a label that would overlap one already placed moves up
|
||||
groups = []
|
||||
for pr, lab in labels:
|
||||
i = next(k for k, r in enumerate(rows) if r["pr"] == str(pr))
|
||||
if groups and X(i) - X(groups[-1][-1][1]) < 6:
|
||||
groups[-1].append((pr, i, lab))
|
||||
else:
|
||||
groups.append([(pr, i, lab)])
|
||||
# labels in two rows above the plot, each with a guide down to its dot
|
||||
placed = []
|
||||
for g in groups:
|
||||
i = g[-1][1]
|
||||
x, y = X(i), Y(rel[i])
|
||||
for pr, k, lab in g:
|
||||
b.append('<circle class="nj-charts-json-dot" cx="%.1f" cy="%.1f" r="3.5"><title>#%s: %s</title></circle>'
|
||||
% (X(k), Y(rel[k]), pr, fx(rel[k])))
|
||||
marks = list(dict.fromkeys(lab for _, _, lab in g))
|
||||
w = 18 * len(marks) - 3
|
||||
tx = min(max(x, L + w / 2), R - w / 2)
|
||||
row = 0
|
||||
while any(r == row and abs(tx - px) < (w + pw) / 2 + 4 for px, r, pw in placed):
|
||||
row += 1
|
||||
placed.append((tx, row, w))
|
||||
ty = 46 - 18 * row # the center of the badges
|
||||
b.append('<line class="nj-charts-grid" stroke-dasharray="2 2" x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f"/>' % (x, ty + 8, x, y - 5))
|
||||
for k, mark in enumerate(marks):
|
||||
cx = tx - w / 2 + 7.5 + 18 * k
|
||||
b.append('<circle class="nj-theme-dot%s" cx="%.1f" cy="%.1f" r="7.5"/>' % ("" if mark.isdigit() else " nj-theme-dot--other", cx, ty))
|
||||
b.append('<text class="nj-theme-num" x="%.1f" y="%.1f" text-anchor="middle">%s</text>' % (cx, ty + 4, mark))
|
||||
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, by theme: %s."
|
||||
% (title, n, fx(final).replace(TIMES, "x"), ", ".join(lab for _, lab in labels)))
|
||||
write("perf_blog_timeline_%s.svg" % col, W, H, "nj-charts--timeline", "nj-blog-tl-" + col,
|
||||
"%s: speedup over 3.12.0 by commit" % title, desc, b)
|
||||
|
||||
|
||||
# ---------- cliffs: 3.12.0 and 3.13.0 times on a log axis ----------
|
||||
# (operation, 3.12.0 ms, 3.13.0 ms), copied from the table in "Fix the algorithm first"
|
||||
CLIFFS = [
|
||||
("diff() 64k numbers vs []", 4237, 10.8),
|
||||
("diff() 20k objects vs half", 122, 4.13),
|
||||
("parse() callback, 32k objects", 1398, 12.1),
|
||||
("operator< nested 24 deep", 64.4, 0.002),
|
||||
("operator< citm, 10x", 284, 3.94),
|
||||
("flatten() citm, ordered_json", 271, 1.45),
|
||||
("to_bson() 200 deep, 100x", 20.3, 0.352),
|
||||
("push_back() 100k, diagnostics", 1589, 5.32),
|
||||
("at(i) 10k, diagnostics", 45.9, 0.088),
|
||||
]
|
||||
|
||||
|
||||
def cliffs():
|
||||
W, L, R = 600, 250, 585
|
||||
lo, hi = -3, 4 # 1 µs .. 10 s, in log10 ms
|
||||
X = lambda ms: L + (math.log10(ms) - lo) / (hi - lo) * (R - L)
|
||||
top, pitch = 40, 34
|
||||
b, desc = [], []
|
||||
axis_y = top + pitch * len(CLIFFS) - 10
|
||||
for e in range(lo, hi + 1):
|
||||
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)))
|
||||
# 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 + 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, 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]
|
||||
# the fastest other library: below 1 json_document is the fastest, and the distance shows by how much
|
||||
best = min((l for l in libs if l != "nlohmann json_document"), 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 = 0.4, 1.15
|
||||
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 (0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1):
|
||||
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 other 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">next 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(max(lo, min(r, hi))), y - 3.5 + 7 * k, esc_md(f), esc_md(name), r, TIMES, esc_md(winner[plat, f])))
|
||||
w = winner["x86-gcc", f]
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--l%s" x="%g" y="%g">%s</text>'
|
||||
% (" nj-charts-best" if rel["x86-gcc", f] > 1.0005 else "", R + 14, y + 4, esc_md(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">as fast as the next</text>' % (X(1), top - 14))
|
||||
wins = {p: sum(rel[p, f] < 1 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 other library per file",
|
||||
"Dot plot per file, less is better; below 1.0 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 5 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)
|
||||
PRICE = [
|
||||
("Apple clang 21, -O0 (debug)", [("count_numbers", 955.0, 1320.5, 688.5, 917.5), ("server_config", 1113.2, 1496.4, 862.6, 1135.5)]),
|
||||
("Apple clang 21, -O2", [("count_numbers", 1393.2, 2081.0, 1458.4, 1684.6), ("server_config", 1753.5, 2545.6, 1925.3, 2168.6)]),
|
||||
("GCC 16, -O0 (debug)", [("count_numbers", 1569.4, 2548.4, 1725.0, 1699.8), ("server_config", 2025.4, 2985.1, 2301.6, 2325.8)]),
|
||||
("GCC 16, -O2", [("count_numbers", 2336.0, 3701.5, 2986.8, 2913.4), ("server_config", 3121.5, 4714.2, 4006.2, 4054.9)]),
|
||||
]
|
||||
PRICE_SERIES = [("3.13.0", "nj-charts-c2"), ("3.13.0, precompiled header", "nj-charts-c1"), ("3.13.0, module", "nj-charts-c3")]
|
||||
|
||||
|
||||
def price():
|
||||
W, L, R = 600, 150, 560
|
||||
lo, hi = -50, 70
|
||||
X = lambda pct: L + (pct - lo) / (hi - lo) * (R - L)
|
||||
pct = lambda new, old: round((new / old - 1) * 100)
|
||||
lab = lambda p: (MINUS + "%d%%" % -p) if p < 0 else "+%d%%" % p
|
||||
bh, pitch, gap = 11, 14, 10
|
||||
b, desc = [], []
|
||||
# the key above the plot
|
||||
x = 8
|
||||
for name, cls in PRICE_SERIES:
|
||||
b.append('<rect class="%s" x="%g" y="6" width="12" height="12" rx="3"/>' % (cls, x))
|
||||
b.append('<text class="nj-charts-leg" x="%g" y="16.5">%s</text>' % (x + 18, esc(name)))
|
||||
x += 18 + 8.2 * len(name) + 22
|
||||
top = 54
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">as fast as 3.12.0</text>' % (X(0), top - 8))
|
||||
y = top
|
||||
for build, progs in PRICE:
|
||||
b.append('<text class="nj-charts-panel" x="8" y="%g">%s</text>' % (y + 14, esc(build)))
|
||||
y += 24
|
||||
y0, at = y, len(b)
|
||||
for prog, old, *new in progs:
|
||||
b.append('<text class="nj-charts-rowlabel nj-charts-code" x="%g" y="%g" text-anchor="end">%s</text>'
|
||||
% (L - 8, y + 1.5 * pitch + 2, prog))
|
||||
for (name, cls), t in zip(PRICE_SERIES, new):
|
||||
p = pct(t, old)
|
||||
b.append('<path class="%s" d="%s"><title>%s, %s, %s: %s ms against %s ms with 3.12.0 (%s)</title></path>'
|
||||
% (cls, hbar(X(0), X(p), y, bh), prog, esc(build), esc(name), format(round(t), ","), format(round(old), ","), lab(p)))
|
||||
if p < 0:
|
||||
b.append('<text class="nj-charts-val" x="%g" y="%g" text-anchor="end">%s</text>' % (X(p) - 5, y + bh - 1.5, lab(p)))
|
||||
else:
|
||||
b.append('<text class="nj-charts-val" x="%g" y="%g">%s</text>' % (X(p) + 5, y + bh - 1.5, lab(p)))
|
||||
desc.append("%s, %s, %s: %s" % (build, prog, name, lab(p).replace(MINUS, "-")))
|
||||
y += pitch
|
||||
y += gap - (pitch - bh)
|
||||
# the grid behind this panel's bars only, so that it doesn't cross the panel titles
|
||||
b[at:at] = ['<line class="nj-charts-grid" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(t), y0 - 4, X(t), y - gap + 4)
|
||||
for t in range(lo + 10, hi + 1, 20) if t]
|
||||
y += 8
|
||||
axis_y = y
|
||||
b.append('<line class="nj-charts-ref" x1="%g" y1="%g" x2="%g" y2="%g"/>' % (X(0), top - 2, X(0), axis_y))
|
||||
for t in range(lo + 10, hi + 1, 20):
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (X(t), axis_y + 16, "0" if t == 0 else lab(t)))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">compile time compared with 3.12.0, less is better</text>' % ((L + R) / 2, axis_y + 34))
|
||||
write("perf_blog_price.svg", W, axis_y + 44, "nj-charts--blog", "nj-blog-price",
|
||||
"Compile time of two programs with 3.13.0, alone, with a precompiled header and as a module, compared with 3.12.0",
|
||||
"Horizontal bars of the change in compile time against 3.12.0, less is better. " + "; ".join(desc) + ".", b)
|
||||
|
||||
|
||||
# ---------- use cases: libraries x use cases, relative time ----------
|
||||
# data/perf_usecases_<platform>.json is written by tests/benchmarks/json_view/others/summarize.py --json
|
||||
UC_FILES = ["twitter", "citm_catalog", "canada", "jeopardy"]
|
||||
USE_CASES = [("validate", "validate"), ("sum", "sum"), ("select", "select"),
|
||||
("edit", "edit"), ("minify", "minify"), ("write", "write")]
|
||||
UC_LIBS = { # library in the JSON -> row label
|
||||
"nlohmann json_document": "nlohmann/json json_document", "nlohmann json": "nlohmann/json json",
|
||||
"yyjson": "yyjson", "simdjson": "simdjson", "sonic-cpp": "sonic-cpp", "Glaze": "Glaze", "Boost.JSON": "Boost.JSON",
|
||||
"RapidJSON": "RapidJSON", "sonic-rs": "sonic-rs (Rust)", "simd-json": "simd-json (Rust)", "serde_json": "serde_json (Rust)",
|
||||
}
|
||||
UC_PLATFORMS = [("mac", "Use cases: time of each library relative to the fastest, Apple M1 Max"),
|
||||
("x86-gcc", "Use cases: time of each library relative to the fastest, x86-64 with GCC 16.2"),
|
||||
("x86-gcc13", "Use cases: time of each library relative to the fastest, x86-64 with GCC 13"),
|
||||
("x86-clang", "Use cases: time of each library relative to the fastest, x86-64 with Clang 23")]
|
||||
LEVEL_MARK = {"no UTF-8": "U", "partial": "P", "full": ""}
|
||||
# why a cell is empty (the tooltips of the n/a cells)
|
||||
NA = {("simdjson", "edit"): "simdjson's documents are read-only: it has no API to change a value and write the result"}
|
||||
|
||||
|
||||
def geomean(xs):
|
||||
return math.exp(sum(math.log(x) for x in xs) / len(xs))
|
||||
|
||||
|
||||
WRITING = ("edit", "minify", "write") # the use cases that write numbers
|
||||
NUMBER_TEXT = ("source numbers", "raw numbers") # variants that write each number by copying its text
|
||||
|
||||
|
||||
def normalize_usecases(data):
|
||||
"""Chooses each library's best variants again with the rules of the post: variants that reuse a parser or document
|
||||
across calls are measured but not chosen. Variants that write each number by copying its text instead of formatting
|
||||
it (json_document's number_format::source, yyjson's and RapidJSON's raw numbers in edit, minify and write) are not
|
||||
chosen as the fully validating way, but as a way that does less, marked "N" like "U" and "P". Skipping the number
|
||||
conversion while reading is allowed. Each pick has a "mark": "", or the letters of what it skips"""
|
||||
data = json.loads(json.dumps(data))
|
||||
rank = {"full": 0, "n/a": 0, "no UTF-8": 1, "partial": 2}
|
||||
for uc, files in data.items():
|
||||
numtext = lambda k: uc in WRITING and any(w in k for w in NUMBER_TEXT)
|
||||
for cell in files.values():
|
||||
for e in cell.values():
|
||||
vs = [(v["us"], k, v["level"]) for k, v in e["variants"].items() if "reused" not in k]
|
||||
full = [v for v in vs if rank[v[2]] == 0 and not numtext(v[1])]
|
||||
pick = lambda v: {"us": v[0], "variant": v[1], "level": "full" if rank[v[2]] == 0 else v[2],
|
||||
"mark": " ".join(m for m in (LEVEL_MARK.get(v[2], ""), "N" if numtext(v[1]) else "") if m)}
|
||||
e["best"] = pick(min(full)) if full else None
|
||||
e["best_any"] = pick(min(vs))
|
||||
return data
|
||||
|
||||
|
||||
FILE_NAMES = {"twitter": "twitter.json", "citm_catalog": "citm_catalog.json", "canada": "canada.json",
|
||||
"jeopardy": "jeopardy.json"}
|
||||
# what a variant that checks less skips, worded as the trade it is (the tooltips of the heatmaps)
|
||||
CHECKS_LESS = [
|
||||
("simdjson", "On-Demand", "reads lazily: On-Demand reads only what you ask for and steps over the rest by matching brackets"),
|
||||
("simdjson", "minify", "simdjson::minify() only removes whitespace, without parsing the values"),
|
||||
("Glaze", "lazy_json", "reads lazily: lazy_json reads only what you ask for and steps over the rest"),
|
||||
("Glaze", "minify_json", "minify_json only removes whitespace, without parsing the values"),
|
||||
("Glaze", "generic", "accepts trailing garbage after the value: Glaze's default (validate_trailing_whitespace checks it)"),
|
||||
("Glaze", "structs", "reads into structs and steps over fields it doesn't know without checking them "
|
||||
"(validate_skipped checks them too)"),
|
||||
("RapidJSON", "", "trusts UTF-8: RapidJSON's default (kParseValidateEncodingFlag checks it)"),
|
||||
("sonic-cpp", "", "trusts UTF-8: sonic-cpp 1.0.2 doesn't check it"),
|
||||
("serde_json", "", "trusts UTF-8 in the strings it skips (from_slice); strings it reads are checked"),
|
||||
]
|
||||
# what a variant that copies number text does (the "N" half of edit, minify and write)
|
||||
NUMBER_TEXT_TIPS = {
|
||||
"nlohmann json_document": "copies each number's text instead of formatting it (number_format::source)",
|
||||
"yyjson": "copies each number's text instead of formatting it (YYJSON_READ_NUMBER_AS_RAW)",
|
||||
"RapidJSON": "copies each number's text instead of formatting it (kParseNumbersAsStringsFlag)",
|
||||
}
|
||||
|
||||
|
||||
def checks_less(lib, variant):
|
||||
for l, v, text in CHECKS_LESS:
|
||||
if l == lib and v in variant:
|
||||
return text
|
||||
return "checks less"
|
||||
|
||||
|
||||
def usecase_table(data):
|
||||
"""{library: {use case: cell}}: per library the geometric mean over UC_FILES of its fastest fully validating time
|
||||
("full") and of its fastest time at any level ("alt", only if it is at least 3 % faster), each divided by the best
|
||||
such fully validating mean in the use case, so that every file counts equally and the fastest library is 1.00"""
|
||||
out = {}
|
||||
data = normalize_usecases(data)
|
||||
for uc, _ in USE_CASES:
|
||||
files = data.get(uc, {})
|
||||
if not files:
|
||||
continue
|
||||
cells = {}
|
||||
for lib in UC_LIBS:
|
||||
es = [files.get(f, {}).get(lib) for f in UC_FILES]
|
||||
if not all(es):
|
||||
continue
|
||||
full = [e["best"] for e in es]
|
||||
alt = [e["best_any"] for e in es]
|
||||
cells[lib] = {"full": geomean([b["us"] for b in full]) if all(full) else None, "alt": geomean([a["us"] for a in alt]),
|
||||
"files": [(f, b, a) for f, b, a in zip(UC_FILES, full, alt)]}
|
||||
ref = min(c["full"] for c in cells.values() if c["full"])
|
||||
for lib, c in cells.items():
|
||||
full = c["full"] / ref if c["full"] else None
|
||||
alt = c["alt"] / ref
|
||||
if full is not None and alt > full * 0.97:
|
||||
alt = None
|
||||
levels = {a["level"] for _, _, a in c["files"]} if alt is not None else set()
|
||||
level = "partial" if "partial" in levels else "no UTF-8" if "no UTF-8" in levels else "full"
|
||||
numtext = alt is not None and any("N" in a["mark"].split() for _, _, a in c["files"])
|
||||
marks = " ".join(m for m in (LEVEL_MARK[level], "N" if numtext else "") if m)
|
||||
out.setdefault(lib, {})[uc] = {"full": full, "alt": alt, "level": level, "marks": marks, "files": c["files"]}
|
||||
return out
|
||||
|
||||
|
||||
# cell colors: green for the fastest, gray around twice the time, red for the slowest; the upper bounds of the steps
|
||||
HEAT_STEPS = [1.15, 1.5, 2.5, 5, float("inf")]
|
||||
HEAT_LABELS = ["below 1.15", "1.15 to 1.5", "1.5 to 2.5", "2.5 to 5", "5 and more"]
|
||||
|
||||
|
||||
def heat(r):
|
||||
return next(i for i, b in enumerate(HEAT_STEPS) if r < b)
|
||||
|
||||
|
||||
def fr(r):
|
||||
return "%.2f" % r if r < 9.995 else "%.1f" % r if r < 99.95 else "%.0f" % r
|
||||
|
||||
|
||||
def fus(us):
|
||||
return "{:,.0f} µs".format(us) if us >= 100 else "%.1f µs" % us
|
||||
|
||||
|
||||
def tip(lib, uc_label, c, half):
|
||||
"""the tooltip of a cell: lines separated by newlines ( in the attribute), the first one the heading"""
|
||||
if half == "full":
|
||||
lines = ["%s · %s" % (UC_LIBS[lib], uc_label),
|
||||
"%s× the time of the fastest library (fully validating)" % fr(c["full"])]
|
||||
picks = [(f, b) for f, b, _ in c["files"]]
|
||||
else:
|
||||
lines = ["%s · %s, checking less" % (UC_LIBS[lib], uc_label),
|
||||
"%s× the time of the fastest fully validating library" % fr(c["alt"])]
|
||||
picks = [(f, a) for f, _, a in c["files"]]
|
||||
ways = sorted({e["variant"] for _, e in picks})
|
||||
if len(ways) == 1:
|
||||
lines.append("way: %s" % ways[0])
|
||||
for f, e in picks:
|
||||
lines.append("%s: %s%s%s" % (FILE_NAMES[f], fus(e["us"]), "" if len(ways) == 1 else " · " + e["variant"],
|
||||
" (validates fully)" if half == "alt" and e["level"] == "full" else ""))
|
||||
if half == "alt":
|
||||
seen = []
|
||||
for _, e in picks:
|
||||
ts = ([checks_less(lib, e["variant"])] if e["level"] != "full" else []) + \
|
||||
([NUMBER_TEXT_TIPS.get(lib, "copies each number's text instead of formatting it")] if "N" in e["mark"].split() else [])
|
||||
for t in ts:
|
||||
if t not in seen:
|
||||
seen.append(t)
|
||||
lines += seen
|
||||
if any("(copy)" in e["variant"] for _, e in picks):
|
||||
lines.append("(copy): parses in place, on a copy of the input that is part of the time")
|
||||
return " ".join(lines)
|
||||
|
||||
|
||||
def heatmap(platform, title):
|
||||
data = json.load((HERE / "data" / ("perf_usecases_%s.json" % platform)).open())
|
||||
t = usecase_table(data)
|
||||
libs = [l for l in UC_LIBS if l in t]
|
||||
score = lambda l: geomean([v["full"] or v["alt"] for v in t[l].values()]) # the mean of the row as shown
|
||||
libs.sort(key=score)
|
||||
W, L, cw, ch, top = 784, 224, 92, 36, 44
|
||||
b, desc = [], []
|
||||
for j, (uc, label) in enumerate(USE_CASES):
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">%s</text>' % (L + j * cw + cw / 2, top - 10, esc(label)))
|
||||
for i, lib in enumerate(libs):
|
||||
y = top + i * ch
|
||||
cls = "nj-charts-name-json" if lib.startswith("nlohmann") else ""
|
||||
b.append('<text class="nj-charts-rowlabel %s" x="%g" y="%g" text-anchor="end">%s</text>' % (cls, L - 8, y + ch / 2 + 4, esc(UC_LIBS[lib])))
|
||||
for j, (uc, label) in enumerate(USE_CASES):
|
||||
x = L + j * cw
|
||||
c = t[lib].get(uc)
|
||||
if c is None:
|
||||
b.append('<g class="nj-heat-cell" tabindex="0" data-tip="%s">' % esc("%s · %s %s" % (UC_LIBS[lib], label, NA.get((lib, uc), "the library has no API for this use case"))))
|
||||
b.append('<rect class="nj-heat-na" x="%g" y="%g" width="%g" height="%g" rx="3"/>' % (x + 1, y + 1, cw - 2, ch - 2))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">n/a</text>' % (x + cw / 2, y + ch / 2 + 4))
|
||||
b.append('</g>')
|
||||
desc.append("%s %s: n/a" % (UC_LIBS[lib], label))
|
||||
continue
|
||||
halves = []
|
||||
if c["full"] is not None:
|
||||
halves.append(("full", c["full"]))
|
||||
if c["alt"] is not None:
|
||||
halves.append(("alt", c["alt"]))
|
||||
hw = (cw - 2) / len(halves)
|
||||
for k, (half, r) in enumerate(halves):
|
||||
hx = x + 1 + k * hw
|
||||
gap = 1 if len(halves) == 2 else 0
|
||||
b.append('<g class="nj-heat-cell" tabindex="0" data-tip="%s">' % esc(tip(lib, label, c, half)))
|
||||
b.append('<rect class="nj-heat-%d" x="%g" y="%g" width="%g" height="%g" rx="3"/>'
|
||||
% (heat(r), hx + (gap if k else 0), y + 1, hw - gap, ch - 2))
|
||||
cx = hx + hw / 2
|
||||
if half == "alt":
|
||||
b.append('<text class="nj-charts-cell" x="%g" y="%g" text-anchor="middle">%s</text>' % (cx, y + 16, fr(r)))
|
||||
b.append('<text class="nj-charts-cell nj-charts-cell--small" x="%g" y="%g" text-anchor="middle">%s</text>'
|
||||
% (cx, y + 29, c["marks"]))
|
||||
else:
|
||||
b.append('<text class="nj-charts-cell" x="%g" y="%g" text-anchor="middle">%s</text>' % (cx, y + ch / 2 + 4, fr(r)))
|
||||
b.append('</g>')
|
||||
if c["full"] is None: # no fully validating way: the left half stays empty
|
||||
pass
|
||||
desc.append("%s %s: %s%s" % (UC_LIBS[lib], label, fr(c["full"]) if c["full"] else "no fully validating way",
|
||||
(" (%s doing less, %s)" % (fr(c["alt"]), c["marks"])) if c["alt"] else ""))
|
||||
# the key, set apart from the grid and narrower than its columns, so that it doesn't read as a row of it
|
||||
yb = top + len(libs) * ch + 28
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="8" y="%g">time relative to the fastest fully validating library, less is better</text>' % (yb + 4))
|
||||
kw, ky = 76, yb + 14
|
||||
for i, lab in enumerate(HEAT_LABELS):
|
||||
# each swatch in its own group, so that the ink rule for the strong steps (a sibling selector) stays inside it
|
||||
b.append('<g><rect class="nj-heat-%d" x="%g" y="%g" width="%g" height="20" rx="3"/>' % (i, 8 + i * (kw + 4), ky, kw))
|
||||
b.append('<text class="nj-charts-cell nj-charts-cell--small" x="%g" y="%g" text-anchor="middle">%s</text></g>' % (8 + i * (kw + 4) + kw / 2, ky + 14, esc(lab)))
|
||||
nx = 8 + len(HEAT_LABELS) * (kw + 4) + 12
|
||||
b.append('<rect class="nj-heat-na" x="%g" y="%g" width="%g" height="20" rx="3"/>' % (nx, ky, 40))
|
||||
b.append('<text class="nj-charts-tick" x="%g" y="%g">n/a</text>' % (nx + 20, ky + 14))
|
||||
b.append('<text class="nj-charts-tick nj-charts-tick--l" x="%g" y="%g">no API for it</text>' % (nx + 48, ky + 14))
|
||||
write("perf_blog_usecases_%s.svg" % platform, W, ky + 28, "nj-charts--blog nj-charts--heat", "nj-blog-uc-" + platform, title,
|
||||
"Table of relative times, libraries by use case. " + "; ".join(desc) + ".", b)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
swar()
|
||||
overlap()
|
||||
digits()
|
||||
heldout()
|
||||
if OVERVIEW:
|
||||
overview()
|
||||
distribution()
|
||||
if TIMELINE:
|
||||
timeline()
|
||||
if CLIFFS:
|
||||
cliffs()
|
||||
price()
|
||||
for platform, title in UC_PLATFORMS:
|
||||
if (HERE / "data" / ("perf_usecases_%s.json" % platform)).exists():
|
||||
heatmap(platform, title)
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Prints the tables of Appendix E of home/blog/how_3_13_0_got_faster.md (comparison with other libraries) as Markdown,
|
||||
from data/perf_usecases_<platform>.json, which tests/benchmarks/json_view/others/summarize.py --json writes.
|
||||
|
||||
Usage: python3 scripts/figures/perf_blog_tables.py <platform> [title]
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from perf_blog import normalize_usecases
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
FILES = [("twitter", "`twitter.json`"), ("citm_catalog", "`citm_catalog.json`"), ("canada", "`canada.json`"),
|
||||
("jeopardy", "`jeopardy.json`"), ("status", "one status (2.5 KB)")]
|
||||
USE_CASES = [("validate", "validate"), ("sum", "sum"), ("select", "select"), ("edit", "edit"), ("minify", "minify"),
|
||||
("write", "write")]
|
||||
NAMES = {"nlohmann json_document": "nlohmann/json `json_document`", "nlohmann json": "nlohmann/json `json`",
|
||||
"sonic-rs": "sonic-rs (Rust)", "simd-json": "simd-json (Rust)", "serde_json": "serde_json (Rust)"}
|
||||
|
||||
|
||||
def fmt(us):
|
||||
if us >= 10000:
|
||||
return "{:,.0f}".format(us)
|
||||
if us >= 100:
|
||||
return "{:,.0f}".format(us)
|
||||
return "%.1f" % us
|
||||
|
||||
|
||||
def table(data, uc, indent):
|
||||
files = [f for f, _ in FILES if f in data.get(uc, {})]
|
||||
libs = list(data[uc][files[0]].keys())
|
||||
jd = lambda f: data[uc][f]["nlohmann json_document"]["best"]["us"]
|
||||
libs.sort(key=lambda l: sum(((data[uc][f][l]["best"] or data[uc][f][l]["best_any"])["us"] / jd(f)) for f in files))
|
||||
head = "| library | variant | " + " | ".join(n for f, n in FILES if f in files) + " |"
|
||||
rows = [head, "| --- | --- | " + " | ".join("--:" for _ in files) + " |"]
|
||||
for lib in libs:
|
||||
best = [data[uc][f][lib]["best"] for f in files]
|
||||
anyv = [data[uc][f][lib]["best_any"] for f in files]
|
||||
names = sorted({b["variant"] for b in best if b} | {a["variant"] + " [%s]" % a["mark"] for b, a in zip(best, anyv) if a["mark"] and (not b or a["us"] < b["us"])})
|
||||
cells = []
|
||||
for b, a in zip(best, anyv):
|
||||
c = fmt(b["us"]) if b else "–"
|
||||
if a["mark"] and (not b or a["us"] < b["us"] * 0.97):
|
||||
c += " (%s %s)" % (a["mark"], fmt(a["us"]))
|
||||
cells.append(c)
|
||||
bold = "**%s**" if lib == "nlohmann json_document" else "%s"
|
||||
rows.append("| %s | %s | %s |" % (bold % NAMES.get(lib, lib), ", ".join(names), " | ".join(cells)))
|
||||
return "\n".join(indent + r for r in rows)
|
||||
|
||||
|
||||
def main():
|
||||
platform = sys.argv[1]
|
||||
data = json.load((HERE / "data" / ("perf_usecases_%s.json" % platform)).open())
|
||||
data = normalize_usecases(data) # the same choices as the figure
|
||||
out = []
|
||||
for uc, label in USE_CASES:
|
||||
if uc not in data:
|
||||
continue
|
||||
out.append("**%s**\n" % label)
|
||||
out.append(table(data, uc, ""))
|
||||
out.append("")
|
||||
print("\n".join(out))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user