]> git.ozlabs.org Git - ccan/blob - ccan/tdb2/tools/speed.c
tdb2: update tools/speed.c, tools/tdbtool.c and tools/tdbtorture.c to new API
[ccan] / ccan / tdb2 / tools / speed.c
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 <ccan/tdb2/tdb2.h>
14
15 /* Nanoseconds per operation */
16 static size_t normalize(const struct timeval *start,
17                         const struct timeval *stop,
18                         unsigned int num)
19 {
20         struct timeval diff;
21
22         timersub(stop, start, &diff);
23
24         /* Floating point is more accurate here. */
25         return (double)(diff.tv_sec * 1000000 + diff.tv_usec)
26                 / num * 1000;
27 }
28
29 static size_t file_size(void)
30 {
31         struct stat st;
32
33         if (stat("/tmp/speed.tdb", &st) != 0)
34                 return -1;
35         return st.st_size;
36 }
37
38 static int count_record(struct tdb_context *tdb,
39                         TDB_DATA key, TDB_DATA data, void *p)
40 {
41         int *total = p;
42         *total += *(int *)data.dptr;
43         return 0;
44 }
45
46 static void dump_and_clear_stats(struct tdb_attribute_stats *stats)
47 {
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);
92
93         /* Now clear. */
94         memset(&stats->allocs, 0, (char *)(stats+1) - (char *)&stats->allocs);
95 }
96
97 int main(int argc, char *argv[])
98 {
99         unsigned int i, j, num = 1000, stage = 0, stopat = -1;
100         int flags = TDB_DEFAULT;
101         bool transaction = false;
102         TDB_DATA key, data;
103         struct tdb_context *tdb;
104         struct timeval start, stop;
105         union tdb_attribute seed, stats;
106         enum TDB_ERROR ecode;
107
108         /* Try to keep benchmarks even. */
109         seed.base.attr = TDB_ATTRIBUTE_SEED;
110         seed.base.next = NULL;
111         seed.seed.seed = 0;
112
113         memset(&stats, 0, sizeof(stats));
114         stats.base.attr = TDB_ATTRIBUTE_STATS;
115         stats.base.next = NULL;
116         stats.stats.size = sizeof(stats);
117
118         if (argv[1] && strcmp(argv[1], "--internal") == 0) {
119                 flags = TDB_INTERNAL;
120                 argc--;
121                 argv++;
122         }
123         if (argv[1] && strcmp(argv[1], "--transaction") == 0) {
124                 transaction = true;
125                 argc--;
126                 argv++;
127         }
128         if (argv[1] && strcmp(argv[1], "--stats") == 0) {
129                 seed.base.next = &stats;
130                 argc--;
131                 argv++;
132         }
133
134         tdb = tdb_open("/tmp/speed.tdb", flags, O_RDWR|O_CREAT|O_TRUNC,
135                        0600, &seed);
136         if (!tdb)
137                 err(1, "Opening /tmp/speed.tdb");
138
139         key.dptr = (void *)&i;
140         key.dsize = sizeof(i);
141         data = key;
142
143         if (argv[1]) {
144                 num = atoi(argv[1]);
145                 argv++;
146                 argc--;
147         }
148
149         if (argv[1]) {
150                 stopat = atoi(argv[1]);
151                 argv++;
152                 argc--;
153         }
154
155         if (transaction && (ecode = tdb_transaction_start(tdb)))
156                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
157
158         /* Add 1000 records. */
159         printf("Adding %u records: ", num); fflush(stdout);
160         gettimeofday(&start, NULL);
161         for (i = 0; i < num; i++)
162                 if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
163                         errx(1, "Inserting key %u in tdb: %s",
164                              i, tdb_errorstr(ecode));
165         gettimeofday(&stop, NULL);
166         if (transaction && (ecode = tdb_transaction_commit(tdb)))
167                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
168         printf(" %zu ns (%zu bytes)\n",
169                normalize(&start, &stop, num), file_size());
170
171         if (seed.base.next)
172                 dump_and_clear_stats(&stats.stats);
173         if (++stage == stopat)
174                 exit(0);
175
176         if (transaction && (ecode = tdb_transaction_start(tdb)))
177                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
178
179         /* Finding 1000 records. */
180         printf("Finding %u records: ", num); fflush(stdout);
181         gettimeofday(&start, NULL);
182         for (i = 0; i < num; i++) {
183                 struct tdb_data dbuf;
184                 if ((ecode = tdb_fetch(tdb, key, &dbuf)) != TDB_SUCCESS
185                     || *(int *)dbuf.dptr != i) {
186                         errx(1, "Fetching key %u in tdb gave %u",
187                              i, ecode ? ecode : *(int *)dbuf.dptr);
188                 }
189         }
190         gettimeofday(&stop, NULL);
191         if (transaction && (ecode = tdb_transaction_commit(tdb)))
192                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
193         printf(" %zu ns (%zu bytes)\n",
194                normalize(&start, &stop, num), file_size());
195         if (seed.base.next)
196                 dump_and_clear_stats(&stats.stats);
197         if (++stage == stopat)
198                 exit(0);
199
200         if (transaction && (ecode = tdb_transaction_start(tdb)))
201                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
202
203         /* Missing 1000 records. */
204         printf("Missing %u records: ", num); fflush(stdout);
205         gettimeofday(&start, NULL);
206         for (i = num; i < num*2; i++) {
207                 struct tdb_data dbuf;
208                 ecode = tdb_fetch(tdb, key, &dbuf);
209                 if (ecode != TDB_ERR_NOEXIST)
210                         errx(1, "Fetching key %u in tdb gave %s",
211                              i, tdb_errorstr(ecode));
212         }
213         gettimeofday(&stop, NULL);
214         if (transaction && (ecode = tdb_transaction_commit(tdb)))
215                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
216         printf(" %zu ns (%zu bytes)\n",
217                normalize(&start, &stop, num), file_size());
218         if (seed.base.next)
219                 dump_and_clear_stats(&stats.stats);
220         if (++stage == stopat)
221                 exit(0);
222
223         if (transaction && (ecode = tdb_transaction_start(tdb)))
224                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
225
226         /* Traverse 1000 records. */
227         printf("Traversing %u records: ", num); fflush(stdout);
228         i = 0;
229         gettimeofday(&start, NULL);
230         if (tdb_traverse(tdb, count_record, &i) != num)
231                 errx(1, "Traverse returned wrong number of records");
232         if (i != (num - 1) * (num / 2))
233                 errx(1, "Traverse tallied to %u", i);
234         gettimeofday(&stop, NULL);
235         if (transaction && (ecode = tdb_transaction_commit(tdb)))
236                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
237         printf(" %zu ns (%zu bytes)\n",
238                normalize(&start, &stop, num), file_size());
239         if (seed.base.next)
240                 dump_and_clear_stats(&stats.stats);
241         if (++stage == stopat)
242                 exit(0);
243
244         if (transaction && (ecode = tdb_transaction_start(tdb)))
245                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
246
247         /* Delete 1000 records (not in order). */
248         printf("Deleting %u records: ", num); fflush(stdout);
249         gettimeofday(&start, NULL);
250         for (j = 0; j < num; j++) {
251                 i = (j + 100003) % num;
252                 if ((ecode = tdb_delete(tdb, key)) != TDB_SUCCESS)
253                         errx(1, "Deleting key %u in tdb: %s",
254                              i, tdb_errorstr(ecode));
255         }
256         gettimeofday(&stop, NULL);
257         if (transaction && (ecode = tdb_transaction_commit(tdb)))
258                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
259         printf(" %zu ns (%zu bytes)\n",
260                normalize(&start, &stop, num), file_size());
261         if (seed.base.next)
262                 dump_and_clear_stats(&stats.stats);
263         if (++stage == stopat)
264                 exit(0);
265
266         if (transaction && (ecode = tdb_transaction_start(tdb)))
267                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
268
269         /* Re-add 1000 records (not in order). */
270         printf("Re-adding %u records: ", num); fflush(stdout);
271         gettimeofday(&start, NULL);
272         for (j = 0; j < num; j++) {
273                 i = (j + 100003) % num;
274                 if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
275                         errx(1, "Inserting key %u in tdb: %s",
276                              i, tdb_errorstr(ecode));
277         }
278         gettimeofday(&stop, NULL);
279         if (transaction && (ecode = tdb_transaction_commit(tdb)))
280                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
281         printf(" %zu ns (%zu bytes)\n",
282                normalize(&start, &stop, num), file_size());
283         if (seed.base.next)
284                 dump_and_clear_stats(&stats.stats);
285         if (++stage == stopat)
286                 exit(0);
287
288         if (transaction && (ecode = tdb_transaction_start(tdb)))
289                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
290
291         /* Append 1000 records. */
292         printf("Appending %u records: ", num); fflush(stdout);
293         gettimeofday(&start, NULL);
294         for (i = 0; i < num; i++)
295                 if ((ecode = tdb_append(tdb, key, data)) != TDB_SUCCESS)
296                         errx(1, "Appending key %u in tdb: %s",
297                              i, tdb_errorstr(ecode));
298         gettimeofday(&stop, NULL);
299         if (transaction && (ecode = tdb_transaction_commit(tdb)))
300                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
301         printf(" %zu ns (%zu bytes)\n",
302                normalize(&start, &stop, num), file_size());
303         if (++stage == stopat)
304                 exit(0);
305
306         if (transaction && (ecode = tdb_transaction_start(tdb)))
307                 errx(1, "starting transaction: %s", tdb_errorstr(ecode));
308
309         /* Churn 1000 records: not in order! */
310         printf("Churning %u records: ", num); fflush(stdout);
311         gettimeofday(&start, NULL);
312         for (j = 0; j < num; j++) {
313                 i = (j + 1000019) % num;
314                 if ((ecode = tdb_delete(tdb, key)) != TDB_SUCCESS)
315                         errx(1, "Deleting key %u in tdb: %s",
316                              i, tdb_errorstr(ecode));
317                 i += num;
318                 if ((ecode = tdb_store(tdb, key, data, TDB_INSERT)) != 0)
319                         errx(1, "Inserting key %u in tdb: %s",
320                              i, tdb_errorstr(ecode));
321         }
322         gettimeofday(&stop, NULL);
323         if (transaction && (ecode = tdb_transaction_commit(tdb)))
324                 errx(1, "committing transaction: %s", tdb_errorstr(ecode));
325         printf(" %zu ns (%zu bytes)\n",
326                normalize(&start, &stop, num), file_size());
327
328         if (seed.base.next)
329                 dump_and_clear_stats(&stats.stats);
330         if (++stage == stopat)
331                 exit(0);
332
333         return 0;
334 }