////
Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
Copyright (c) 2025 Dmitry Arkhipov (grisumbras@yandex.ru)

Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Official repository: https://github.com/boostorg/json
////

[pagelevels=1,toclevels=1]
= Benchmarks
This section compares the performance of Boost.JSON with two widely used
libraries with similar functionality: RapidJSON which is known for its
performance, and JSON for Modern C++ which is known for feature-richness. The
bench program measures the throughput of parsing and serialization for the
a set of JSON representing typical workloads. These implementations are
evaluated:

.Implementations
|===
|Name|Description

| *boost(pool)*
| Parses the input using a <<ref_monotonic_resource>>,
        which is optimized for parsing without subsequent
        modification.
        The <<ref_stream_parser>> object is reused between
        trials, allowing temporary memory allocated by the
        implementation to persist and improve performance.

| *boost*
| Parses the input using the <<default_memory_resource, default memory
 resource>>, which uses the standard C++ allocator, and is designed for general
 use including mutation of the document after it is parsed. The
 <<ref_stream_parser>> object is reused between trials, allowing temporary
 memory allocated by the implementation to persist and improve performance.

| *rapidjson(pool)*
| Parses the input using an instance of
  https://rapidjson.org/classrapidjson_1_1_memory_pool_allocator.html[`MemoryPoolAllocator`],
  which is optimized for parsing without subsequent modification. The
  https://rapidjson.org/classrapidjson_1_1_generic_document.html[`Document`]
  object holding temporary memory is not reused between trials, otherwise
  memory consumption grows without bounds and invalidates the benchmark.

| *rapidjson*
| Parses the input using an instance of
  https://rapidjson.org/classrapidjson_1_1_crt_allocator.html[`CrtAllocator`],
  which uses the standard C++ allocator, and is designed for general use
  including mutation of the document after it is parsed. The
  https://rapidjson.org/classrapidjson_1_1_generic_document.html[`Document`]
  object holding temporary memory is not reused between trials, otherwise
  memory consumption grows without bounds and invalidates the benchmark.

| *nlohmann*
| Parses the input using the static member function
  https://nlohmann.github.io/json/classnlohmann_1_1basic__json_ab330c13ba254ea41fbc1c52c5c610f45.html[`json::parse`],
  which uses the default `std` allocator, and is designed for general use
  including mutation of the document after it is parsed. This library does not
  provide an interface to reuse temporary storage used during parsing or
  serialization on subsequent operations.
|===

== Methodology
The input files are all loaded first. Then each configuration is run for
a sufficient number of trials to last at least 5 seconds. The elapsed time,
number of invocations (of parse or serialize), and bytes transferred are
emitted as a sample along with a calculation of throughput expressed in
megabytes per second. Several samples (currently five) are generated for each
configuration. All but the median two samples are discarded, with the remaining
samples averaged to produce a single number which is reported as the benchmark
result.

The input files, available in the bench/data directory, are laid out thusly:

.Input Files
|===
|Name|Size|Description

| <<parse_apache_builds_json,*apache_builds.json*>>
| 125KB
| Data from the Apache Jenkins installation.

| <<parse_canada_json,*canada.json*>>
| 2.2MB
| The largest file, containing a large number of 2-element arrays holding
  floating-point coordinate pairs.

| <<parse_citm_catalog_json,*citm_catalog.json*>>
| 1.69MB
| A large JSON with a variety of nesting, types, and lengths.

| <<parse_github_events_json,*github_events.json*>>
| 64KB
| An export of data from the Github Events API.

| <<parse_gsoc_2018_json,*gsoc-2018.json*>>
| 3.25MB
| Google Summer of Code 2018 data.

| <<parse_instruments_json,*instruments.json*>>
| 216KB
| An array of large objects.

| <<parse_marine_ik_json,*marine_ik.json*>>
| 2.91MB
| A three.js example model serialized to JSON.

| <<parse_mesh_json,*mesh.json*>>
| 707KB
| A JSON representing a 3D mesh. Contains many floating-point numbers.

| <<parse_mesh_pretty_json,*mesh.pretty.json*>>
| 1.54MB
| mesh.json with whitespace added.

| <<parse_numbers_json,*numbers.json*>>
| 147KB
| A array containing only floating-point numbers.

| <<parse_random_json,*random.json*>>
| 499KB
| A JSON with lots of Cyrillic characters.

| <<parse_twitter_json,*twitter.json*>>
| 617KB
| An export of data from Twitter's API.

| <<parse_twitterescaped_json,*twitterescaped.json*>>
| 550KB
| twitter.json with whitespace removed and non-ASCII characters replaced with
  Unicode escapes.

| <<parse_update_center_json,*update-center.json*>>
| 521KB
| An export of data from Twitter's API.
|===

Hardware used for testing: **Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz**,
Windows 10, 32GB RAM.

Compilers and optimization flags: gcc 8.1 (-O3), clang 12.0 (-O3), and msvc
19.26 (/O2).

== Parsing

=== Parse apache_builds.json
image::images/parse_apache_builds.png[width=668,height=712]

=== Parse canada.json
image::images/parse_canada.png[width=668,height=712]

=== Parse citm_catalog.json
image::images/parse_citm_catalog.png[width=668,height=712px]

=== Parse github_events.json
image::images/parse_github_events.png[width=668,height=712]

=== Parse gsoc-2018.json
image::images/parse_gsoc_2018.png[width=668,height=712]

=== Parse instruments.json
image::images/parse_instruments.png[width=668,height=712]

=== Parse marine_ik.json
image::images/parse_marine_ik.png[width=668,height=712]

=== Parse mesh.json
image::images/parse_mesh.png[width=668,height=712]

=== Parse mesh.pretty.json
image::images/parse_mesh_pretty.png[width=668,height=712]

=== Parse numbers.json
image::images/parse_numbers.png[width=668,height=712]

=== Parse random.json
image::images/parse_random.png[width=668,height=712]

=== Parse twitter.json
image::images/parse_twitter.png[width=668,height=712]

=== Parse twitterescaped.json
image::images/parse_twitterescaped.png[width=668,height=712]

=== Parse update-center.json
image::images/parse_update_center.png[width=668,height=712]

== Serialization

=== Serialize canada.json
image::images/serialize_canada.png[width=668,height=712]

=== Serialize citm_catalog.json
image::images/serialize_citm_catalog.png[width=668,height=712]

=== Serialize github_events.json
image::images/serialize_github_events.png[width=668,height=712]

=== Serialize gsoc-2018.json
image::images/serialize_gsoc_2018.png[width=668,height=712]

=== Serialize instruments.json
image::images/serialize_instruments.png[width=668,height=712]

=== Serialize marine_ik.json
image::images/serialize_marine_ik.png[width=668,height=712]

=== Serialize mesh.json
image::images/serialize_mesh.png[width=668,height=712]

=== Serialize mesh.pretty.json
image::images/serialize_mesh_pretty.png[width=668,height=712]

=== Serialize numbers.json
image::images/serialize_numbers.png[width=668,height=712]

=== Serialize random.json
image::images/serialize_random.png[width=668,height=712]

=== Serialize twitter.json
image::images/serialize_twitter.png[width=668,height=712]

=== Serialize twitterescaped.json
image::images/serialize_twitterescaped.png[width=668,height=712]

=== Serialize update-center.json
image::images/serialize_update_center.png[width=668,height=712px]
