1 /* Simple speed test for NTDB */
2 #include <ccan/err/err.h>
15 /* Nanoseconds per operation */
16 static size_t normalize(const struct timeval
*start
,
17 const struct timeval
*stop
,
22 timersub(stop
, start
, &diff
);
24 /* Floating point is more accurate here. */
25 return (double)(diff
.tv_sec
* 1000000 + diff
.tv_usec
)
29 static size_t file_size(void)
33 if (stat("/tmp/speed.ntdb", &st
) != 0)
38 static int count_record(struct ntdb_context
*ntdb
,
39 NTDB_DATA key
, NTDB_DATA data
, void *p
)
42 *total
+= *(int *)data
.dptr
;
46 static void dump_and_clear_stats(struct ntdb_context
**ntdb
,
48 union ntdb_attribute
*attr
)
50 union ntdb_attribute stats
;
51 enum NTDB_ERROR ecode
;
53 stats
.base
.attr
= NTDB_ATTRIBUTE_STATS
;
54 stats
.stats
.size
= sizeof(stats
.stats
);
55 ecode
= ntdb_get_attribute(*ntdb
, &stats
);
56 if (ecode
!= NTDB_SUCCESS
)
57 errx(1, "Getting stats: %s", ntdb_errorstr(ecode
));
59 printf("allocs = %llu\n",
60 (unsigned long long)stats
.stats
.allocs
);
61 printf(" alloc_subhash = %llu\n",
62 (unsigned long long)stats
.stats
.alloc_subhash
);
63 printf(" alloc_chain = %llu\n",
64 (unsigned long long)stats
.stats
.alloc_chain
);
65 printf(" alloc_bucket_exact = %llu\n",
66 (unsigned long long)stats
.stats
.alloc_bucket_exact
);
67 printf(" alloc_bucket_max = %llu\n",
68 (unsigned long long)stats
.stats
.alloc_bucket_max
);
69 printf(" alloc_leftover = %llu\n",
70 (unsigned long long)stats
.stats
.alloc_leftover
);
71 printf(" alloc_coalesce_tried = %llu\n",
72 (unsigned long long)stats
.stats
.alloc_coalesce_tried
);
73 printf(" alloc_coalesce_iterate_clash = %llu\n",
74 (unsigned long long)stats
.stats
.alloc_coalesce_iterate_clash
);
75 printf(" alloc_coalesce_lockfail = %llu\n",
76 (unsigned long long)stats
.stats
.alloc_coalesce_lockfail
);
77 printf(" alloc_coalesce_race = %llu\n",
78 (unsigned long long)stats
.stats
.alloc_coalesce_race
);
79 printf(" alloc_coalesce_succeeded = %llu\n",
80 (unsigned long long)stats
.stats
.alloc_coalesce_succeeded
);
81 printf(" alloc_coalesce_num_merged = %llu\n",
82 (unsigned long long)stats
.stats
.alloc_coalesce_num_merged
);
83 printf("compares = %llu\n",
84 (unsigned long long)stats
.stats
.compares
);
85 printf(" compare_wrong_offsetbits = %llu\n",
86 (unsigned long long)stats
.stats
.compare_wrong_offsetbits
);
87 printf(" compare_wrong_keylen = %llu\n",
88 (unsigned long long)stats
.stats
.compare_wrong_keylen
);
89 printf(" compare_wrong_rechash = %llu\n",
90 (unsigned long long)stats
.stats
.compare_wrong_rechash
);
91 printf(" compare_wrong_keycmp = %llu\n",
92 (unsigned long long)stats
.stats
.compare_wrong_keycmp
);
93 printf("transactions = %llu\n",
94 (unsigned long long)stats
.stats
.transactions
);
95 printf(" transaction_cancel = %llu\n",
96 (unsigned long long)stats
.stats
.transaction_cancel
);
97 printf(" transaction_nest = %llu\n",
98 (unsigned long long)stats
.stats
.transaction_nest
);
99 printf(" transaction_expand_file = %llu\n",
100 (unsigned long long)stats
.stats
.transaction_expand_file
);
101 printf(" transaction_read_direct = %llu\n",
102 (unsigned long long)stats
.stats
.transaction_read_direct
);
103 printf(" transaction_read_direct_fail = %llu\n",
104 (unsigned long long)stats
.stats
.transaction_read_direct_fail
);
105 printf(" transaction_write_direct = %llu\n",
106 (unsigned long long)stats
.stats
.transaction_write_direct
);
107 printf(" transaction_write_direct_fail = %llu\n",
108 (unsigned long long)stats
.stats
.transaction_write_direct_fail
);
109 printf("expands = %llu\n",
110 (unsigned long long)stats
.stats
.expands
);
111 printf("frees = %llu\n",
112 (unsigned long long)stats
.stats
.frees
);
113 printf("locks = %llu\n",
114 (unsigned long long)stats
.stats
.locks
);
115 printf(" lock_lowlevel = %llu\n",
116 (unsigned long long)stats
.stats
.lock_lowlevel
);
117 printf(" lock_nonblock = %llu\n",
118 (unsigned long long)stats
.stats
.lock_nonblock
);
119 printf(" lock_nonblock_fail = %llu\n",
120 (unsigned long long)stats
.stats
.lock_nonblock_fail
);
124 *ntdb
= ntdb_open("/tmp/speed.ntdb", flags
, O_RDWR
, 0, attr
);
127 static void ntdb_log(struct ntdb_context
*ntdb
,
128 enum ntdb_log_level level
,
129 enum NTDB_ERROR ecode
,
133 fprintf(stderr
, "ntdb:%s:%s:%s\n",
134 ntdb_name(ntdb
), ntdb_errorstr(ecode
), message
);
137 int main(int argc
, char *argv
[])
139 unsigned int i
, j
, num
= 1000, stage
= 0, stopat
= -1;
140 int flags
= NTDB_DEFAULT
;
141 bool transaction
= false, summary
= false;
143 struct ntdb_context
*ntdb
;
144 struct timeval start
, stop
;
145 union ntdb_attribute seed
, log
;
146 bool do_stats
= false;
147 enum NTDB_ERROR ecode
;
149 /* Try to keep benchmarks even. */
150 seed
.base
.attr
= NTDB_ATTRIBUTE_SEED
;
151 seed
.base
.next
= NULL
;
154 log
.base
.attr
= NTDB_ATTRIBUTE_LOG
;
155 log
.base
.next
= &seed
;
156 log
.log
.fn
= ntdb_log
;
158 if (argv
[1] && strcmp(argv
[1], "--internal") == 0) {
159 flags
= NTDB_INTERNAL
;
163 if (argv
[1] && strcmp(argv
[1], "--transaction") == 0) {
168 if (argv
[1] && strcmp(argv
[1], "--no-sync") == 0) {
169 flags
|= NTDB_NOSYNC
;
173 if (argv
[1] && strcmp(argv
[1], "--summary") == 0) {
178 if (argv
[1] && strcmp(argv
[1], "--stats") == 0) {
184 ntdb
= ntdb_open("/tmp/speed.ntdb", flags
, O_RDWR
|O_CREAT
|O_TRUNC
,
187 err(1, "Opening /tmp/speed.ntdb");
189 key
.dptr
= (void *)&i
;
190 key
.dsize
= sizeof(i
);
200 stopat
= atoi(argv
[1]);
205 /* Add 1000 records. */
206 printf("Adding %u records: ", num
); fflush(stdout
);
207 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
208 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
209 gettimeofday(&start
, NULL
);
210 for (i
= 0; i
< num
; i
++)
211 if ((ecode
= ntdb_store(ntdb
, key
, data
, NTDB_INSERT
)) != 0)
212 errx(1, "Inserting key %u in ntdb: %s",
213 i
, ntdb_errorstr(ecode
));
214 gettimeofday(&stop
, NULL
);
215 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
216 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
217 printf(" %zu ns (%zu bytes)\n",
218 normalize(&start
, &stop
, num
), file_size());
220 if (ntdb_check(ntdb
, NULL
, NULL
))
221 errx(1, "ntdb_check failed!");
224 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
225 printf("%s\n", sumstr
);
229 dump_and_clear_stats(&ntdb
, flags
, &log
);
231 if (++stage
== stopat
)
234 /* Finding 1000 records. */
235 printf("Finding %u records: ", num
); fflush(stdout
);
236 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
237 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
238 gettimeofday(&start
, NULL
);
239 for (i
= 0; i
< num
; i
++) {
241 if ((ecode
= ntdb_fetch(ntdb
, key
, &dbuf
)) != NTDB_SUCCESS
242 || *(int *)dbuf
.dptr
!= i
) {
243 errx(1, "Fetching key %u in ntdb gave %u",
244 i
, ecode
? ecode
: *(int *)dbuf
.dptr
);
247 gettimeofday(&stop
, NULL
);
248 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
249 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
250 printf(" %zu ns (%zu bytes)\n",
251 normalize(&start
, &stop
, num
), file_size());
252 if (ntdb_check(ntdb
, NULL
, NULL
))
253 errx(1, "ntdb_check failed!");
256 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
257 printf("%s\n", sumstr
);
261 dump_and_clear_stats(&ntdb
, flags
, &log
);
262 if (++stage
== stopat
)
265 /* Missing 1000 records. */
266 printf("Missing %u records: ", num
); fflush(stdout
);
267 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
268 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
269 gettimeofday(&start
, NULL
);
270 for (i
= num
; i
< num
*2; i
++) {
272 ecode
= ntdb_fetch(ntdb
, key
, &dbuf
);
273 if (ecode
!= NTDB_ERR_NOEXIST
)
274 errx(1, "Fetching key %u in ntdb gave %s",
275 i
, ntdb_errorstr(ecode
));
277 gettimeofday(&stop
, NULL
);
278 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
279 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
280 printf(" %zu ns (%zu bytes)\n",
281 normalize(&start
, &stop
, num
), file_size());
282 if (ntdb_check(ntdb
, NULL
, NULL
))
283 errx(1, "ntdb_check failed!");
286 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
287 printf("%s\n", sumstr
);
291 dump_and_clear_stats(&ntdb
, flags
, &log
);
292 if (++stage
== stopat
)
295 /* Traverse 1000 records. */
296 printf("Traversing %u records: ", num
); fflush(stdout
);
297 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
298 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
300 gettimeofday(&start
, NULL
);
301 if (ntdb_traverse(ntdb
, count_record
, &i
) != num
)
302 errx(1, "Traverse returned wrong number of records");
303 if (i
!= (num
- 1) * (num
/ 2))
304 errx(1, "Traverse tallied to %u", i
);
305 gettimeofday(&stop
, NULL
);
306 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
307 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
308 printf(" %zu ns (%zu bytes)\n",
309 normalize(&start
, &stop
, num
), file_size());
310 if (ntdb_check(ntdb
, NULL
, NULL
))
311 errx(1, "ntdb_check failed!");
314 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
315 printf("%s\n", sumstr
);
319 dump_and_clear_stats(&ntdb
, flags
, &log
);
320 if (++stage
== stopat
)
323 /* Delete 1000 records (not in order). */
324 printf("Deleting %u records: ", num
); fflush(stdout
);
325 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
326 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
327 gettimeofday(&start
, NULL
);
328 for (j
= 0; j
< num
; j
++) {
329 i
= (j
+ 100003) % num
;
330 if ((ecode
= ntdb_delete(ntdb
, key
)) != NTDB_SUCCESS
)
331 errx(1, "Deleting key %u in ntdb: %s",
332 i
, ntdb_errorstr(ecode
));
334 gettimeofday(&stop
, NULL
);
335 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
336 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
337 printf(" %zu ns (%zu bytes)\n",
338 normalize(&start
, &stop
, num
), file_size());
339 if (ntdb_check(ntdb
, NULL
, NULL
))
340 errx(1, "ntdb_check failed!");
343 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
344 printf("%s\n", sumstr
);
348 dump_and_clear_stats(&ntdb
, flags
, &log
);
349 if (++stage
== stopat
)
352 /* Re-add 1000 records (not in order). */
353 printf("Re-adding %u records: ", num
); fflush(stdout
);
354 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
355 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
356 gettimeofday(&start
, NULL
);
357 for (j
= 0; j
< num
; j
++) {
358 i
= (j
+ 100003) % num
;
359 if ((ecode
= ntdb_store(ntdb
, key
, data
, NTDB_INSERT
)) != 0)
360 errx(1, "Inserting key %u in ntdb: %s",
361 i
, ntdb_errorstr(ecode
));
363 gettimeofday(&stop
, NULL
);
364 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
365 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
366 printf(" %zu ns (%zu bytes)\n",
367 normalize(&start
, &stop
, num
), file_size());
368 if (ntdb_check(ntdb
, NULL
, NULL
))
369 errx(1, "ntdb_check failed!");
372 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
373 printf("%s\n", sumstr
);
377 dump_and_clear_stats(&ntdb
, flags
, &log
);
378 if (++stage
== stopat
)
381 /* Append 1000 records. */
382 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
383 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
384 printf("Appending %u records: ", num
); fflush(stdout
);
385 gettimeofday(&start
, NULL
);
386 for (i
= 0; i
< num
; i
++)
387 if ((ecode
= ntdb_append(ntdb
, key
, data
)) != NTDB_SUCCESS
)
388 errx(1, "Appending key %u in ntdb: %s",
389 i
, ntdb_errorstr(ecode
));
390 gettimeofday(&stop
, NULL
);
391 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
392 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
393 printf(" %zu ns (%zu bytes)\n",
394 normalize(&start
, &stop
, num
), file_size());
395 if (ntdb_check(ntdb
, NULL
, NULL
))
396 errx(1, "ntdb_check failed!");
399 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
400 printf("%s\n", sumstr
);
403 if (++stage
== stopat
)
406 /* Churn 1000 records: not in order! */
407 if (transaction
&& (ecode
= ntdb_transaction_start(ntdb
)))
408 errx(1, "starting transaction: %s", ntdb_errorstr(ecode
));
409 printf("Churning %u records: ", num
); fflush(stdout
);
410 gettimeofday(&start
, NULL
);
411 for (j
= 0; j
< num
; j
++) {
412 i
= (j
+ 1000019) % num
;
413 if ((ecode
= ntdb_delete(ntdb
, key
)) != NTDB_SUCCESS
)
414 errx(1, "Deleting key %u in ntdb: %s",
415 i
, ntdb_errorstr(ecode
));
417 if ((ecode
= ntdb_store(ntdb
, key
, data
, NTDB_INSERT
)) != 0)
418 errx(1, "Inserting key %u in ntdb: %s",
419 i
, ntdb_errorstr(ecode
));
421 gettimeofday(&stop
, NULL
);
422 if (transaction
&& (ecode
= ntdb_transaction_commit(ntdb
)))
423 errx(1, "committing transaction: %s", ntdb_errorstr(ecode
));
424 printf(" %zu ns (%zu bytes)\n",
425 normalize(&start
, &stop
, num
), file_size());
427 if (ntdb_check(ntdb
, NULL
, NULL
))
428 errx(1, "ntdb_check failed!");
431 ntdb_summary(ntdb
, NTDB_SUMMARY_HISTOGRAMS
, &sumstr
);
432 printf("%s\n", sumstr
);
436 dump_and_clear_stats(&ntdb
, flags
, &log
);
437 if (++stage
== stopat
)