1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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"
|