mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
c806e955c4
* Initial work on JSON builder * moving the files back to ondemand for now. * tweak * more later * update * minor edits * dropping vs arm (missing support) * adding tests. we still specialized write_string_escaped * tweaking * fix typo * tweaking the approach * minor fix * missing store * another missing store * Attempt at fixing failing serialization tests. (#2292) * Fixing appeand_float typo (#2294) * applying a couple of fixes * updating single header * fix for pre C++17 if constexpr * Fixing unused argument problem and updating the singleheader file * various pedantic fixes * Sketch of builder * reordering. * simplify * Adding draft of static reflection based deserialization * Updating simdjson singleheader * patching the automated deserialization. * automated * Adding support for smart pointers of user defined types. * Adding specialization for smart pointers for basic types. I think it is highly likely that this can be done in a more generic way. * Referncing a later version of rapidjson that fixed the issue related with assignment attempt of a const variable for GenericStringRef class. * guarding the tests * adding documentation for string_builder * saving * rename to 'append' * saving * non-functional benchmarks (#2342) * non-functional benchmarks * Fix typo * various fixes * tweaking --------- Co-authored-by: Daniel Lemire <dlemire@lemire.me> Co-authored-by: Francisco Geiman Thiesen <franciscogthiesen@gmail.com> * tuning * various minor fixes * minor tweak * minor simplification * updating amal * adding a cast * update * fancy casting * removing dead code * Pushing latest changes. CITM benchmark is still not working. * Still not working, but now I am getting only 10 errors. * add static reflection benchmark to 'large random' benchmark and allows (#2349) deserialization (with static reflection) from objects and arrays. Co-authored-by: Daniel Lemire <dlemire@lemire.me> * Removing std::map from CitmCatalog definition, since that is not currently supported. * Added free to rust bench, segfault is still happening.. * The syntax changed: ^E became ^^E. (#2350) * The syntax changed: ^E became ^^E. * guarding --------- Co-authored-by: Daniel Lemire <dlemire@lemire.me> * Adding support for string_view_keyed_map types. * Adding concepts as a conditional include. * updating single-header * Adding concepts to ondemand deps * rust benchmark is finally working * Fixing small typo in docs. * adding docker config and instructions so that our users can test the static reflection (#2358) * adding docker config and instructions so that our users can test the static reflection * completing the instructions * pruning white spaces --------- Co-authored-by: Daniel Lemire <dlemire@lemire.me> * minor optimizations on the JSON builder branch * avoiding undef behaviour * saving * somewhat nicer builder * make it possible to run just one benchmark * adding linux perf * fixing minor issue * updating swar * Adding real world compilation benchmark (#2379) * Adding compilation benchmark for json parsing with and without reflection * Moving it to the benchmark folder, also reducing a bit the number of iterations. * Removing script from root folder. * Reducing number of iterations * Update benchmark/benchmark_reflection_usage_compilation.sh Co-authored-by: Daniel Lemire <daniel@lemire.me> * Update benchmark/benchmark_reflection_usage_compilation.sh Co-authored-by: Daniel Lemire <daniel@lemire.me> * Update benchmark/benchmark_reflection_usage_compilation.sh Co-authored-by: Daniel Lemire <daniel@lemire.me> * Making the script more customizable and also test whether the compiler being used supports reflection before actually running the benchmark --------- Co-authored-by: Daniel Lemire <daniel@lemire.me> * Using define_static_string from https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3491r2.html (#2389) * Applying changes needed after latest reflection paper updates. * Working, but no template for yet. * Updating single-header to incldue the use of define_static_string. * copying over master --------- Co-authored-by: Daniel Lemire <dlemire@lemire.me> Co-authored-by: Francisco Geiman Thiesen <franciscogthiesen@gmail.com>
168 lines
5.6 KiB
C++
168 lines
5.6 KiB
C++
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <format>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <nlohmann/json.hpp>
|
|
#include <simdjson.h>
|
|
#include <string>
|
|
#include "twitter_data.h"
|
|
#include "nlohmann_twitter_data.h"
|
|
#include "../benchmark_utils/benchmark_helper.h"
|
|
#if SIMDJSON_BENCH_CPP_REFLECT
|
|
#include <rfl.hpp>
|
|
#include <rfl/json.hpp>
|
|
void bench_reflect_cpp(TwitterData &data) {
|
|
std::string output = rfl::json::write(data);
|
|
size_t output_volume = output.size();
|
|
printf("# output volume: %zu bytes\n", output_volume);
|
|
|
|
volatile size_t measured_volume = 0;
|
|
pretty_print(1, output_volume, "bench_reflect_cpp",
|
|
bench([&data, &measured_volume, &output_volume]() {
|
|
std::string output = rfl::json::write(data);
|
|
measured_volume = output.size();
|
|
if (measured_volume != output_volume) {
|
|
printf("mismatch\n");
|
|
}
|
|
}));
|
|
}
|
|
#endif // SIMDJSON_BENCH_CPP_REFLECT
|
|
|
|
#ifdef SIMDJSON_RUST_VERSION
|
|
#include "../serde-benchmark/serde_benchmark.h"
|
|
|
|
|
|
void bench_rust(serde_benchmark::TwitterData *data) {
|
|
const char * output = serde_benchmark::str_from_twitter(data);
|
|
size_t output_volume = strlen(output);
|
|
printf("# output volume: %zu bytes\n", output_volume);
|
|
volatile size_t measured_volume = 0;
|
|
pretty_print(1, output_volume, "bench_rust",
|
|
bench([&data, &measured_volume, &output_volume]() {
|
|
const char * output = serde_benchmark::str_from_twitter(data);
|
|
serde_benchmark::free_string(output);
|
|
}));
|
|
}
|
|
#endif
|
|
|
|
template <class T> void bench_simdjson_static_reflection(T &data) {
|
|
simdjson::builder::string_builder sb;
|
|
simdjson::builder::append(sb, data);
|
|
std::string_view p;
|
|
if(sb.view().get(p)) {
|
|
std::cerr << "Error!" << std::endl;
|
|
}
|
|
size_t output_volume = p.size();
|
|
sb.clear();
|
|
printf("# output volume: %zu bytes\n", output_volume);
|
|
|
|
volatile size_t measured_volume = 0;
|
|
pretty_print(sizeof(data), output_volume, "bench_simdjson_static_reflection",
|
|
bench([&data, &measured_volume, &output_volume, &sb]() {
|
|
sb.clear();
|
|
simdjson::builder::append(sb, data);
|
|
std::string_view p;
|
|
if(sb.view().get(p)) {
|
|
std::cerr << "Error!" << std::endl;
|
|
}
|
|
measured_volume = sb.size();
|
|
if (measured_volume != output_volume) {
|
|
printf("mismatch\n");
|
|
}
|
|
}));
|
|
}
|
|
|
|
void bench_nlohmann(TwitterData &data) {
|
|
std::string output = nlohmann_serialize(data);
|
|
size_t output_volume = output.size();
|
|
printf("# output volume: %zu bytes\n", output_volume);
|
|
|
|
volatile size_t measured_volume = 0;
|
|
pretty_print(1, output_volume, "bench_nlohmann",
|
|
bench([&data, &measured_volume, &output_volume]() {
|
|
std::string output = nlohmann_serialize(data);
|
|
measured_volume = output.size();
|
|
if (measured_volume != output_volume) {
|
|
printf("mismatch\n");
|
|
}
|
|
}));
|
|
}
|
|
|
|
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
|
((std::string *)userp)->append((char *)contents, size * nmemb);
|
|
return size * nmemb;
|
|
}
|
|
|
|
std::string read_file(std::string filename) {
|
|
printf("# Reading file %s\n", filename.c_str());
|
|
constexpr size_t read_size = 4096;
|
|
auto stream = std::ifstream(filename.c_str());
|
|
stream.exceptions(std::ios_base::badbit);
|
|
std::string out;
|
|
std::string buf(read_size, '\0');
|
|
while (stream.read(&buf[0], read_size)) {
|
|
out.append(buf, 0, size_t(stream.gcount()));
|
|
}
|
|
out.append(buf, 0, size_t(stream.gcount()));
|
|
return out;
|
|
}
|
|
|
|
// Function to check if benchmark name contains filter substring
|
|
bool matches_filter(const std::string& benchmark_name, const std::string& filter) {
|
|
return filter.empty() || benchmark_name.find(filter) != std::string::npos;
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
std::string filter;
|
|
|
|
// Parse command-line arguments
|
|
for (int i = 1; i < argc; ++i) {
|
|
if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--filter") == 0) {
|
|
if (i + 1 < argc) {
|
|
filter = argv[++i];
|
|
} else {
|
|
std::cerr << "Error: -f/--filter requires an argument" << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
// Testing correctness of round-trip (serialization + deserialization)
|
|
std::string json_str = read_file(JSON_FILE);
|
|
|
|
// Loading up the data into a structure.
|
|
simdjson::ondemand::parser parser;
|
|
simdjson::ondemand::document doc;
|
|
if(parser.iterate(simdjson::pad(json_str)).get(doc)) {
|
|
std::cerr << "Error loading the document!" << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
TwitterData my_struct;
|
|
if(doc.get<TwitterData>().get(my_struct)) {
|
|
std::cerr << "Error loading TwitterData!" << std::endl;
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
// Benchmarking the serialization
|
|
if (matches_filter("nlohmann", filter)) {
|
|
bench_nlohmann(my_struct);
|
|
}
|
|
if (matches_filter("simdjson_static_reflection", filter)) {
|
|
bench_simdjson_static_reflection(my_struct);
|
|
}
|
|
#ifdef SIMDJSON_RUST_VERSION
|
|
if (matches_filter("rust", filter)) {
|
|
printf("# WARNING: The Rust benchmark may not be directly comparable since it does not use an equivalent data structure.\n");
|
|
serde_benchmark::TwitterData * td = serde_benchmark::twitter_from_str(json_str.c_str(), json_str.size());
|
|
bench_rust(td);
|
|
serde_benchmark::free_twitter(td);
|
|
}
|
|
#endif
|
|
#if SIMDJSON_BENCH_CPP_REFLECT
|
|
if (matches_filter("reflect_cpp", filter)) {
|
|
bench_reflect_cpp(my_struct);
|
|
}
|
|
#endif
|
|
return EXIT_SUCCESS;
|
|
} |