{"id":19904179,"url":"https://github.com/bertptrs/json-speedtest","last_synced_at":"2026-05-09T22:02:41.908Z","repository":{"id":68622162,"uuid":"232102513","full_name":"bertptrs/json-speedtest","owner":"bertptrs","description":"Testing out different JSON libraries for performance","archived":false,"fork":false,"pushed_at":"2020-01-06T13:07:30.000Z","size":157,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-11T21:32:06.782Z","etag":null,"topics":["cpp","json","performance-analysis"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bertptrs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-06T13:05:58.000Z","updated_at":"2020-01-06T13:09:28.000Z","dependencies_parsed_at":"2023-02-21T12:16:21.985Z","dependency_job_id":null,"html_url":"https://github.com/bertptrs/json-speedtest","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertptrs%2Fjson-speedtest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertptrs%2Fjson-speedtest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertptrs%2Fjson-speedtest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertptrs%2Fjson-speedtest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bertptrs","download_url":"https://codeload.github.com/bertptrs/json-speedtest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241331737,"owners_count":19945437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","json","performance-analysis"],"created_at":"2024-11-12T20:27:17.489Z","updated_at":"2026-05-09T22:02:41.797Z","avatar_url":"https://github.com/bertptrs.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSON speed test\n\nIn this repository we attempt to compare the (de)serialization performance of\nvarious JSON libraries. Here, we test the following json serialization\nlibraries:\n\n- [epee](https://github.com/hyle-team/epee), the library currently in use by\n  [Monero project](https://github.com/monero-project/monero/). Serialization\n  is intrusive (part of the actual struct) and heavily macro based. It is\n  theoretically header-only but it does depend indirectly on `easylogging++`.\n\n- [JSON for Modern C++](https://github.com/nlohmann/json), also known as\n  `nlohmann/json` or just `nlohmann` is one of the most widely used JSON\n  libraries for C++11 and offers a DOM-based API for easy (de)serialization.\n\n- [RapidJSON](https://rapidjson.org/) is a high-performance JSON serialization\n  library designed for speed over convenience. It requires significant input\n  from the API consumer on memory management, but it is also about as fast as\n  `strlen()`.\n\n- [json_dto](https://github.com/Stiffstream/json_dto) is a relatively new, thin\n  wrapper for RapidJSON. It abstracts away the rough edges and provides you\n  with primitives that you can use to easily serialize your own types, as well\n  as standard library types. The library may be a little less common, but the\n  heavy lifting of securely parsing JSON is left to the well tested\n  RapidJSON.\n\nIn the table below you can see a short summary of the code-quality\n\n| Library | C++ | Maintainer responsiveness | Github stars | Contributors | Notoriety |\n| --- | --- | --- | --- | --- | --- |\n| epee | C++11 | n/a | n/a | 1, maybe | n/a |\n| nlohmann/json | C++11 | 1 day | 16.9k | 147 | De-facto standard |\n| RapidJSON | C++03, C++11 | Wildly varying | 8.7k | 139, backed by Tencent | Well-known high-performance JSON library |\n| `json_dto` | C++14 | 1 day | 31 | 3 | Small wrapper around RapidJSON adding lots of quality-of-life improvements while not doing heavy lifting. |\n\n\n## Included code and licenses\n\nThis project includes code from `epee` by Andrey N. Sabelnikov, and code from\nEasylogging++. All code is copyright their respective authors.\n\n## Requirements\n\nThis speed test project targets C++17 for brevity, however this is not a\ntechnical requirement, and the code can be easily converted to target older\nversions of C++.\n\nFor most projects under test, the minimal C++ version is 11, however,\n`json_dto` requires C++14. Support for C++14 is currently widespread and\navailable in the default GCC bundled with the LTS versions of all major\nLinux distributions, as well as Apple and Windows.\n\nThe speedtest can be built with CMake. It will search the system for library\nlocations for `nlohmann`, RapidJSON, and `json_dto`. The usual overrides for\n[`find_package`](https://cmake.org/cmake/help/latest/command/find_package.html)\napply. `epee` and `easylogging++` are included in-tree.\n\n## Implementation\n\nEach JSON implementation has its own compile unit in `src`. This allows us to\neffectively measure the binary size and compilation time for each\nimplementation. Each implementation exposes a pair of functions: one to\ndeserialize from a string view to a struct, and one to serialize that struct to\na string. The struct definition is trivial, but shared between the\nimplementations.\n\nAn exception to this is the implementation for `epee`, since it has to be\nimplemented intrusively. To keep the comparison fair, `epee` therefore\nserializes objects of type `EpeeSampleStruct`.\n\nLooking at the different implementation files, it is easy to see that\nthere's a difference in ergonomics between the libraries. RapidJSON\nreqiures a lot more code to express the same thing as `json_dto` does.\n\n## Usage\n\nThe speed test executable can be called as follows:\n\n```\n./speedtest IMPLEMENTATION SAMPLE_FILE\n# example\n./speedtest nlohmann ../sample.json\n```\n\nwhere the sample file is a file that can be deserialized as a `SampleStruct`.\nRefer to `sample.json` for an example. The struct and the sample file are\nchosen to be similar to generic RPC call arguments without being specific\nto any given application. It includes strings, numbers, booleans, arrays,\nand nested structs.\n\nThe complete measurements can be run using the `test.sh` script.\n\n## Test results\n\nWe measure the following metrics for each implementation:\n\n- total compiled size, using [Bloaty](https://github.com/google/bloaty),\n  (`bloaty -d compileunits`)\n- total compile time, using `command time` to measure the compile time for the\n  specific unit,\n- run time per iteration of deserializing/serializing averaged over 100000\n  cycles,\n- total number of allocations over the above iterations,\n- total number of bytes allocated over the above iterations.\n\nThe following table shows the result of our testing with\n[`sample.json`](./sample.json) as the input file. Lower values are\nbetter.\n\n| implementation | compile size | compile time | run time per iteration (ns) | num allocations | bytes allocated |\n| --- | ---: | ---: | ---: | ---: | ---: |\n| `epee` | 376791 | 10.96 | 4010.770 | 4000367 | 0.49 Gib |\n| `nlohmann` | 118827 | 3.12 | 4122.610 | 8800367 | 0.39 GiB |\n| `rapidjson` | 10881 | 1.32 | 961.692 | 1800369 | 12.42 GiB |\n| `json_dto` | 59809 | 1.45 | 967.808 | 1700369 | 12.42 GiB |\n\nIf we use a slightly larger file\n([`sample-large.json`](./sample-large.json)) as input, the differences\nbecome more apparent:\n\n| implementation | run time per iteration (ns) | num allocations | bytes allocated |\n| --- | ---: | ---: | ---: |\n| `epee` | 32157.40 | 23400337 | 7.33 GiB |\n| `nlohmann` | 28405.90 | 52100353 | 2.87 GiB |\n| `rapidjson` | 5453.87 | 2400369 | 12.60 GiB |\n| `json_dto` | 4112.31 | 1900369 | 12.56 GiB |\n\nSome caveats apply: memory usage always includes 365 allocations for the\ninitialization of `easylogging`, which results in approximately 15kb more\nallocated. The compile size and time for `epee` does not include the size\nof its dependency `easylogging`.\n\nIt should be noted that the number of bytes allocated is a total number, not\nto be confused with the maximum resident set. Maximum resident set is\ncomparable and negligible between the different implementations.\n\nWe can see that `epee` is outperformed by every other JSON library. RapidJSON\n(and by extension `json_dto`) does larger but less frequent allocations than\nthe other two. It makes up for this by doing less allocations in total as well\nas significantly better performance. The difference also becomes smaller\nas file size increases.\n\n### Compilation comparison\n\n![Comparison of compilation of different\nimplementations](./graphs/compile.svg)\n\n### Performance on `sample.json`\n\n![Run time for different implementations](./graphs/runtime.svg)\n\n![Comparison of memory allocations](./graphs/allocations.svg)\n\n### Performance on `sample-large.json`\n\n![Run time for different implementations](./graphs-large/runtime.svg)\n\n![Comparison of memory allocations](./graphs-large/allocations.svg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbertptrs%2Fjson-speedtest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbertptrs%2Fjson-speedtest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbertptrs%2Fjson-speedtest/lists"}