aboutsummaryrefslogtreecommitdiff
path: root/test/benchmark/benchflatccjson
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
committerToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
commit5a40295c4cf0af5ea8da9ced04a4ce7d3621a080 (patch)
treecb21506e7b04d10b45d6066a0ee1655563d5d52b /test/benchmark/benchflatccjson
Squashed 'flatcc/' content from commit 473da2a
git-subtree-dir: flatcc git-subtree-split: 473da2afa5ca435363f8c5e6569167aee6bc31c5
Diffstat (limited to 'test/benchmark/benchflatccjson')
-rw-r--r--test/benchmark/benchflatccjson/benchflatccjson.c182
-rwxr-xr-xtest/benchmark/benchflatccjson/run.sh23
2 files changed, 205 insertions, 0 deletions
diff --git a/test/benchmark/benchflatccjson/benchflatccjson.c b/test/benchmark/benchflatccjson/benchflatccjson.c
new file mode 100644
index 0000000..26ee291
--- /dev/null
+++ b/test/benchmark/benchflatccjson/benchflatccjson.c
@@ -0,0 +1,182 @@
+#define BENCH_TITLE "flatcc json parser and printer for C"
+
+/*
+ * NOTE:
+ *
+ * Using dtoa_grisu3.c over sprintf("%.17g") more than doubles the
+ * encoding performance of this benchmark from 3.3 us/op to 1.3 us/op.
+ */
+
+#include <stdlib.h>
+
+/*
+ * Builder is only needed so we can create the initial buffer to encode
+ * json from, but it also includes the reader which is needed calculate
+ * the decoded checksum after parsing.
+ */
+#include "flatbench_builder.h"
+
+#include "flatbench_json_parser.h"
+#include "flatbench_json_printer.h"
+
+#define C(x) FLATBUFFERS_WRAP_NAMESPACE(benchfb_FooBarContainer, x)
+#define FooBar(x) FLATBUFFERS_WRAP_NAMESPACE(benchfb_FooBar, x)
+#define Bar(x) FLATBUFFERS_WRAP_NAMESPACE(benchfb_Bar, x)
+#define Foo(x) FLATBUFFERS_WRAP_NAMESPACE(benchfb_Foo, x)
+#define Enum(x) FLATBUFFERS_WRAP_NAMESPACE(benchfb_Enum, x)
+#define True flatbuffers_true
+#define False flatbuffers_false
+#define StringLen flatbuffers_string_len
+
+typedef struct flatcc_jsonbench {
+ flatcc_builder_t builder;
+ flatcc_json_parser_t parser;
+ flatcc_json_printer_t printer;
+
+ /* Holds the source data to print (encode) from. */
+ char bin[1000];
+ size_t bin_size;
+ /* Extra buffer for extracting the parse (decoded) into. */
+ char decode_buffer[1000];
+ /*
+ * The target encode / source decode buffer is provided by the
+ * benchmark framework.
+ */
+} flatcc_jsonbench_t;
+
+int flatcc_jsonbench_init(flatcc_jsonbench_t *bench)
+{
+ int i, veclen = 3;
+ void *buffer_ok;
+ flatcc_builder_t *B = &bench->builder;
+
+ flatcc_builder_init(B);
+
+ /* Generate the data needed to print from, just once. */
+ C(start_as_root(B));
+ C(list_start(B));
+ for (i = 0; i < veclen; ++i) {
+ /*
+ * By using push_start instead of push_create we can construct
+ * the sibling field (of Bar type) in-place on the stack,
+ * otherwise we would need to create a temporary Bar struct.
+ */
+ C(list_push_start(B));
+ FooBar(sibling_create(B,
+ 0xABADCAFEABADCAFE + i, 10000 + i, '@' + i, 1000000 + i,
+ 123456 + i, 3.14159f + i, 10000 + i));
+ FooBar(name_create_str(B, "Hello, World!"));
+ FooBar(rating_add(B, 3.1415432432445543543 + i));
+ FooBar(postfix_add(B, '!' + i));
+ C(list_push_end(B));
+ }
+ C(list_end(B));
+ C(location_create_str(B, "https://www.example.com/myurl/"));
+ C(fruit_add(B, Enum(Bananas)));
+ C(initialized_add(B, True));
+ C(end_as_root(B));
+
+ buffer_ok = flatcc_builder_copy_buffer(B, bench->bin, sizeof(bench->bin));
+ bench->bin_size = flatcc_builder_get_buffer_size(B);
+
+ flatcc_builder_reset(&bench->builder);
+ return !buffer_ok;
+}
+
+void flatcc_jsonbench_clear(flatcc_jsonbench_t *bench)
+{
+ flatcc_json_printer_clear(&bench->printer);
+ flatcc_builder_clear(&bench->builder);
+ // parser does not need to be cleared.
+}
+
+/*
+ * For a buffer large enough to hold encoded representation.
+ *
+ * 1000 is enough for compact json, but for pretty printing we must up.
+ */
+#define BENCHMARK_BUFSIZ 10000
+
+/* Interface to main benchmark logic. */
+#define DECLARE_BENCHMARK(BM) \
+ flatcc_jsonbench_t flatcc_jsonbench, *BM; \
+ BM = &flatcc_jsonbench; \
+ flatcc_jsonbench_init(BM);
+
+#define CLEAR_BENCHMARK(BM) flatcc_jsonbench_clear(BM);
+
+int encode(flatcc_jsonbench_t *bench, void *buffer, size_t *size)
+{
+ int ret;
+
+ flatcc_json_printer_init_buffer(&bench->printer, buffer, *size);
+ /*
+ * Normally avoid setting indentation - this yields compact
+ * spaceless json which is what you want in resource critical
+ * parsing and printing. But - it doesn't get that much slower,
+ * so interesting to benchmark. Improve by enabling SSE4_2, but
+ * generally not worth the trouble.
+ */
+ //flatcc_json_printer_set_indent(&bench->printer, 8);
+
+ /*
+ * Unquoted makes it slightly slower, noenum hardly makes a
+ * difference - for this particular data set.
+ */
+ // flatcc_json_printer_set_noenum(&bench->printer, 1);
+ // flatcc_json_printer_set_unquoted(&bench->printer, 1);
+ ret = flatbench_print_json(&bench->printer, bench->bin, bench->bin_size);
+ *size = flatcc_json_printer_flush(&bench->printer);
+
+ return ret < 0 ? ret : 0;
+}
+
+int64_t decode(flatcc_jsonbench_t *bench, void *buffer, size_t size, int64_t sum)
+{
+ unsigned int i;
+ int ret;
+ flatcc_builder_t *B = &bench->builder;
+
+ C(table_t) foobarcontainer;
+ FooBar(vec_t) list;
+ FooBar(table_t) foobar;
+ Bar(struct_t) bar;
+ Foo(struct_t) foo;
+
+ flatcc_builder_reset(B);
+ ret = flatbench_parse_json(B, &bench->parser, buffer, size, 0);
+ if (ret) {
+ return 0;
+ }
+ if (!flatcc_builder_copy_buffer(B,
+ bench->decode_buffer, sizeof(bench->decode_buffer))) {
+ return 0;
+ }
+
+ /* Traverse parsed result to calculate checksum. */
+
+ foobarcontainer = C(as_root(bench->decode_buffer));
+ sum += C(initialized(foobarcontainer));
+ sum += StringLen(C(location(foobarcontainer)));
+ sum += C(fruit(foobarcontainer));
+ list = C(list(foobarcontainer));
+ for (i = 0; i < FooBar(vec_len(list)); ++i) {
+ foobar = FooBar(vec_at(list, i));
+ sum += StringLen(FooBar(name(foobar)));
+ sum += FooBar(postfix(foobar));
+ sum += (int64_t)FooBar(rating(foobar));
+ bar = FooBar(sibling(foobar));
+ sum += (int64_t)Bar(ratio(bar));
+ sum += Bar(size(bar));
+ sum += Bar(time(bar));
+ foo = Bar(parent(bar));
+ sum += Foo(count(foo));
+ sum += Foo(id(foo));
+ sum += Foo(length(foo));
+ sum += Foo(prefix(foo));
+ }
+ return sum + 2 * sum;
+}
+
+/* Copy to same folder before compilation or use include directive. */
+#include "benchmain.h"
diff --git a/test/benchmark/benchflatccjson/run.sh b/test/benchmark/benchflatccjson/run.sh
new file mode 100755
index 0000000..c24e02e
--- /dev/null
+++ b/test/benchmark/benchflatccjson/run.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+set -e
+cd `dirname $0`/../../..
+ROOT=`pwd`
+TMP=build/tmp/test/benchmark/benchflatccjson
+${ROOT}/scripts/build.sh
+mkdir -p ${TMP}
+rm -rf ${TMP}/*
+bin/flatcc --json -crw -o ${TMP} test/benchmark/schema/flatbench.fbs
+
+CC=${CC:-cc}
+cp -r test/benchmark/benchmain/* ${TMP}
+cp -r test/benchmark/benchflatccjson/* ${TMP}
+cd ${TMP}
+$CC -g -std=c11 -I ${ROOT}/include benchflatccjson.c \
+ ${ROOT}/lib/libflatccrt_d.a -o benchflatccjson_d
+$CC -O3 -DNDEBUG -std=c11 -I ${ROOT}/include benchflatccjson.c \
+ ${ROOT}/lib/libflatccrt.a -o benchflatccjson
+echo "running flatbench flatcc json parse and print for C (debug)"
+./benchflatccjson_d
+echo "running flatbench flatcc json parse and print for C (optimized)"
+./benchflatccjson