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("expands = %llu\n",
69 (unsigned long long)stats->expands);
70 printf("frees = %llu\n",
71 (unsigned long long)stats->frees);
72 printf("locks = %llu\n",
73 (unsigned long long)stats->locks);
74 printf(" lock_lowlevel = %llu\n",
75 (unsigned long long)stats->lock_lowlevel);
76 printf(" lock_nonblock = %llu\n",
77 (unsigned long long)stats->lock_nonblock);
80 memset(&stats->allocs, 0, (char *)(stats+1) - (char *)&stats->allocs);
83 int main(int argc, char *argv[])
85 unsigned int i, j, num = 1000, stage = 0, stopat = -1;
86 int flags = TDB_DEFAULT;
87 bool transaction = false;
89 struct tdb_context *tdb;
90 struct timeval start, stop;
91 union tdb_attribute seed, stats;
93 /* Try to keep benchmarks even. */
94 seed.base.attr = TDB_ATTRIBUTE_SEED;
95 seed.base.next = NULL;
98 memset(&stats, 0, sizeof(stats));
99 stats.base.attr = TDB_ATTRIBUTE_STATS;
100 stats.base.next = NULL;
101 stats.stats.size = sizeof(stats);
103 if (argv[1] && strcmp(argv[1], "--internal") == 0) {
104 flags = TDB_INTERNAL;
108 if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
113 if (argv[1] && strcmp(argv[1], "--stats") == 0) {
114 seed.base.next = &stats;
119 tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR|O_CREAT|O_TRUNC,
122 err(1, "Opening /tmp/speed.tdb");
124 key.dptr = (void *)&i;
125 key.dsize = sizeof(i);
135 stopat = atoi(argv[1]);
140 if (transaction && tdb_transaction_start(tdb))
141 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
143 /* Add 1000 records. */
144 printf("Adding %u records: ", num); fflush(stdout);
145 gettimeofday(&start, NULL);
146 for (i = 0; i < num; i++)
147 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
148 errx(1, "Inserting key %u in tdb: %s",
149 i, tdb_errorstr(tdb));
150 gettimeofday(&stop, NULL);
151 if (transaction && tdb_transaction_commit(tdb))
152 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
153 printf(" %zu ns (%zu bytes)\n",
154 normalize(&start, &stop, num), file_size());
157 dump_and_clear_stats(&stats.stats);
158 if (++stage == stopat)
161 if (transaction && tdb_transaction_start(tdb))
162 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
164 /* Finding 1000 records. */
165 printf("Finding %u records: ", num); fflush(stdout);
166 gettimeofday(&start, NULL);
167 for (i = 0; i < num; i++) {
169 dptr = (int *)tdb_fetch(tdb, key).dptr;
170 if (!dptr || *dptr != i)
171 errx(1, "Fetching key %u in tdb gave %u",
172 i, dptr ? *dptr : -1);
174 gettimeofday(&stop, NULL);
175 if (transaction && tdb_transaction_commit(tdb))
176 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
177 printf(" %zu ns (%zu bytes)\n",
178 normalize(&start, &stop, num), file_size());
180 dump_and_clear_stats(&stats.stats);
181 if (++stage == stopat)
184 if (transaction && tdb_transaction_start(tdb))
185 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
187 /* Missing 1000 records. */
188 printf("Missing %u records: ", num); fflush(stdout);
189 gettimeofday(&start, NULL);
190 for (i = num; i < num*2; i++) {
192 dptr = (int *)tdb_fetch(tdb, key).dptr;
194 errx(1, "Fetching key %u in tdb gave %u", i, *dptr);
196 gettimeofday(&stop, NULL);
197 if (transaction && tdb_transaction_commit(tdb))
198 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
199 printf(" %zu ns (%zu bytes)\n",
200 normalize(&start, &stop, num), file_size());
202 dump_and_clear_stats(&stats.stats);
203 if (++stage == stopat)
206 if (transaction && tdb_transaction_start(tdb))
207 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
209 /* Traverse 1000 records. */
210 printf("Traversing %u records: ", num); fflush(stdout);
212 gettimeofday(&start, NULL);
213 if (tdb_traverse(tdb, count_record, &i) != num)
214 errx(1, "Traverse returned wrong number of records");
215 if (i != (num - 1) * (num / 2))
216 errx(1, "Traverse tallied to %u", i);
217 gettimeofday(&stop, NULL);
218 if (transaction && tdb_transaction_commit(tdb))
219 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
220 printf(" %zu ns (%zu bytes)\n",
221 normalize(&start, &stop, num), file_size());
223 dump_and_clear_stats(&stats.stats);
224 if (++stage == stopat)
227 if (transaction && tdb_transaction_start(tdb))
228 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
230 /* Delete 1000 records (not in order). */
231 printf("Deleting %u records: ", num); fflush(stdout);
232 gettimeofday(&start, NULL);
233 for (j = 0; j < num; j++) {
234 i = (j + 100003) % num;
235 if (tdb_delete(tdb, key) != 0)
236 errx(1, "Deleting key %u in tdb: %s",
237 i, tdb_errorstr(tdb));
239 gettimeofday(&stop, NULL);
240 if (transaction && tdb_transaction_commit(tdb))
241 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
242 printf(" %zu ns (%zu bytes)\n",
243 normalize(&start, &stop, num), file_size());
245 dump_and_clear_stats(&stats.stats);
246 if (++stage == stopat)
249 if (transaction && tdb_transaction_start(tdb))
250 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
252 /* Re-add 1000 records (not in order). */
253 printf("Re-adding %u records: ", num); fflush(stdout);
254 gettimeofday(&start, NULL);
255 for (j = 0; j < num; j++) {
256 i = (j + 100003) % num;
257 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
258 errx(1, "Inserting key %u in tdb: %s",
259 i, tdb_errorstr(tdb));
261 gettimeofday(&stop, NULL);
262 if (transaction && tdb_transaction_commit(tdb))
263 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
264 printf(" %zu ns (%zu bytes)\n",
265 normalize(&start, &stop, num), file_size());
267 dump_and_clear_stats(&stats.stats);
268 if (++stage == stopat)
271 if (transaction && tdb_transaction_start(tdb))
272 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
274 /* Append 1000 records. */
275 printf("Appending %u records: ", num); fflush(stdout);
276 gettimeofday(&start, NULL);
277 for (i = 0; i < num; i++)
278 if (tdb_append(tdb, key, data) != 0)
279 errx(1, "Appending key %u in tdb: %s",
280 i, tdb_errorstr(tdb));
281 gettimeofday(&stop, NULL);
282 if (transaction && tdb_transaction_commit(tdb))
283 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
284 printf(" %zu ns (%zu bytes)\n",
285 normalize(&start, &stop, num), file_size());
286 if (++stage == stopat)
289 if (transaction && tdb_transaction_start(tdb))
290 errx(1, "starting transaction: %s", tdb_errorstr(tdb));
292 /* Churn 1000 records: not in order! */
293 printf("Churning %u records: ", num); fflush(stdout);
294 gettimeofday(&start, NULL);
295 for (j = 0; j < num; j++) {
296 i = (j + 1000019) % num;
297 if (tdb_delete(tdb, key) != 0)
298 errx(1, "Deleting key %u in tdb: %s",
299 i, tdb_errorstr(tdb));
301 if (tdb_store(tdb, key, data, TDB_INSERT) != 0)
302 errx(1, "Inserting key %u in tdb: %s",
303 i, tdb_errorstr(tdb));
305 gettimeofday(&stop, NULL);
306 if (transaction && tdb_transaction_commit(tdb))
307 errx(1, "committing transaction: %s", tdb_errorstr(tdb));
308 printf(" %zu ns (%zu bytes)\n",
309 normalize(&start, &stop, num), file_size());
312 dump_and_clear_stats(&stats.stats);
313 if (++stage == stopat)