Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fair play with JSON #335

Merged
merged 10 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,27 +200,42 @@ Testing base64 encoding/decoding of the large blob into the newly allocated buff

Testing parsing and simple calculating of values from a big JSON file.

NOTE: D implementations except Mir-based (like Ion and Asdf) have
[inaccurate number parsing](https://issues.dlang.org/show_bug.cgi?id=20967).
NOTE: DAW JSON Link NoCheck doesn't perform JSON structure correctness checks.

NOTE: DAW JSON Link, gason, 'fast', default (not Pricese) RapidJSON, and D implementations except Mir-based
have inaccurate IEEE incompatible number parsing.
<small>
- [DAW JSON Link's number parsing issue](https://github.com/beached/daw_json_link/issues/226),
- [gason's number parsing issue](https://github.com/vivkin/gason/issues/35)
- ['fast' number parsing issue](https://github.com/mleise/fast/issues/19)
- [D stdlib number parsing issue](https://issues.dlang.org/show_bug.cgi?id=20967)
</small>

NOTE: gason mutates input strings.

NOTE: simdjson and 'fast' (D) require input strings with batch of trailing zeros: a special zero padding for SIMD instructions.

[Json](json)

| Language | Time, s | Memory, MiB | Energy, J |
| :------------------------------ | ----------------------: | --------------------------------------------------: | ----------------------: |
| C++/g++ (DAW JSON Link) | 0.079<sub>±0.002</sub> | 109.22<sub>±00.01</sub> + 0.00<sub>±00.00</sub> | 1.92<sub>±00.07</sub> |
| C++/g++ (DAW JSON Link NoCheck) | 0.079<sub>±0.001</sub> | 112.82<sub>±00.23</sub> + 0.00<sub>±00.00</sub> | 2.24<sub>±00.04</sub> |
| C++/g++ (simdjson On-Demand) | 0.081<sub>±0.002</sub> | 109.87<sub>±00.03</sub> + 59.55<sub>±00.00</sub> | 1.86<sub>±00.11</sub> |
| D/gdc (fast) | 0.099<sub>±0.002</sub> | 219.96<sub>±00.07</sub> + 11.34<sub>±00.00</sub> | 2.44<sub>±00.17</sub> |
| C++/g++ (DAW JSON Link) | 0.114<sub>±0.002</sub> | 112.64<sub>±00.03</sub> + 0.00<sub>±00.00</sub> | 3.25<sub>±00.10</sub> |
| Rust (Serde Typed) | 0.125<sub>±0.004</sub> | 108.53<sub>±00.05</sub> + 11.77<sub>±00.26</sub> | 3.01<sub>±00.16</sub> |
| Rust (Serde Custom) | 0.133<sub>±0.002</sub> | 108.38<sub>±00.05</sub> + 0.00<sub>±00.00</sub> | 2.53<sub>±00.12</sub> |
| C++/g++ (simdjson DOM) | 0.148<sub>±0.004</sub> | 109.88<sub>±00.04</sub> + 176.60<sub>±00.00</sub> | 3.69<sub>±00.23</sub> |
| C++/g++ (gason) | 0.159<sub>±0.001</sub> | 109.21<sub>±00.01</sub> + 97.17<sub>±00.03</sub> | 3.02<sub>±00.09</sub> |
| C++/g++ (RapidJSON) | 0.221<sub>±0.006</sub> | 109.24<sub>±00.01</sub> + 128.82<sub>±00.00</sub> | 4.56<sub>±00.48</sub> |
| D/ldc2 (Mir Amazon's Ion) | 0.231<sub>±0.003</sub> | 109.38<sub>±00.07</sub> + 16.11<sub>±00.01</sub> | 4.86<sub>±00.12</sub> |
| D/ldc2 (Mir Asdf) | 0.238<sub>±0.005</sub> | 109.45<sub>±00.04</sub> + 57.83<sub>±00.00</sub> | 4.92<sub>±00.27</sub> |
| D/ldc2 (Mir Amazon's Ion DOM) | 0.231<sub>±0.003</sub> | 109.38<sub>±00.07</sub> + 16.11<sub>±00.01</sub> | 4.86<sub>±00.12</sub> |
| D/ldc2 (Mir Asdf DOM) | 0.238<sub>±0.005</sub> | 109.45<sub>±00.04</sub> + 57.83<sub>±00.00</sub> | 4.92<sub>±00.27</sub> |
| C++/g++ (RapidJSON Precise) | 0.283<sub>±0.003</sub> | 113.09<sub>±00.03</sub> + 128.71<sub>±00.06</sub> | 6.70<sub>±00.11</sub> |
| C++/g++ (Boost.JSON) | 0.498<sub>±0.009</sub> | 109.81<sub>±00.03</sub> + 435.70<sub>±00.00</sub> | 10.00<sub>±00.67</sub> |
| Java | 0.508<sub>±0.007</sub> | 253.80<sub>±00.21</sub> + 70.03<sub>±01.09</sub> | 13.87<sub>±00.33</sub> |
| C++/g++ (RapidJSON SAX) | 0.530<sub>±0.008</sub> | 109.44<sub>±00.02</sub> + 0.00<sub>±00.00</sub> | 11.80<sub>±00.31</sub> |
| Scala | 0.589<sub>±0.011</sub> | 307.27<sub>±00.60</sub> + 74.61<sub>±00.32</sub> | 14.93<sub>±00.66</sub> |
| C++/g++ (RapidJSON SAX Precise) | 0.600<sub>±0.008</sub> | 112.90<sub>±00.03</sub> + 0.00<sub>±00.00</sub> | 14.76<sub>±00.25</sub> |
| Node.js | 0.632<sub>±0.026</sub> | 242.44<sub>±00.02</sub> + 185.01<sub>±00.27</sub> | 15.47<sub>±01.24</sub> |
| Go (jsoniter) | 0.653<sub>±0.014</sub> | 224.31<sub>±00.14</sub> + 13.69<sub>±00.22</sub> | 14.46<sub>±00.73</sub> |
| Crystal (Schema) | 0.783<sub>±0.008</sub> | 110.38<sub>±00.03</sub> + 46.88<sub>±00.11</sub> | 12.28<sub>±00.20</sub> |
Expand Down
18 changes: 16 additions & 2 deletions json/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ executables := \
target/json_boost_json_cpp \
target/json_rapid_cpp \
target/json_rapid_sax_cpp \
target/json_rapid_cpp_precised \
target/json_rapid_sax_cpp_precised \
target/json_gason_cpp \
target/json_libjson_cpp \
target/json_hs \
Expand All @@ -42,6 +44,7 @@ executables := \
target/json_vala_gcc \
target/json_vala_clang \
target/json_dawjsonlink_cpp \
target/json_dawjsonlink_cpp_unchecked \
json-fsharp/target/Release/net5.0/json-fsharp \
target/Release/net5.0/json \
json-core/target/Release/net5.0/json-core \
Expand Down Expand Up @@ -136,12 +139,12 @@ target/json_go_gccgo: test.go | $(gofmt)

# Boost releases:
# https://www.boost.org/users/download/
BOOST_VERSION := boost_1_75_0
BOOST_VERSION := boost_1_76_0
boost = target/$(BOOST_VERSION)
$(boost): | target
cd target && \
wget --progress=dot:giga -O - \
https://dl.bintray.com/boostorg/release/1.75.0/source/$(BOOST_VERSION).tar.bz2 \
https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/$(BOOST_VERSION).tar.bz2 \
| tar -xj

target/json_boost_ptree_cpp: test_boost_ptree.cpp | $(boost) libnotify
Expand Down Expand Up @@ -181,9 +184,15 @@ $(rapidjson-dir): | target
target/json_rapid_cpp: test_rapid.cpp | $(rapidjson-dir) $(boost) libnotify
$(GCC_CPP_BUILD) -I$(rapidjson-dir)/include -I$(boost)

target/json_rapid_cpp_precised: test_rapid.cpp | $(rapidjson-dir) $(boost) libnotify
$(GCC_CPP_BUILD) -I$(rapidjson-dir)/include -I$(boost) -DPRECISED

target/json_rapid_sax_cpp: test_rapid_sax.cpp | $(rapidjson-dir) $(boost) libnotify
$(GCC_CPP_BUILD) -I$(rapidjson-dir)/include -I$(boost)

target/json_rapid_sax_cpp_precised: test_rapid_sax.cpp | $(rapidjson-dir) $(boost) libnotify
$(GCC_CPP_BUILD) -I$(rapidjson-dir)/include -I$(boost) -DPRECISED

gason-dir := target/gason
$(gason-dir): | target
$(GIT_CLONE) "https://github.com/vivkin/gason.git" $@
Expand Down Expand Up @@ -265,6 +274,11 @@ target/json_dawjsonlink_cpp: test_dawjsonlink.cpp | $(daw_json_link_all) $(boost
-I$(daw_json_link_all)/header_libraries/include \
-I$(daw_json_link_all)/utf_range/include -I$(boost)

target/json_dawjsonlink_cpp_unchecked: test_dawjsonlink.cpp | $(daw_json_link_all) $(boost) libnotify
$(GCC_CPP_BUILD) -I$(daw_json_link_all)/daw_json_link/include \
-I$(daw_json_link_all)/header_libraries/include \
-I$(daw_json_link_all)/utf_range/include -I$(boost) -DUNCHECKED

json-fsharp/target/Release/net5.0/json-fsharp: json-fsharp/json-fsharp.fsproj json-fsharp/Program.fs
$(DOTNET_BUILD)

Expand Down
4 changes: 2 additions & 2 deletions json/generate_json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

524_288.times do
h = {
'x' => rand,
'y' => rand,
'x' => rand * -10e-30,
'y' => rand * 10e+30,
'z' => rand,
'name' => "#{('a'..'z').to_a.sample(6).join} #{rand(10_000)}",
'opts' => { '1' => [1, true] }
Expand Down
12 changes: 10 additions & 2 deletions json/test_dawjsonlink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ coordinate_t calc(const string& text) {
auto x = 0.0, y = 0.0, z = 0.0;
auto len = 0;

#ifdef UNCHECKED
using range_t = daw::json::json_array_range<coordinate_t, daw::json::NoCommentSkippingPolicyUnchecked>;
nuald marked this conversation as resolved.
Show resolved Hide resolved
#else
using range_t = daw::json::json_array_range<coordinate_t>;
#endif
auto rng = range_t(json_sv, "coordinates");

for (auto c : rng) {
Expand All @@ -118,8 +122,12 @@ int main() {
}

const auto& text = read_file( "/tmp/1.json" );

notify(str(boost::format("C++/g++ (DAW JSON Link)\t%d") % getpid()));
#ifdef UNCHECKED
const string suffix = " NoCheck";
#else
const string suffix = "";
#endif
notify(str(boost::format("C++/g++ (DAW JSON Link%s)\t%d") % suffix % getpid()));
const auto& results = calc(text);
notify( "stop" );

Expand Down
2 changes: 1 addition & 1 deletion json/test_mir_asdf.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void main()
{
validate!calc;
auto text = cast(string) "/tmp/1.json".read;
"D/ldc2 (Mir Asdf)".notifyStart;
"D/ldc2 (Mir Asdf DOM)".notifyStart;
auto coordinate = calc(text);
notifyStop;
coordinate.print;
Expand Down
2 changes: 1 addition & 1 deletion json/test_mir_ion.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void main()
{
validate!calc;
auto text = cast(string) "/tmp/1.json".read;
"D/ldc2 (Mir Amazon's Ion)".notifyStart;
"D/ldc2 (Mir Amazon's Ion DOM)".notifyStart;
auto coordinate = calc(text);
notifyStop;
coordinate.print;
Expand Down
2 changes: 1 addition & 1 deletion json/test_mir_ion_file.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import mir.ion.deser.json : deserializeJsonFile;

void main() @safe @nogc
{
"D/ldc2 (Mir Amazon's Ion, file input)".notifyStart;
"D/ldc2 (Mir Amazon's Ion DOM, file input)".notifyStart;
auto coordinate = "/tmp/1.json".deserializeJsonFile!Avg.coordinates.avg;
notifyStop;
coordinate.print;
Expand Down
12 changes: 11 additions & 1 deletion json/test_rapid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ string read_file(const string& filename) {

coordinate_t calc(const string& text) {
Document jobj;
#ifdef PRECISED
jobj.Parse<kParseFullPrecisionFlag>(text);
nuald marked this conversation as resolved.
Show resolved Hide resolved
#else
jobj.Parse(text);
#endif

const Value& coordinates = jobj["coordinates"];
auto len = coordinates.Size();
Expand Down Expand Up @@ -68,7 +72,13 @@ int main() {

const auto& text = read_file("/tmp/1.json");

notify(str(boost::format("C++/g++ (RapidJSON)\t%d") % getpid()));
#ifdef PRECISED
const string suffix = " Precise";
#else
const string suffix = "";
#endif

notify(str(boost::format("C++/g++ (RapidJSON%s)\t%d") % suffix % getpid()));
const auto& results = calc(text);
notify("stop");

Expand Down
12 changes: 11 additions & 1 deletion json/test_rapid_sax.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ void calc(stringstream& ss, const TCallback& callback) {
IStreamWrapper isw(ss);
Reader reader;
CoordinateHandler handler(callback);
#ifdef PRECISED
reader.Parse<kParseFullPrecisionFlag>(isw, handler);
nuald marked this conversation as resolved.
Show resolved Hide resolved
#else
reader.Parse(isw, handler);
#endif
}

int main() {
Expand All @@ -148,7 +152,13 @@ int main() {
stringstream ss;
read_file("/tmp/1.json", ss);

notify(str(boost::format("C++/g++ (RapidJSON SAX)\t%d") % getpid()));
#ifdef PRECISED
const string suffix = " Precise";
#else
const string suffix = "";
#endif

notify(str(boost::format("C++/g++ (RapidJSON SAX%s)\t%d") % suffix % getpid()));
calc(ss, [](const coordinate_t& results) {
notify("stop");

Expand Down