From 561ffcd5198e059d371d800ded92ecbdad465b2e Mon Sep 17 00:00:00 2001 From: Ikraduya Edian Date: Mon, 4 Dec 2023 22:33:53 +0700 Subject: [PATCH] Add benchmarks for boost json (#2092) --- benchmark/CMakeLists.txt | 3 + benchmark/bench_ondemand.cpp | 11 +++ benchmark/distinct_user_id/boostjson.h | 29 +++++++ benchmark/find_tweet/boostjson.h | 30 +++++++ benchmark/json2msgpack/boostjson.h | 104 +++++++++++++++++++++++++ benchmark/kostya/boostjson.h | 29 +++++++ benchmark/large_random/boostjson.h | 29 +++++++ benchmark/partial_tweets/boostjson.h | 43 ++++++++++ benchmark/top_tweet/boostjson.h | 37 +++++++++ 9 files changed, 315 insertions(+) create mode 100644 benchmark/distinct_user_id/boostjson.h create mode 100644 benchmark/find_tweet/boostjson.h create mode 100644 benchmark/json2msgpack/boostjson.h create mode 100644 benchmark/kostya/boostjson.h create mode 100644 benchmark/large_random/boostjson.h create mode 100644 benchmark/partial_tweets/boostjson.h create mode 100644 benchmark/top_tweet/boostjson.h diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index bb7635fec..92df9bbc8 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -26,6 +26,9 @@ if (TARGET benchmark::benchmark) if(TARGET nlohmann_json) target_link_libraries(bench_ondemand PRIVATE nlohmann_json) endif() + if(TARGET boostjson) + target_link_libraries(bench_ondemand PRIVATE boostjson) + endif() endif() endif() diff --git a/benchmark/bench_ondemand.cpp b/benchmark/bench_ondemand.cpp index 9d10db75d..74bc8db85 100644 --- a/benchmark/bench_ondemand.cpp +++ b/benchmark/bench_ondemand.cpp @@ -21,6 +21,10 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS #include #endif +#ifdef SIMDJSON_COMPETITION_BOOSTJSON +#include +#endif + // This has to be last, for reasons I don't yet understand #include @@ -33,6 +37,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #include "json2msgpack/sajson.h" #endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON #include "json2msgpack/nlohmann_json.h" +#include "json2msgpack/boostjson.h" #include "partial_tweets/simdjson_ondemand.h" #include "partial_tweets/simdjson_dom.h" @@ -48,6 +53,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "partial_tweets/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "partial_tweets/boostjson.h" #include "distinct_user_id/simdjson_ondemand.h" @@ -66,6 +72,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "distinct_user_id/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "distinct_user_id/boostjson.h" #include "find_tweet/simdjson_ondemand.h" #include "find_tweet/simdjson_dom.h" @@ -81,6 +88,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "find_tweet/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "find_tweet/boostjson.h" #include "top_tweet/simdjson_ondemand.h" #include "top_tweet/simdjson_dom.h" @@ -96,6 +104,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "top_tweet/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "top_tweet/boostjson.h" #include "kostya/simdjson_ondemand.h" @@ -112,6 +121,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "kostya/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "kostya/boostjson.h" #include "large_random/simdjson_ondemand.h" #if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED @@ -130,6 +140,7 @@ SIMDJSON_POP_DISABLE_WARNINGS #if SIMDJSON_COMPETITION_SAX #include "large_random/nlohmann_json_sax.h" #endif // SIMDJSON_COMPETITION_SAX +#include "large_random/boostjson.h" #include "amazon_cellphones/simdjson_dom.h" #include "amazon_cellphones/simdjson_ondemand.h" diff --git a/benchmark/distinct_user_id/boostjson.h b/benchmark/distinct_user_id/boostjson.h new file mode 100644 index 000000000..3d171ee8b --- /dev/null +++ b/benchmark/distinct_user_id/boostjson.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "distinct_user_id.h" + +namespace distinct_user_id { + +struct boostjson { + bool run(simdjson::padded_string &json, std::vector &result) { + + auto root = boost::json::parse(json); + for (const auto &tweet : root.at("statuses").as_array()) { + result.push_back(tweet.at("user").at("id").to_number()); + + if (tweet.as_object().if_contains("retweeted_status")) { + result.push_back(tweet.at("retweeted_status").at("user").at("id").to_number()); + } + } + + return true; + } +}; + +BENCHMARK_TEMPLATE(distinct_user_id, boostjson)->UseManualTime(); + +} // namespace distinct_user_id + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/find_tweet/boostjson.h b/benchmark/find_tweet/boostjson.h new file mode 100644 index 000000000..adbb7ad70 --- /dev/null +++ b/benchmark/find_tweet/boostjson.h @@ -0,0 +1,30 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "find_tweet.h" + +namespace find_tweet { + +struct boostjson { + using StringType=std::string; + + bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) { + + auto root = boost::json::parse(json); + for (const auto &tweet : root.at("statuses").as_array()) { + if (tweet.at("id") == find_id) { + result = tweet.at("text").as_string(); + return true; + } + } + + return false; + } +}; + +BENCHMARK_TEMPLATE(find_tweet, boostjson)->UseManualTime(); + +} // namespace find_tweet + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/json2msgpack/boostjson.h b/benchmark/json2msgpack/boostjson.h new file mode 100644 index 000000000..b7dc7a7c8 --- /dev/null +++ b/benchmark/json2msgpack/boostjson.h @@ -0,0 +1,104 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "json2msgpack.h" + +namespace json2msgpack { + +struct boostjson2msgpack { + inline std::string_view to_msgpack(const boost::json::value &root, uint8_t *buf) { + buff = buf; + recursive_processor(root); + return std::string_view(reinterpret_cast(buf), size_t(buff - buf)); + } + +private: + uint8_t *buff{}; + + inline void write_double(const double d) noexcept { + *buff++ = 0xcb; + ::memcpy(buff, &d, sizeof(d)); + buff += sizeof(d); + } + + inline void write_byte(const uint8_t b) noexcept { + *buff = b; + buff++; + } + + inline void write_uint32(const uint32_t w) noexcept { + ::memcpy(buff, &w, sizeof(w)); + buff += sizeof(w); + } + + inline void write_string(const std::string & str) { + write_byte(0xdb); + write_uint32(uint32_t(str.size())); + ::memcpy(buff, str.data(), str.size()); + buff += str.size(); + } + + inline void recursive_processor(const boost::json::value &element) { + switch(element.kind()) { + case boost::json::kind::array: { + write_byte(0xdd); + const auto &array = element.as_array(); + write_uint32(static_cast(array.size())); + for (const auto &child : array) { + recursive_processor(child); + } + } break; + + case boost::json::kind::object: { + write_byte(0xdf); + const auto &object = element.as_object(); + write_uint32(static_cast(object.size())); + for (const auto &child : object) { + write_string(child.key_c_str()); + recursive_processor(child.value()); + } + } break; + + case boost::json::kind::int64: + case boost::json::kind::uint64: + case boost::json::kind::double_: + write_double(element.to_number()); + break; + + case boost::json::kind::string: + write_string(element.as_string().c_str()); + break; + + case boost::json::kind::bool_: + write_byte(0xc2 + element.as_bool()); + break; + + case boost::json::kind::null: + write_byte(0xc0); + break; + + default: + printf("unexpected\n"); + break; + } + } +}; + +struct boostjson { + using StringType=std::string; + + boostjson2msgpack parser{}; + + bool run(simdjson::padded_string &json, char *buffer, std::string_view &result) { + auto root = boost::json::parse(json); + result = parser.to_msgpack(root, reinterpret_cast(buffer)); + return true; + } +}; + +BENCHMARK_TEMPLATE(json2msgpack, boostjson)->UseManualTime(); + +} // namespace json2msgpack + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/kostya/boostjson.h b/benchmark/kostya/boostjson.h new file mode 100644 index 000000000..bfe2b2c83 --- /dev/null +++ b/benchmark/kostya/boostjson.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "kostya.h" + +namespace kostya { + +struct boostjson { + static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS; + + bool run(simdjson::padded_string &json, std::vector &result) { + auto root = boost::json::parse(json); + for (const auto &point : root.at("coordinates").as_array()) { + result.emplace_back(json_benchmark::point{ + point.at("x").to_number(), + point.at("y").to_number(), + point.at("z").to_number() + }); + } + return true; + } +}; + +BENCHMARK_TEMPLATE(kostya, boostjson)->UseManualTime(); + +} // namespace kostya + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/large_random/boostjson.h b/benchmark/large_random/boostjson.h new file mode 100644 index 000000000..da2fdf63c --- /dev/null +++ b/benchmark/large_random/boostjson.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "large_random.h" + +namespace large_random { + +struct boostjson { + static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS; + + bool run(simdjson::padded_string &json, std::vector &result) { + auto root = boost::json::parse(json); + for (const auto &point : root.as_array()) { + result.emplace_back(json_benchmark::point{ + point.at("x").to_number(), + point.at("y").to_number(), + point.at("z").to_number() + }); + } + return true; + } +}; + +BENCHMARK_TEMPLATE(large_random, boostjson)->UseManualTime(); + +} // namespace large_random + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/partial_tweets/boostjson.h b/benchmark/partial_tweets/boostjson.h new file mode 100644 index 000000000..b402b35f4 --- /dev/null +++ b/benchmark/partial_tweets/boostjson.h @@ -0,0 +1,43 @@ +#pragma once + +#ifdef SIMDJSON_COMPETITION_BOOSTJSON + +#include "partial_tweets.h" + +namespace partial_tweets { + +struct boostjson { + using StringType=std::string; + + bool run(simdjson::padded_string &json, std::vector> &result) { + + auto root = boost::json::parse(json); + for (const auto &tweet : root.at("statuses").as_array()) { + const auto &user = tweet.at("user"); + + auto in_reply_to_status_id = tweet.as_object().if_contains("in_reply_to_status_id") + ? tweet.at("in_reply_to_status_id") : boost::json::value(); + + result.emplace_back(partial_tweets::tweet{ + tweet.at("created_at").as_string().c_str(), + tweet.at("id").to_number(), + tweet.at("text").as_string().c_str(), + in_reply_to_status_id.is_null() ? 0 : in_reply_to_status_id.to_number(), + { + user.at("id").to_number(), + user.at("screen_name").as_string().c_str() + }, + tweet.at("retweet_count").to_number(), + tweet.at("favorite_count").to_number() + }); + } + + return true; + } +}; + +BENCHMARK_TEMPLATE(partial_tweets, boostjson)->UseManualTime(); + +} // namespace partial_tweets + +#endif // SIMDJSON_COMPETITION_BOOSTJSON diff --git a/benchmark/top_tweet/boostjson.h b/benchmark/top_tweet/boostjson.h new file mode 100644 index 000000000..4202a7458 --- /dev/null +++ b/benchmark/top_tweet/boostjson.h @@ -0,0 +1,37 @@ +#pragma once + +#if SIMDJSON_COMPETITION_BOOSTJSON + +#include "top_tweet.h" + +namespace top_tweet { + +using namespace simdjson; + +struct boostjson { + using StringType=std::string; + + bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result &result) { + result.retweet_count = -1; + boost::json::value top_tweet{}; + + auto root = boost::json::parse(json); + for (const auto &tweet : root.at("statuses").as_array()) { + int64_t retweet_count = tweet.at("retweet_count").as_int64(); + if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) { + result.retweet_count = retweet_count; + top_tweet = tweet; + } + } + + result.text = top_tweet.at("text").as_string(); + result.screen_name = top_tweet.at("user").at("screen_name").as_string(); + return result.retweet_count != -1; + } +}; + +BENCHMARK_TEMPLATE(top_tweet, boostjson)->UseManualTime(); + +} // namespace top_tweet + +#endif // SIMDJSON_COMPETITION_BOOSTJSON \ No newline at end of file