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_chain = %llu\n",
53 (unsigned long long)stats->alloc_chain);
54 printf(" alloc_bucket_exact = %llu\n",
55 (unsigned long long)stats->alloc_bucket_exact);
56 printf(" alloc_bucket_max = %llu\n",
57 (unsigned long long)stats->alloc_bucket_max);
58 printf(" alloc_leftover = %llu\n",
59 (unsigned long long)stats->alloc_leftover);
60 printf(" alloc_coalesce_tried = %llu\n",
61 (unsigned long long)stats->alloc_coalesce_tried);
62 printf(" alloc_coalesce_lockfail = %llu\n",
63 (unsigned long long)stats->alloc_coalesce_lockfail);
64 printf(" alloc_coalesce_race = %llu\n",
65 (unsigned long long)stats->alloc_coalesce_race);
66 printf(" alloc_coalesce_succeeded = %llu\n",
67 (unsigned long long)stats->alloc_coalesce_succeeded);
68 printf(" alloc_coalesce_num_merged = %llu\n",
69 (unsigned long long)stats->alloc_coalesce_num_merged);
70 printf("compares = %llu\n",
71 (unsigned long long)stats->compares);
72 printf(" compare_wrong_bucket = %llu\n",
73 (unsigned long long)stats->compare_wrong_bucket);
74 printf(" compare_wrong_offsetbits = %llu\n",
75 (unsigned long long)stats->compare_wrong_offsetbits);
76 printf(" compare_wrong_keylen = %llu\n",
77 (unsigned long long)stats->compare_wrong_keylen);
78 printf(" compare_wrong_rechash = %llu\n",
79 (unsigned long long)stats->compare_wrong_rechash);
80 printf(" compare_wrong_keycmp = %llu\n",
81 (unsigned long long)stats->compare_wrong_keycmp);
82 printf("expands = %llu\n",
83 (unsigned long long)stats->expands);
84 printf("frees = %llu\n",
85 (unsigned long long)stats->frees);
86 printf("locks = %llu\n",
87 (unsigned long long)stats->locks);
88 printf(" lock_lowlevel = %llu\n",
89 (unsigned long long)stats->lock_lowlevel);
90 printf(" lock_nonblock = %llu\n",
91 (unsigned long long)stats->lock_nonblock);
94 memset(&stats->allocs, 0, (char *)(stats+1) - (char *)&stats->allocs);
97 int main(int argc, char *argv[])
99 unsigned int i, j, num = 1000, stage = 0, stopat = -1;
100 int flags = TDB_DEFAULT;
101 bool transaction = false;
103 struct tdb_context *tdb;
104 struct timeval start, stop;
105 union tdb_attribute seed, stats;
107 /* Try to keep benchmarks even. */
108 seed.base.attr = TDB_ATTRIBUTE_SEED;
109 seed.base.next = NULL;
112 memset(&stats, 0, sizeof(stats));
113 stats.base.attr = TDB_ATTRIBUTE_STATS;
114 stats.base.next = NULL;
115 stats.stats.size = sizeof(stats);
117 if (argv[1] && strcmp(argv[1], "--internal") == 0) {
118 flags = TDB_INTERNAL;
122 if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
127 if (argv[1] && strcmp(argv[1], "--stats") == 0) {
128 seed.base.next = &stats;
133 tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR|O_CREAT|O_TRUNC,
136 err(1, "Opening /tmp/speed.tdb");
138 key.dptr = (void *)&i;
139 key.dsize = sizeof(i);
149 stopat = atoi(argv[1]);
154 if (transaction && tdb_transaction_start(tdb))
155 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
157 /* Add 1000 records. */
158 printf("Adding %u records: ", num); fflush(stdout);
159 gettimeofday(&start, NULL);
160 for (i = 0; i < num; i++)
161 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
162 errx(1, "Inserting key %u in tdb: %s",
163 i, tdb_errorstr(tdb));
164 gettimeofday(&stop, NULL);
165 if (transaction && tdb_transaction_commit(tdb))
166 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
167 printf(" %zu ns (%zu bytes)\n",
168 normalize(&start, &stop, num), file_size());
171 dump_and_clear_stats(&stats.stats);
172 if (++stage == stopat)
175 if (transaction && tdb_transaction_start(tdb))
176 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
178 /* Finding 1000 records. */
179 printf("Finding %u records: ", num); fflush(stdout);
180 gettimeofday(&start, NULL);
181 for (i = 0; i < num; i++) {
183 dptr = (int *)tdb_fetch(tdb, key).dptr;
184 if (!dptr || *dptr != i)
185 errx(1, "Fetching key %u in tdb gave %u",
186 i, dptr ? *dptr : -1);
188 gettimeofday(&stop, NULL);
189 if (transaction && tdb_transaction_commit(tdb))
190 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
191 printf(" %zu ns (%zu bytes)\n",
192 normalize(&start, &stop, num), file_size());
194 dump_and_clear_stats(&stats.stats);
195 if (++stage == stopat)
198 if (transaction && tdb_transaction_start(tdb))
199 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
201 /* Missing 1000 records. */
202 printf("Missing %u records: ", num); fflush(stdout);
203 gettimeofday(&start, NULL);
204 for (i = num; i < num*2; i++) {
206 dptr = (int *)tdb_fetch(tdb, key).dptr;
208 errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
210 gettimeofday(&stop, NULL);
211 if (transaction && tdb_transaction_commit(tdb))
212 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
213 printf(" %zu ns (%zu bytes)\n",
214 normalize(&start, &stop, num), file_size());
216 dump_and_clear_stats(&stats.stats);
217 if (++stage == stopat)
220 if (transaction && tdb_transaction_start(tdb))
221 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
223 /* Traverse 1000 records. */
224 printf("Traversing %u records: ", num); fflush(stdout);
226 gettimeofday(&start, NULL);
227 if (tdb_traverse(tdb, count_record, &i) != num)
228 errx(1, "Traverse returned wrong number of records");
229 if (i != (num - 1) * (num / 2))
230 errx(1, "Traverse tallied to %u", i);
231 gettimeofday(&stop, NULL);
232 if (transaction && tdb_transaction_commit(tdb))
233 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
234 printf(" %zu ns (%zu bytes)\n",
235 normalize(&start, &stop, num), file_size());
237 dump_and_clear_stats(&stats.stats);
238 if (++stage == stopat)
241 if (transaction && tdb_transaction_start(tdb))
242 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
244 /* Delete 1000 records (not in order). */
245 printf("Deleting %u records: ", num); fflush(stdout);
246 gettimeofday(&start, NULL);
247 for (j = 0; j < num; j++) {
248 i = (j + 100003) % num;
249 if (tdb_delete(tdb, key) != 0)
250 errx(1, "Deleting key %u in tdb: %s",
251 i, tdb_errorstr(tdb));
253 gettimeofday(&stop, NULL);
254 if (transaction && tdb_transaction_commit(tdb))
255 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
256 printf(" %zu ns (%zu bytes)\n",
257 normalize(&start, &stop, num), file_size());
259 dump_and_clear_stats(&stats.stats);
260 if (++stage == stopat)
263 if (transaction && tdb_transaction_start(tdb))
264 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
266 /* Re-add 1000 records (not in order). */
267 printf("Re-adding %u records: ", num); fflush(stdout);
268 gettimeofday(&start, NULL);
269 for (j = 0; j < num; j++) {
270 i = (j + 100003) % num;
271 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
272 errx(1, "Inserting key %u in tdb: %s",
273 i, tdb_errorstr(tdb));
275 gettimeofday(&stop, NULL);
276 if (transaction && tdb_transaction_commit(tdb))
277 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
278 printf(" %zu ns (%zu bytes)\n",
279 normalize(&start, &stop, num), file_size());
281 dump_and_clear_stats(&stats.stats);
282 if (++stage == stopat)
285 if (transaction && tdb_transaction_start(tdb))
286 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
288 /* Append 1000 records. */
289 printf("Appending %u records: ", num); fflush(stdout);
290 gettimeofday(&start, NULL);
291 for (i = 0; i < num; i++)
292 if (tdb_append(tdb, key, data) != 0)
293 errx(1, "Appending key %u in tdb: %s",
294 i, tdb_errorstr(tdb));
295 gettimeofday(&stop, NULL);
296 if (transaction && tdb_transaction_commit(tdb))
297 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
298 printf(" %zu ns (%zu bytes)\n",
299 normalize(&start, &stop, num), file_size());
300 if (++stage == stopat)
303 if (transaction && tdb_transaction_start(tdb))
304 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
306 /* Churn 1000 records: not in order! */
307 printf("Churning %u records: ", num); fflush(stdout);
308 gettimeofday(&start, NULL);
309 for (j = 0; j < num; j++) {
310 i = (j + 1000019) % num;
311 if (tdb_delete(tdb, key) != 0)
312 errx(1, "Deleting key %u in tdb: %s",
313 i, tdb_errorstr(tdb));
315 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
316 errx(1, "Inserting key %u in tdb: %s",
317 i, tdb_errorstr(tdb));
319 gettimeofday(&stop, NULL);
320 if (transaction && tdb_transaction_commit(tdb))
321 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
322 printf(" %zu ns (%zu bytes)\n",
323 normalize(&start, &stop, num), file_size());
326 dump_and_clear_stats(&stats.stats);
327 if (++stage == stopat)