s4:torture: cleanup after smb2 setinfo scan
[Samba/gebeck_regimport.git] / lib / tdb2 / tools / speed.c
blobccb5ae349d894f43d57ce0349b280d6539713e7d
1 /* Simple speed test for TDB */
2 #include <err.h>
3 #include <time.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <sys/time.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdbool.h>
13 #include "tdb2.h"
15 /* Nanoseconds per operation */
16 static size_t normalize(const struct timeval *start,
17 const struct timeval *stop,
18 unsigned int num)
20 struct timeval diff;
22 timersub(stop, start, &diff);
24 /* Floating point is more accurate here. */
25 return (double)(diff.tv_sec * 1000000 + diff.tv_usec)
26 / num * 1000;
29 static size_t file_size(void)
31 struct stat st;
33 if (stat("/tmp/speed.tdb", &st) != 0)
34 return -1;
35 return st.st_size;
38 static int count_record(struct tdb_context *tdb,
39 TDB_DATA key, TDB_DATA data, void *p)
41 int *total = p;
42 *total += *(int *)data.dptr;
43 return 0;
46 static void dump_and_clear_stats(struct tdb_context **tdb,
47 int flags,
48 union tdb_attribute *attr)
50 union tdb_attribute stats;
51 enum TDB_ERROR ecode;
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);
124 /* Now clear. */
125 tdb_close(*tdb);
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,
132 const char *message,
133 void *data)
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;
144 TDB_DATA key, data;
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;
154 seed.seed.seed = 0;
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;
162 argc--;
163 argv++;
165 if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
166 transaction = true;
167 argc--;
168 argv++;
170 if (argv[1] && strcmp(argv[1], "--no-sync") == 0) {
171 flags |= TDB_NOSYNC;
172 argc--;
173 argv++;
175 if (argv[1] && strcmp(argv[1], "--summary") == 0) {
176 summary = true;
177 argc--;
178 argv++;
180 if (argv[1] && strcmp(argv[1], "--stats") == 0) {
181 do_stats = true;
182 argc--;
183 argv++;
186 tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR|O_CREAT|O_TRUNC,
187 0600, &log);
188 if (!tdb)
189 err(1, "Opening /tmp/speed.tdb");
191 key.dptr = (void *)&i;
192 key.dsize = sizeof(i);
193 data = key;
195 if (argv[1]) {
196 num = atoi(argv[1]);
197 argv++;
198 argc--;
201 if (argv[1]) {
202 stopat = atoi(argv[1]);
203 argv++;
204 argc--;
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!");
224 if (summary) {
225 char *sumstr = NULL;
226 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
227 printf("%s\n", sumstr);
228 free(sumstr);
230 if (do_stats)
231 dump_and_clear_stats(&tdb, flags, &log);
233 if (++stage == stopat)
234 exit(0);
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!");
256 if (summary) {
257 char *sumstr = NULL;
258 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
259 printf("%s\n", sumstr);
260 free(sumstr);
262 if (do_stats)
263 dump_and_clear_stats(&tdb, flags, &log);
264 if (++stage == stopat)
265 exit(0);
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!");
286 if (summary) {
287 char *sumstr = NULL;
288 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
289 printf("%s\n", sumstr);
290 free(sumstr);
292 if (do_stats)
293 dump_and_clear_stats(&tdb, flags, &log);
294 if (++stage == stopat)
295 exit(0);
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));
301 i = 0;
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!");
314 if (summary) {
315 char *sumstr = NULL;
316 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
317 printf("%s\n", sumstr);
318 free(sumstr);
320 if (do_stats)
321 dump_and_clear_stats(&tdb, flags, &log);
322 if (++stage == stopat)
323 exit(0);
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!");
343 if (summary) {
344 char *sumstr = NULL;
345 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
346 printf("%s\n", sumstr);
347 free(sumstr);
349 if (do_stats)
350 dump_and_clear_stats(&tdb, flags, &log);
351 if (++stage == stopat)
352 exit(0);
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!");
372 if (summary) {
373 char *sumstr = NULL;
374 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
375 printf("%s\n", sumstr);
376 free(sumstr);
378 if (do_stats)
379 dump_and_clear_stats(&tdb, flags, &log);
380 if (++stage == stopat)
381 exit(0);
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!");
399 if (summary) {
400 char *sumstr = NULL;
401 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
402 printf("%s\n", sumstr);
403 free(sumstr);
405 if (++stage == stopat)
406 exit(0);
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));
418 i += num;
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!");
431 if (summary) {
432 char *sumstr = NULL;
433 tdb_summary(tdb, TDB_SUMMARY_HISTOGRAMS, &sumstr);
434 printf("%s\n", sumstr);
435 free(sumstr);
437 if (do_stats)
438 dump_and_clear_stats(&tdb, flags, &log);
439 if (++stage == stopat)
440 exit(0);
442 return 0;