1 /* Simple speed test for TDB */
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.tdb", &st
) != 0)
38 static int count_record(struct tdb_context
*tdb
,
39 TDB_DATA key
, TDB_DATA data
, void *p
)
42 *total
+= *(int *)data
.dptr
;
46 static void dump_and_clear_stats(struct tdb_context
**tdb
,
48 union tdb_attribute
*attr
)
50 union tdb_attribute stats
;
53 stats
.base
.attr
= TDB_ATTRIBUTE_STATS
;
54 stats
.stats
.size
= sizeof(stats
.stats
);
55 ecode
= tdb_get_attribute(*tdb
, &stats
);
56 if (ecode
!= TDB_SUCCESS
)
57 errx(1, "Getting stats: %s", tdb_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_bucket = %llu\n",
86 (unsigned long long)stats
.stats
.compare_wrong_bucket
);
87 printf(" compare_wrong_offsetbits = %llu\n",
88 (unsigned long long)stats
.stats
.compare_wrong_offsetbits
);
89 printf(" compare_wrong_keylen = %llu\n",
90 (unsigned long long)stats
.stats
.compare_wrong_keylen
);
91 printf(" compare_wrong_rechash = %llu\n",
92 (unsigned long long)stats
.stats
.compare_wrong_rechash
);
93 printf(" compare_wrong_keycmp = %llu\n",
94 (unsigned long long)stats
.stats
.compare_wrong_keycmp
);
95 printf("transactions = %llu\n",
96 (unsigned long long)stats
.stats
.transactions
);
97 printf(" transaction_cancel = %llu\n",
98 (unsigned long long)stats
.stats
.transaction_cancel
);
99 printf(" transaction_nest = %llu\n",
100 (unsigned long long)stats
.stats
.transaction_nest
);
101 printf(" transaction_expand_file = %llu\n",
102 (unsigned long long)stats
.stats
.transaction_expand_file
);
103 printf(" transaction_read_direct = %llu\n",
104 (unsigned long long)stats
.stats
.transaction_read_direct
);
105 printf(" transaction_read_direct_fail = %llu\n",
106 (unsigned long long)stats
.stats
.transaction_read_direct_fail
);
107 printf(" transaction_write_direct = %llu\n",
108 (unsigned long long)stats
.stats
.transaction_write_direct
);
109 printf(" transaction_write_direct_fail = %llu\n",
110 (unsigned long long)stats
.stats
.transaction_write_direct_fail
);
111 printf("expands = %llu\n",
112 (unsigned long long)stats
.stats
.expands
);
113 printf("frees = %llu\n",
114 (unsigned long long)stats
.stats
.frees
);
115 printf("locks = %llu\n",
116 (unsigned long long)stats
.stats
.locks
);
117 printf(" lock_lowlevel = %llu\n",
118 (unsigned long long)stats
.stats
.lock_lowlevel
);
119 printf(" lock_nonblock = %llu\n",
120 (unsigned long long)stats
.stats
.lock_nonblock
);
121 printf(" lock_nonblock_fail = %llu\n",
122 (unsigned long long)stats
.stats
.lock_nonblock_fail
);
126 *tdb
= tdb_open("/tmp/speed.tdb", flags
, O_RDWR
, 0, attr
);
129 static void tdb_log(struct tdb_context
*tdb
,
130 enum tdb_log_level level
,
131 enum TDB_ERROR ecode
,
135 fprintf(stderr
, "tdb:%s:%s:%s\n",
136 tdb_name(tdb
), tdb_errorstr(ecode
), message
);
139 int main(int argc
, char *argv
[])
141 unsigned int i
, j
, num
= 1000, stage
= 0, stopat
= -1;
142 int flags
= TDB_DEFAULT
;
143 bool transaction
= false, summary
= false;
145 struct tdb_context
*tdb
;
146 struct timeval start
, stop
;
147 union tdb_attribute seed
, log
;
148 bool do_stats
= false;
149 enum TDB_ERROR ecode
;
151 /* Try to keep benchmarks even. */
152 seed
.base
.attr
= TDB_ATTRIBUTE_SEED
;
153 seed
.base
.next
= NULL
;
156 log
.base
.attr
= TDB_ATTRIBUTE_LOG
;
157 log
.base
.next
= &seed
;
158 log
.log
.fn
= tdb_log
;
160 if (argv
[1] && strcmp(argv
[1], "--internal") == 0) {
161 flags
= TDB_INTERNAL
;
165 if (argv
[1] && strcmp(argv
[1], "--transaction") == 0) {
170 if (argv
[1] && strcmp(argv
[1], "--no-sync") == 0) {
175 if (argv
[1] && strcmp(argv
[1], "--summary") == 0) {
180 if (argv
[1] && strcmp(argv
[1], "--stats") == 0) {
186 tdb
= tdb_open("/tmp/speed.tdb", flags
, O_RDWR
|O_CREAT
|O_TRUNC
,
189 err(1, "Opening /tmp/speed.tdb");
191 key
.dptr
= (void *)&i
;
192 key
.dsize
= sizeof(i
);
202 stopat
= atoi(argv
[1]);
207 /* Add 1000 records. */
208 printf("Adding %u records: ", num
); fflush(stdout
);
209 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
210 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
211 gettimeofday(&start
, NULL
);
212 for (i
= 0; i
< num
; i
++)
213 if ((ecode
= tdb_store(tdb
, key
, data
, TDB_INSERT
)) != 0)
214 errx(1, "Inserting key %u in tdb: %s",
215 i
, tdb_errorstr(ecode
));
216 gettimeofday(&stop
, NULL
);
217 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
218 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
219 printf(" %zu ns (%zu bytes)\n",
220 normalize(&start
, &stop
, num
), file_size());
222 if (tdb_check(tdb
, NULL
, NULL
))
223 errx(1, "tdb_check failed!");
226 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
227 printf("%s\n", sumstr
);
231 dump_and_clear_stats(&tdb
, flags
, &log
);
233 if (++stage
== stopat
)
236 /* Finding 1000 records. */
237 printf("Finding %u records: ", num
); fflush(stdout
);
238 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
239 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
240 gettimeofday(&start
, NULL
);
241 for (i
= 0; i
< num
; i
++) {
242 struct tdb_data dbuf
;
243 if ((ecode
= tdb_fetch(tdb
, key
, &dbuf
)) != TDB_SUCCESS
244 || *(int *)dbuf
.dptr
!= i
) {
245 errx(1, "Fetching key %u in tdb gave %u",
246 i
, ecode
? ecode
: *(int *)dbuf
.dptr
);
249 gettimeofday(&stop
, NULL
);
250 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
251 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
252 printf(" %zu ns (%zu bytes)\n",
253 normalize(&start
, &stop
, num
), file_size());
254 if (tdb_check(tdb
, NULL
, NULL
))
255 errx(1, "tdb_check failed!");
258 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
259 printf("%s\n", sumstr
);
263 dump_and_clear_stats(&tdb
, flags
, &log
);
264 if (++stage
== stopat
)
267 /* Missing 1000 records. */
268 printf("Missing %u records: ", num
); fflush(stdout
);
269 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
270 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
271 gettimeofday(&start
, NULL
);
272 for (i
= num
; i
< num
*2; i
++) {
273 struct tdb_data dbuf
;
274 ecode
= tdb_fetch(tdb
, key
, &dbuf
);
275 if (ecode
!= TDB_ERR_NOEXIST
)
276 errx(1, "Fetching key %u in tdb gave %s",
277 i
, tdb_errorstr(ecode
));
279 gettimeofday(&stop
, NULL
);
280 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
281 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
282 printf(" %zu ns (%zu bytes)\n",
283 normalize(&start
, &stop
, num
), file_size());
284 if (tdb_check(tdb
, NULL
, NULL
))
285 errx(1, "tdb_check failed!");
288 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
289 printf("%s\n", sumstr
);
293 dump_and_clear_stats(&tdb
, flags
, &log
);
294 if (++stage
== stopat
)
297 /* Traverse 1000 records. */
298 printf("Traversing %u records: ", num
); fflush(stdout
);
299 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
300 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
302 gettimeofday(&start
, NULL
);
303 if (tdb_traverse(tdb
, count_record
, &i
) != num
)
304 errx(1, "Traverse returned wrong number of records");
305 if (i
!= (num
- 1) * (num
/ 2))
306 errx(1, "Traverse tallied to %u", i
);
307 gettimeofday(&stop
, NULL
);
308 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
309 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
310 printf(" %zu ns (%zu bytes)\n",
311 normalize(&start
, &stop
, num
), file_size());
312 if (tdb_check(tdb
, NULL
, NULL
))
313 errx(1, "tdb_check failed!");
316 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
317 printf("%s\n", sumstr
);
321 dump_and_clear_stats(&tdb
, flags
, &log
);
322 if (++stage
== stopat
)
325 /* Delete 1000 records (not in order). */
326 printf("Deleting %u records: ", num
); fflush(stdout
);
327 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
328 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
329 gettimeofday(&start
, NULL
);
330 for (j
= 0; j
< num
; j
++) {
331 i
= (j
+ 100003) % num
;
332 if ((ecode
= tdb_delete(tdb
, key
)) != TDB_SUCCESS
)
333 errx(1, "Deleting key %u in tdb: %s",
334 i
, tdb_errorstr(ecode
));
336 gettimeofday(&stop
, NULL
);
337 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
338 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
339 printf(" %zu ns (%zu bytes)\n",
340 normalize(&start
, &stop
, num
), file_size());
341 if (tdb_check(tdb
, NULL
, NULL
))
342 errx(1, "tdb_check failed!");
345 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
346 printf("%s\n", sumstr
);
350 dump_and_clear_stats(&tdb
, flags
, &log
);
351 if (++stage
== stopat
)
354 /* Re-add 1000 records (not in order). */
355 printf("Re-adding %u records: ", num
); fflush(stdout
);
356 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
357 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
358 gettimeofday(&start
, NULL
);
359 for (j
= 0; j
< num
; j
++) {
360 i
= (j
+ 100003) % num
;
361 if ((ecode
= tdb_store(tdb
, key
, data
, TDB_INSERT
)) != 0)
362 errx(1, "Inserting key %u in tdb: %s",
363 i
, tdb_errorstr(ecode
));
365 gettimeofday(&stop
, NULL
);
366 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
367 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
368 printf(" %zu ns (%zu bytes)\n",
369 normalize(&start
, &stop
, num
), file_size());
370 if (tdb_check(tdb
, NULL
, NULL
))
371 errx(1, "tdb_check failed!");
374 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
375 printf("%s\n", sumstr
);
379 dump_and_clear_stats(&tdb
, flags
, &log
);
380 if (++stage
== stopat
)
383 /* Append 1000 records. */
384 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
385 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
386 printf("Appending %u records: ", num
); fflush(stdout
);
387 gettimeofday(&start
, NULL
);
388 for (i
= 0; i
< num
; i
++)
389 if ((ecode
= tdb_append(tdb
, key
, data
)) != TDB_SUCCESS
)
390 errx(1, "Appending key %u in tdb: %s",
391 i
, tdb_errorstr(ecode
));
392 gettimeofday(&stop
, NULL
);
393 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
394 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
395 printf(" %zu ns (%zu bytes)\n",
396 normalize(&start
, &stop
, num
), file_size());
397 if (tdb_check(tdb
, NULL
, NULL
))
398 errx(1, "tdb_check failed!");
401 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
402 printf("%s\n", sumstr
);
405 if (++stage
== stopat
)
408 /* Churn 1000 records: not in order! */
409 if (transaction
&& (ecode
= tdb_transaction_start(tdb
)))
410 errx(1, "starting transaction: %s", tdb_errorstr(ecode
));
411 printf("Churning %u records: ", num
); fflush(stdout
);
412 gettimeofday(&start
, NULL
);
413 for (j
= 0; j
< num
; j
++) {
414 i
= (j
+ 1000019) % num
;
415 if ((ecode
= tdb_delete(tdb
, key
)) != TDB_SUCCESS
)
416 errx(1, "Deleting key %u in tdb: %s",
417 i
, tdb_errorstr(ecode
));
419 if ((ecode
= tdb_store(tdb
, key
, data
, TDB_INSERT
)) != 0)
420 errx(1, "Inserting key %u in tdb: %s",
421 i
, tdb_errorstr(ecode
));
423 gettimeofday(&stop
, NULL
);
424 if (transaction
&& (ecode
= tdb_transaction_commit(tdb
)))
425 errx(1, "committing transaction: %s", tdb_errorstr(ecode
));
426 printf(" %zu ns (%zu bytes)\n",
427 normalize(&start
, &stop
, num
), file_size());
429 if (tdb_check(tdb
, NULL
, NULL
))
430 errx(1, "tdb_check failed!");
433 tdb_summary(tdb
, TDB_SUMMARY_HISTOGRAMS
, &sumstr
);
434 printf("%s\n", sumstr
);
438 dump_and_clear_stats(&tdb
, flags
, &log
);
439 if (++stage
== stopat
)