Skip to content

Commit dd1db8f

Browse files
committed
benchmarks: add json benchmark pack tool
Signed-off-by: Eduardo Silva <[email protected]>
1 parent 40837a3 commit dd1db8f

File tree

4 files changed

+10192
-0
lines changed

4 files changed

+10192
-0
lines changed

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ option(FLB_CUSTOM_CALYPTIA "Enable Calyptia Support" Yes)
214214
# Config formats
215215
option(FLB_CONFIG_YAML "Enable YAML config format" Yes)
216216

217+
option(FLB_BENCHMARKS "Enable benchmarks" No)
218+
219+
217220
# List of plugins available and defaults for each option
218221
include(cmake/plugins_options.cmake)
219222

@@ -318,6 +321,7 @@ if(FLB_DEV)
318321
set(FLB_HTTP_SERVER On)
319322
set(FLB_HTTP_CLIENT_DEBUG On)
320323
set(FLB_TESTS_INTERNAL On)
324+
set(FLB_BENCHMARKS On)
321325
endif()
322326

323327
if(FLB_TRACE)
@@ -588,6 +592,9 @@ endif()
588592
# ring buffer library
589593
add_subdirectory(${FLB_PATH_LIB_RING_BUFFER} EXCLUDE_FROM_ALL)
590594

595+
# yyson
596+
add_subdirectory(${FLB_PATH_LIB_YYJSON} EXCLUDE_FROM_ALL)
597+
591598
# Avro
592599
if(FLB_AVRO_ENCODER)
593600
# jansson
@@ -1067,6 +1074,10 @@ else()
10671074
FLB_DEFINITION_VAL(FLB_MSGPACK_TO_JSON_REALLOC_BUFFER_SIZE ${FLB_MSGPACK_TO_JSON_REALLOC_BUFFER_SIZE})
10681075
endif()
10691076

1077+
if (FLB_BENCHMARKS)
1078+
add_subdirectory(benchmarks)
1079+
endif()
1080+
10701081
# Build tools/xxd-c
10711082
add_subdirectory(tools/xxd-c)
10721083

benchmarks/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_executable(flb-bench-pack_json pack_json.c)
2+
target_link_libraries(flb-bench-pack_json
3+
fluent-bit-static
4+
${CMAKE_THREAD_LIBS_INIT}
5+
)
6+

