Repository navigation
Compare json_view with yyjson, simdjson, and Boost.JSON - #5627
Merged
Merged
Conversation
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
September 30, 2026 13:20
f72abf8 to
acf0cc4
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
3 times, most recently
from
September 30, 2026 18:06
c7a8571 to
13dbe93
Compare
nlohmann
marked this pull request as ready for review
September 30, 2026 18:17
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
September 30, 2026 19:15
13dbe93 to
a91f6f4
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 6, 2026 09:28
1d49222 to
f39b5b1
Compare
nlohmann
changed the base branch from
json-view/14b-view-float-layout
to
json-view/22-view-dump-fast
October 6, 2026 09:29
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 7, 2026 14:44
f39b5b1 to
eb34240
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 17, 2026 06:02
677089d to
7ee0248
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 17, 2026 06:33
7ee0248 to
c590911
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 17, 2026 12:28
c590911 to
2b98fb7
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 17, 2026 21:25
2b98fb7 to
bc532e9
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 02:27
bc532e9 to
c2fd058
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 04:25
c2fd058 to
3298199
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
2 times, most recently
from
October 18, 2026 08:38
0d324d3 to
cbdc9ff
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 08:54
cbdc9ff to
ba41476
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 11:41
ba41476 to
4747b35
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 12:52
4747b35 to
00b7d24
Compare
1 of 4 tasks
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 18, 2026 20:30
00b7d24 to
7ac4e04
Compare
nlohmann
force-pushed
the
json-view/15-view-bench
branch
from
October 19, 2026 15:59
7ac4e04 to
83e0829
Compare
tests/benchmarks/json_view/ holds a comparison with other libraries, answering the question users ask when they pick one. It is not built by CMake and not run by CI. - bench_view.cpp: parse, traverse, select and dump of twitter, citm_catalog, canada, jeopardy, a tweet and an RPC request, against json_view, yyjson, simdjson, Boost.JSON and json::parse, all agreeing and run interleaved. - bench_corpus.cpp: parse, traverse and dump of any file list. - bench_edit.cpp: parses, edits through each library's own API, and serializes; all outputs must describe the same value. - compare.py: builds both programs with system or pinned, SHA-256-checked downloads, and writes results with the commit, CPU, OS, compiler and library versions. - README.md and a workflow that runs on demand or via a PR label. Fairness fixes folded in: each engine runs once untimed before each timed round, so the next one no longer pays for the previous one's cleanup; dump is also compared with source numbers against yyjson's raw-number mode; a "simdjson DOM (fresh)" column and a reused-document column for json_view were added; compare.py's paths are absolute; downloads use a .part file and a failed checksum removes the archive. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Hash the archives in chunks instead of reading them into memory, download with a timeout, extract into a temporary directory that is renamed into place only after success (a half-extracted directory was trusted forever), and split CXX and CC into arguments so that values like 'ccache g++' work. Note at the pins that a SHA-256 mismatch of a GitHub tag archive means that GitHub regenerated it. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
fopen() of the CSV output was not checked, so an unwritable directory made fprintf() write to a null FILE*; the round count is parsed with strtol and clamped instead of atoi. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of the stack for the zero-copy view (#5295). This PR adds a benchmark comparison of
json_viewwith other libraries, and a workflow to run it on GitHub-hosted runners. It is the last PR of the stack: the PRs below it are merged into develop, and this one measures their parser and serializer work.Summary
tests/benchmarks/json_view/holds a comparison with other libraries. It answers the question users ask when they pick a library. It is not built by CMake and not run by CI.bench_view.cpp: parse, traverse, select, and dump of twitter, citm_catalog, canada, jeopardy, a single tweet, and a JSON-RPC request.json::parse.bench_corpus.cpp: parse, traverse, and dump of any list of files. Files that cannot be opened are reported instead of aborting the run.bench_edit.cpp: parses, applies the same logical edits with each library's own API (a handful at fixed places, or one in every record), and serializes; all outputs must describe the same value.compare.py: reproduces the numbers with one command.include/, using the libraries of the system (pkg-config or Homebrew) or pinned downloads (--download): yyjson 0.13.0, simdjson 4.6.11, and Boost 1.92.0..partfile. Each archive is hashed in chunks and checked against its SHA-256; an archive that does not match is removed. It is extracted into a temporary directory that is renamed when complete, so an interrupted run is not mistaken for a finished one.--data,--corpusand--build-dirare made absolute, since the benchmarks run in the build directory.CXXandCCmay contain arguments (they are split withshlex).results/<date>-<host>.mdand.csv, together with the date, commit, CPU, OS, compiler, flags, and library versions.README.md: how to run the comparison, what is measured, and which features each engine has, so that the numbers can be read correctly..github/workflows/json_view_benchmarks.yml: runscompare.py --downloadon GitHub-hosted Ubuntu runners and shows the results as the job summary and as an artifact.workflow_dispatch: x86-64 or AArch64, GCC or Clang), or by adding the labelbenchmarkto a pull request (both architectures, GCC).timeout-minutes: 60and aconcurrencygroup keyed by the label, so adding an unrelated label does not cancel a running benchmark.json_viewstands on another architecture; they are not for publication..github/labeler.ymllabels changes undertests/benchmarks/json_view/.Fair comparison
json::parsepays for the allocator cleaning up the tens of thousands of nodesjson::parsejust freed (with glibc, this madejson_viewlook 1.7 times slower than yyjson on citm_catalog traverse).bench_corpuscompares the dump with source numbers (number_format::source) against yyjson writing numbers read as raw text (YYJSON_READ_NUMBER_AS_RAW); both write the same bytes.JSON_VIEW_BENCH_BOOST;--no-boost).No results are committed. They should come from a quiet machine and include x86-64; the benchmark workflow gives a first x86-64 impression (label
benchmark).Performance
No library code changes in this PR. The numbers below were measured on 2026-10-21 at this PR's head 774ea21 (develop bd5227c with the whole json_view stack merged, plus this PR), with
compare.py --download --rounds 30(-O3), fresh documents, µs, best round. Libraries: yyjson 0.13.0, simdjson 4.6.11, Boost 1.92.0.taskset -c 5. The machine has a load of about 3 from other services, so identical runs differ by up to ±10%.json_viewis ahead of yyjson in every row, with both compilers and on both architectures.json_viewdocument pays for the page faults of 4 KiB pages; with a reused document (json_view (reused)) it takes 47 ms with GCC and 43 ms with Clang, ahead of simdjson. A fresh simdjson DOM takes 131–132 ms.Dump with the numbers of the input (µs; same output bytes), GCC / Clang / M1:
On canada on x86-64, yyjson's lead is mostly the zero-fill of
std::string::resize(), which yyjson'smalloced output does not have.bench_edit(parse, edit, serialize;patch):Comparison with the previous numbers
Each row of
bench_view,bench_corpus, andbench_editwas compared with the json_view stack tip of 2026-10-16 (4933b60), with the same harness. On the M1 that is one old run and two new ones; on x86-64 (Clang) two old runs and three new runs, interleaved; best of each:bench_editcitm_catalog update (+3.3%), canada patch (+3.4%; yyjson also +3.7%), and the 55 MB jeopardy inbench_corpus(parse with a reused document +4.9%, traverse +3.3%; the same parse inbench_viewis 3.9% faster). Single old runs differ from each other by up to 13% in the same rows, so none of them is a measured regression.Some figures in the previous version of this description were worse than these numbers or were too optimistic. In detail:
What tuning does not close: canada traverse (the lazy float conversion runs at fast_float's speed; yyjson converts during the parse) and canada dump with number conversion (converting each 17-digit token to a double during the dump). Both are larger on the M1 than on x86-64.
Tests
None: this PR adds benchmarks, not unit tests. The benchmarks require all engines to agree on every document's content before any timing starts.
compare.pyis not run by CI.Public API
No breaking changes, and no change to the API: this PR only adds files under
tests/benchmarks/json_view/, a GitHub Actions workflow, and a labeler rule. Nothing ininclude/changes.Written by Claude Code.
🤖 Generated with Claude Code