1 /* Simple speed test for TDB */
13 #include <ccan/tdb2/tdb2.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.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_attribute_stats *stats)
48 printf("allocs = %llu\n",
49 (unsigned long long)stats->allocs);
50 printf(" alloc_subhash = %llu\n",
51 (unsigned long long)stats->alloc_subhash);
52 printf(" alloc_bucket_exact = %llu\n",
53 (unsigned long long)stats->alloc_bucket_exact);
54 printf(" alloc_bucket_max = %llu\n",
55 (unsigned long long)stats->alloc_bucket_max);
56 printf(" alloc_leftover = %llu\n",
57 (unsigned long long)stats->alloc_leftover);
58 printf(" alloc_coalesce_tried = %llu\n",
59 (unsigned long long)stats->alloc_coalesce_tried);
60 printf(" alloc_coalesce_lockfail = %llu\n",
61 (unsigned long long)stats->alloc_coalesce_lockfail);
62 printf(" alloc_coalesce_race = %llu\n",
63 (unsigned long long)stats->alloc_coalesce_race);
64 printf(" alloc_coalesce_succeeded = %llu\n",
65 (unsigned long long)stats->alloc_coalesce_succeeded);
66 printf(" alloc_coalesce_num_merged = %llu\n",
67 (unsigned long long)stats->alloc_coalesce_num_merged);
68 printf("compares = %llu\n",
69 (unsigned long long)stats->compares);
70 printf(" compare_wrong_bucket = %llu\n",
71 (unsigned long long)stats->compare_wrong_bucket);
72 printf(" compare_wrong_offsetbits = %llu\n",
73 (unsigned long long)stats->compare_wrong_offsetbits);
74 printf(" compare_wrong_keylen = %llu\n",
75 (unsigned long long)stats->compare_wrong_keylen);
76 printf(" compare_wrong_rechash = %llu\n",
77 (unsigned long long)stats->compare_wrong_rechash);
78 printf(" compare_wrong_keycmp = %llu\n",
79 (unsigned long long)stats->compare_wrong_keycmp);
80 printf("expands = %llu\n",
81 (unsigned long long)stats->expands);
82 printf("frees = %llu\n",
83 (unsigned long long)stats->frees);
84 printf("locks = %llu\n",
85 (unsigned long long)stats->locks);
86 printf(" lock_lowlevel = %llu\n",
87 (unsigned long long)stats->lock_lowlevel);
88 printf(" lock_nonblock = %llu\n",
89 (unsigned long long)stats->lock_nonblock);
92 memset(&stats->allocs, 0, (char *)(stats+1) - (char *)&stats->allocs);
95 int main(int argc, char *argv[])
97 unsigned int i, j, num = 1000, stage = 0, stopat = -1;
98 int flags = TDB_DEFAULT;
99 bool transaction = false;
101 struct tdb_context *tdb;
102 struct timeval start, stop;
103 union tdb_attribute seed, stats;
105 /* Try to keep benchmarks even. */
106 seed.base.attr = TDB_ATTRIBUTE_SEED;
107 seed.base.next = NULL;
110 memset(&stats, 0, sizeof(stats));
111 stats.base.attr = TDB_ATTRIBUTE_STATS;
112 stats.base.next = NULL;
113 stats.stats.size = sizeof(stats);
115 if (argv[1] && strcmp(argv[1], "--internal") == 0) {
116 flags = TDB_INTERNAL;
120 if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
125 if (argv[1] && strcmp(argv[1], "--stats") == 0) {
126 seed.base.next = &stats;
131 tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR|O_CREAT|O_TRUNC,
134 err(1, "Opening /tmp/speed.tdb");
136 key.dptr = (void *)&i;
137 key.dsize = sizeof(i);
147 stopat = atoi(argv[1]);
152 if (transaction && tdb_transaction_start(tdb))
153 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
155 /* Add 1000 records. */
156 printf("Adding %u records: ", num); fflush(stdout);
157 gettimeofday(&start, NULL);
158 for (i = 0; i < num; i++)
159 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
160 errx(1, "Inserting key %u in tdb: %s",
161 i, tdb_errorstr(tdb));
162 gettimeofday(&stop, NULL);
163 if (transaction && tdb_transaction_commit(tdb))
164 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
165 printf(" %zu ns (%zu bytes)\n",
166 normalize(&start, &stop, num), file_size());
169 dump_and_clear_stats(&stats.stats);
170 if (++stage == stopat)
173 if (transaction && tdb_transaction_start(tdb))
174 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
176 /* Finding 1000 records. */
177 printf("Finding %u records: ", num); fflush(stdout);
178 gettimeofday(&start, NULL);
179 for (i = 0; i < num; i++) {
181 dptr = (int *)tdb_fetch(tdb, key).dptr;
182 if (!dptr || *dptr != i)
183 errx(1, "Fetching key %u in tdb gave %u",
184 i, dptr ? *dptr : -1);
186 gettimeofday(&stop, NULL);
187 if (transaction && tdb_transaction_commit(tdb))
188 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
189 printf(" %zu ns (%zu bytes)\n",
190 normalize(&start, &stop, num), file_size());
192 dump_and_clear_stats(&stats.stats);
193 if (++stage == stopat)
196 if (transaction && tdb_transaction_start(tdb))
197 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
199 /* Missing 1000 records. */
200 printf("Missing %u records: ", num); fflush(stdout);
201 gettimeofday(&start, NULL);
202 for (i = num; i < num*2; i++) {
204 dptr = (int *)tdb_fetch(tdb, key).dptr;
206 errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
208 gettimeofday(&stop, NULL);
209 if (transaction && tdb_transaction_commit(tdb))
210 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
211 printf(" %zu ns (%zu bytes)\n",
212 normalize(&start, &stop, num), file_size());
214 dump_and_clear_stats(&stats.stats);
215 if (++stage == stopat)
218 if (transaction && tdb_transaction_start(tdb))
219 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
221 /* Traverse 1000 records. */
222 printf("Traversing %u records: ", num); fflush(stdout);
224 gettimeofday(&start, NULL);
225 if (tdb_traverse(tdb, count_record, &i) != num)
226 errx(1, "Traverse returned wrong number of records");
227 if (i != (num - 1) * (num / 2))
228 errx(1, "Traverse tallied to %u", i);
229 gettimeofday(&stop, NULL);
230 if (transaction && tdb_transaction_commit(tdb))
231 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
232 printf(" %zu ns (%zu bytes)\n",
233 normalize(&start, &stop, num), file_size());
235 dump_and_clear_stats(&stats.stats);
236 if (++stage == stopat)
239 if (transaction && tdb_transaction_start(tdb))
240 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
242 /* Delete 1000 records (not in order). */
243 printf("Deleting %u records: ", num); fflush(stdout);
244 gettimeofday(&start, NULL);
245 for (j = 0; j < num; j++) {
246 i = (j + 100003) % num;
247 if (tdb_delete(tdb, key) != 0)
248 errx(1, "Deleting key %u in tdb: %s",
249 i, tdb_errorstr(tdb));
251 gettimeofday(&stop, NULL);
252 if (transaction && tdb_transaction_commit(tdb))
253 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
254 printf(" %zu ns (%zu bytes)\n",
255 normalize(&start, &stop, num), file_size());
257 dump_and_clear_stats(&stats.stats);
258 if (++stage == stopat)
261 if (transaction && tdb_transaction_start(tdb))
262 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
264 /* Re-add 1000 records (not in order). */
265 printf("Re-adding %u records: ", num); fflush(stdout);
266 gettimeofday(&start, NULL);
267 for (j = 0; j < num; j++) {
268 i = (j + 100003) % num;
269 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
270 errx(1, "Inserting key %u in tdb: %s",
271 i, tdb_errorstr(tdb));
273 gettimeofday(&stop, NULL);
274 if (transaction && tdb_transaction_commit(tdb))
275 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
276 printf(" %zu ns (%zu bytes)\n",
277 normalize(&start, &stop, num), file_size());
279 dump_and_clear_stats(&stats.stats);
280 if (++stage == stopat)
283 if (transaction && tdb_transaction_start(tdb))
284 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
286 /* Append 1000 records. */
287 printf("Appending %u records: ", num); fflush(stdout);
288 gettimeofday(&start, NULL);
289 for (i = 0; i < num; i++)
290 if (tdb_append(tdb, key, data) != 0)
291 errx(1, "Appending key %u in tdb: %s",
292 i, tdb_errorstr(tdb));
293 gettimeofday(&stop, NULL);
294 if (transaction && tdb_transaction_commit(tdb))
295 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
296 printf(" %zu ns (%zu bytes)\n",
297 normalize(&start, &stop, num), file_size());
298 if (++stage == stopat)
301 if (transaction && tdb_transaction_start(tdb))
302 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
304 /* Churn 1000 records: not in order! */
305 printf("Churning %u records: ", num); fflush(stdout);
306 gettimeofday(&start, NULL);
307 for (j = 0; j < num; j++) {
308 i = (j + 1000019) % num;
309 if (tdb_delete(tdb, key) != 0)
310 errx(1, "Deleting key %u in tdb: %s",
311 i, tdb_errorstr(tdb));
313 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
314 errx(1, "Inserting key %u in tdb: %s",
315 i, tdb_errorstr(tdb));
317 gettimeofday(&stop, NULL);
318 if (transaction && tdb_transaction_commit(tdb))
319 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
320 printf(" %zu ns (%zu bytes)\n",
321 normalize(&start, &stop, num), file_size());
324 dump_and_clear_stats(&stats.stats);
325 if (++stage == stopat)