benchmarks/pack_json.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <time.h>
4+
#include <unistd.h>
5+
6+
#include <fluent-bit.h>
7+
#include <fluent-bit/flb_pack_json.h>
8+
9+
#define ITERATIONS 100000
10+
11+
static long diff_ns(struct timespec *s, struct timespec *e)
12+
{
13+
return (e->tv_sec - s->tv_sec) * 1000000000L + (e->tv_nsec - s->tv_nsec);
14+
}
15+
16+
static int compare_encoders_output(char *json, size_t len)
17+
{
18+
int ret;
19+
20+
int root_type1;
21+
char *out_buf1;
22+
size_t out_size1 = 0;
23+
24+
int root_type2;
25+
char *out_buf2;
26+
size_t out_size2 = 0;
27+
28+
struct flb_pack_opts opts = {0};
29+
30+
/* jsmn */
31+
opts.backend = FLB_PACK_JSON_BACKEND_JSMN;
32+
ret = flb_pack_json_ext(json, len, &out_buf1, &out_size1, &root_type1, &opts);
33+
if (ret != 0) {
34+
fprintf(stderr, "error jsmn\n");
35+
return -1;
36+
}
37+
fprintf(stderr, "jsmn records count: %d\n", flb_mp_count(out_buf1, out_size1));
38+
39+
/* yyjson */
40+
opts.backend = FLB_PACK_JSON_BACKEND_YYJSON;
41+
ret = flb_pack_json_ext(json, len, &out_buf2, &out_size2, &root_type2, &opts);
42+
if (ret != 0) {
43+
fprintf(stderr, "error yyjson\n");
44+
flb_free(out_buf1);
45+
return -1;
46+
}
47+
48+
if (out_size1 != out_size2 || memcmp(out_buf1, out_buf2, out_size1) != 0) {
49+
fprintf(stderr, "msgpack mismatch between jsmn and yyjson\n");
50+
fprintf(stderr, "jsmn size: %zu, yyjson size: %zu\n", out_size1, out_size2);
51+
flb_free(out_buf1);
52+
flb_free(out_buf2);
53+
return -1;
54+
}
55+
56+
flb_free(out_buf1);
57+
flb_free(out_buf2);
58+
return 0;
59+
}
60+
61+
int main(int argc, char **argv)
62+
{
63+
int i;
64+
int ret;
65+
size_t len;
66+
struct timespec ts, te;
67+
long d_jsmn, d_yyjson;
68+
char *mp_buf;
69+
size_t mp_size;
70+
struct flb_pack_opts opts = {0};
71+
int root_type;
72+
char *json;
73+
int iterations = 100;
74+
char *log_file = NULL;
75+
int opt;
76+
uint64_t total_bytes;
77+
double mibps_jsmn;
78+
double mibps_yyjson;
79+
double ratio;
80+
double reduction;
81+
82+
/* Parse command-line options */
83+
while ((opt = getopt(argc, argv, "i:f:")) != -1) {
84+
switch (opt) {
85+
case 'i':
86+
iterations = atoi(optarg);
87+
if (iterations <= 0) {
88+
fprintf(stderr, "Invalid value for -i (iterations): %s\n", optarg);
89+
return 1;
90+
}
91+
break;
92+
case 'f':
93+
log_file = optarg;
94+
break;
95+
default:
96+
fprintf(stderr, "Usage: %s -f log_file [-i iterations]\n", argv[0]);
97+
return 1;
98+
}
99+
}
100+
101+
if (log_file == NULL) {
102+
fprintf(stderr, "Error: log file (-f) is required.\n");
103+
fprintf(stderr, "Usage: %s -f log_file [-i iterations]\n", argv[0]);
104+
return 1;
105+
}
106+
107+
ret = flb_utils_read_file(log_file, &json, &len);
108+
if (ret != 0) {
109+
fprintf(stderr, "error reading %s\n", log_file);
110+
return 1;
111+
}
112+
113+
printf("Comparing encoders output: ");
114+
ret = compare_encoders_output(json, len);
115+
if (ret != 0) {
116+
printf("failed\n");
117+
free(json);
118+
exit(EXIT_FAILURE);
119+
}
120+
printf("ok\n\n");
121+
122+
printf("Benchmarking JSON packing to msgpack\n");
123+
printf("-------------------------------------------\n\n");
124+
printf("Iterations : %d\n", iterations);
125+
printf("JSON size : %zu bytes\n", len);
126+
printf("-------------------------------------------\n\n");
127+
128+
/* JSMN */
129+
opts.backend = FLB_PACK_JSON_BACKEND_JSMN;
130+
clock_gettime(CLOCK_MONOTONIC, &ts);
131+
for (i = 0; i < iterations; i++) {
132+
ret = flb_pack_json_ext(json, len, &mp_buf, &mp_size, &root_type, &opts);
133+
if (ret != 0) {
134+
fprintf(stderr, "error jsmn\n");
135+
free(json);
136+
return 1;
137+
}
138+
flb_free(mp_buf);
139+
}
140+
clock_gettime(CLOCK_MONOTONIC, &te);
141+
d_jsmn = diff_ns(&ts, &te);
142+
143+
/* YYJSON */
144+
opts.backend = FLB_PACK_JSON_BACKEND_YYJSON;
145+
clock_gettime(CLOCK_MONOTONIC, &ts);
146+
for (i = 0; i < iterations; i++) {
147+
ret = flb_pack_json_ext(json, len, &mp_buf, &mp_size, &root_type, &opts);
148+
if (ret != 0) {
149+
fprintf(stderr, "error yyjson\n");
150+
free(json);
151+
return 1;
152+
}
153+
flb_free(mp_buf);
154+
}
155+
clock_gettime(CLOCK_MONOTONIC, &te);
156+
d_yyjson = diff_ns(&ts, &te);
157+
158+
159+
total_bytes = (uint64_t) len * (uint64_t) iterations;
160+
161+
mibps_jsmn = (double) total_bytes / d_jsmn * 1e9 / (1024.0 * 1024.0);
162+
mibps_yyjson = (double) total_bytes / d_yyjson * 1e9 / (1024.0 * 1024.0);
163+
164+
ratio = (double) d_jsmn / (double) d_yyjson;
165+
reduction = (double) (d_jsmn - d_yyjson) * 100.0 / (double) d_jsmn;
166+
167+
printf("-------------------------------------------\n");
168+
printf("old encoder : %ld ns | %.2f MiB/s\n", d_jsmn, mibps_jsmn);
169+
printf("new encoder : %ld ns | %.2f MiB/s\n", d_yyjson, mibps_yyjson);
170+
printf("-------------------------------------------\n");
171+
printf("Speedup : %.2fx (time -%.2f%%)\n", ratio, reduction);
172+
173+
free(json);
174+
return 0;
175+
}

0 commit comments

Comments
 (0)