1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 #include "qemu/osdep.h"
3 #include "qemu/qtree.h"
4 #include "qemu/timer.h"
15 const char * const name
;
25 struct tree_implementation
{
26 const char * const name
;
30 static const struct benchmark benchmarks
[] = {
39 .fill_on_init
= false,
58 static const struct tree_implementation impls
[] = {
69 static int compare_func(const void *ap
, const void *bp
)
77 static void init_empty_tree_and_keys(enum impl_type impl
,
78 void **ret_tree
, size_t **ret_keys
,
81 size_t *keys
= g_malloc_n(n_elems
, sizeof(*keys
));
82 for (size_t i
= 0; i
< n_elems
; i
++) {
89 tree
= g_tree_new(compare_func
);
92 tree
= q_tree_new(compare_func
);
95 g_assert_not_reached();
102 static gboolean
traverse_func(gpointer key
, gpointer value
, gpointer data
)
107 static inline void remove_all(void *tree
, enum impl_type impl
)
111 g_tree_destroy(tree
);
114 q_tree_destroy(tree
);
117 g_assert_not_reached();
121 static int64_t run_benchmark(const struct benchmark
*bench
,
128 init_empty_tree_and_keys(impl
, &tree
, &keys
, n_elems
);
129 if (bench
->fill_on_init
) {
130 for (size_t i
= 0; i
< n_elems
; i
++) {
133 g_tree_insert(tree
, &keys
[i
], &keys
[i
]);
136 q_tree_insert(tree
, &keys
[i
], &keys
[i
]);
139 g_assert_not_reached();
144 int64_t start_ns
= get_clock();
147 for (size_t i
= 0; i
< n_elems
; i
++) {
151 value
= g_tree_lookup(tree
, &keys
[i
]);
154 value
= q_tree_lookup(tree
, &keys
[i
]);
157 g_assert_not_reached();
163 for (size_t i
= 0; i
< n_elems
; i
++) {
166 g_tree_insert(tree
, &keys
[i
], &keys
[i
]);
169 q_tree_insert(tree
, &keys
[i
], &keys
[i
]);
172 g_assert_not_reached();
177 for (size_t i
= 0; i
< n_elems
; i
++) {
180 g_tree_remove(tree
, &keys
[i
]);
183 q_tree_remove(tree
, &keys
[i
]);
186 g_assert_not_reached();
191 remove_all(tree
, impl
);
196 g_tree_foreach(tree
, traverse_func
, NULL
);
199 q_tree_foreach(tree
, traverse_func
, NULL
);
202 g_assert_not_reached();
206 g_assert_not_reached();
208 int64_t ns
= get_clock() - start_ns
;
210 if (bench
->op
!= OP_REMOVE_ALL
) {
211 remove_all(tree
, impl
);
218 int main(int argc
, char *argv
[])
228 double res
[ARRAY_SIZE(benchmarks
)][ARRAY_SIZE(impls
)][ARRAY_SIZE(sizes
)];
229 for (int i
= 0; i
< ARRAY_SIZE(sizes
); i
++) {
230 size_t size
= sizes
[i
];
231 for (int j
= 0; j
< ARRAY_SIZE(impls
); j
++) {
232 const struct tree_implementation
*impl
= &impls
[j
];
233 for (int k
= 0; k
< ARRAY_SIZE(benchmarks
); k
++) {
234 const struct benchmark
*bench
= &benchmarks
[k
];
237 run_benchmark(bench
, impl
->type
, size
);
239 int64_t total_ns
= 0;
241 while (total_ns
< 2e8
|| n_runs
< 5) {
242 total_ns
+= run_benchmark(bench
, impl
->type
, size
);
245 double ns_per_run
= (double)total_ns
/ n_runs
;
247 /* Throughput, in Mops/s */
248 res
[k
][j
][i
] = size
/ ns_per_run
* 1e3
;
253 printf("# Results' breakdown: Tree, Op and #Elements. Units: Mops/s\n");
254 printf("%5s %10s ", "Tree", "Op");
255 for (int i
= 0; i
< ARRAY_SIZE(sizes
); i
++) {
256 printf("%7zu ", sizes
[i
]);
260 for (int i
= 0; i
< ARRAY_SIZE(separator
) - 1; i
++) {
263 separator
[ARRAY_SIZE(separator
) - 1] = '\0';
264 printf("%s\n", separator
);
265 for (int i
= 0; i
< ARRAY_SIZE(benchmarks
); i
++) {
266 for (int j
= 0; j
< ARRAY_SIZE(impls
); j
++) {
267 printf("%5s %10s ", impls
[j
].name
, benchmarks
[i
].name
);
268 for (int k
= 0; k
< ARRAY_SIZE(sizes
); k
++) {
269 printf("%7.2f ", res
[i
][j
][k
]);
273 if (res
[i
][0][k
] != 0) {
274 double speedup
= res
[i
][j
][k
] / res
[i
][0][k
];
275 printf("(%4.2fx) ", speedup
);
284 printf("%s\n", separator
);