]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/tests.c
Update bcachefs sources to 6c5219caf0 bcachefs: Rev the on disk format version for...
[bcachefs-tools-debian] / libbcachefs / tests.c
1 // SPDX-License-Identifier: GPL-2.0
2 #ifdef CONFIG_BCACHEFS_TESTS
3
4 #include "bcachefs.h"
5 #include "btree_update.h"
6 #include "journal_reclaim.h"
7 #include "tests.h"
8
9 #include "linux/kthread.h"
10 #include "linux/random.h"
11
12 static void delete_test_keys(struct bch_fs *c)
13 {
14         int ret;
15
16         ret = bch2_btree_delete_range(c, BTREE_ID_extents,
17                                       POS(0, 0), POS(0, U64_MAX),
18                                       NULL);
19         BUG_ON(ret);
20
21         ret = bch2_btree_delete_range(c, BTREE_ID_xattrs,
22                                       POS(0, 0), POS(0, U64_MAX),
23                                       NULL);
24         BUG_ON(ret);
25 }
26
27 /* unit tests */
28
29 static int test_delete(struct bch_fs *c, u64 nr)
30 {
31         struct btree_trans trans;
32         struct btree_iter iter;
33         struct bkey_i_cookie k;
34         int ret;
35
36         bkey_cookie_init(&k.k_i);
37         k.k.p.snapshot = U32_MAX;
38
39         bch2_trans_init(&trans, c, 0, 0);
40         bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs, k.k.p,
41                              BTREE_ITER_INTENT);
42
43         ret = __bch2_trans_do(&trans, NULL, NULL, 0,
44                 bch2_btree_iter_traverse(&iter) ?:
45                 bch2_trans_update(&trans, &iter, &k.k_i, 0));
46         if (ret) {
47                 bch_err(c, "update error in test_delete: %i", ret);
48                 goto err;
49         }
50
51         pr_info("deleting once");
52         ret = __bch2_trans_do(&trans, NULL, NULL, 0,
53                 bch2_btree_iter_traverse(&iter) ?:
54                 bch2_btree_delete_at(&trans, &iter, 0));
55         if (ret) {
56                 bch_err(c, "delete error (first) in test_delete: %i", ret);
57                 goto err;
58         }
59
60         pr_info("deleting twice");
61         ret = __bch2_trans_do(&trans, NULL, NULL, 0,
62                 bch2_btree_iter_traverse(&iter) ?:
63                 bch2_btree_delete_at(&trans, &iter, 0));
64         if (ret) {
65                 bch_err(c, "delete error (second) in test_delete: %i", ret);
66                 goto err;
67         }
68 err:
69         bch2_trans_iter_exit(&trans, &iter);
70         bch2_trans_exit(&trans);
71         return ret;
72 }
73
74 static int test_delete_written(struct bch_fs *c, u64 nr)
75 {
76         struct btree_trans trans;
77         struct btree_iter iter;
78         struct bkey_i_cookie k;
79         int ret;
80
81         bkey_cookie_init(&k.k_i);
82         k.k.p.snapshot = U32_MAX;
83
84         bch2_trans_init(&trans, c, 0, 0);
85
86         bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs, k.k.p,
87                              BTREE_ITER_INTENT);
88
89         ret = __bch2_trans_do(&trans, NULL, NULL, 0,
90                 bch2_btree_iter_traverse(&iter) ?:
91                 bch2_trans_update(&trans, &iter, &k.k_i, 0));
92         if (ret) {
93                 bch_err(c, "update error in test_delete_written: %i", ret);
94                 goto err;
95         }
96
97         bch2_trans_unlock(&trans);
98         bch2_journal_flush_all_pins(&c->journal);
99
100         ret = __bch2_trans_do(&trans, NULL, NULL, 0,
101                 bch2_btree_iter_traverse(&iter) ?:
102                 bch2_btree_delete_at(&trans, &iter, 0));
103         if (ret) {
104                 bch_err(c, "delete error in test_delete_written: %i", ret);
105                 goto err;
106         }
107 err:
108         bch2_trans_iter_exit(&trans, &iter);
109         bch2_trans_exit(&trans);
110         return ret;
111 }
112
113 static int test_iterate(struct bch_fs *c, u64 nr)
114 {
115         struct btree_trans trans;
116         struct btree_iter iter = { NULL };
117         struct bkey_s_c k;
118         u64 i;
119         int ret = 0;
120
121         bch2_trans_init(&trans, c, 0, 0);
122
123         delete_test_keys(c);
124
125         pr_info("inserting test keys");
126
127         for (i = 0; i < nr; i++) {
128                 struct bkey_i_cookie k;
129
130                 bkey_cookie_init(&k.k_i);
131                 k.k.p.offset = i;
132                 k.k.p.snapshot = U32_MAX;
133
134                 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &k.k_i,
135                                         NULL, NULL, 0);
136                 if (ret) {
137                         bch_err(c, "insert error in test_iterate: %i", ret);
138                         goto err;
139                 }
140         }
141
142         pr_info("iterating forwards");
143
144         i = 0;
145
146         for_each_btree_key(&trans, iter, BTREE_ID_xattrs,
147                            POS_MIN, 0, k, ret) {
148                 if (k.k->p.inode)
149                         break;
150
151                 BUG_ON(k.k->p.offset != i++);
152         }
153
154         BUG_ON(i != nr);
155
156         pr_info("iterating backwards");
157
158         while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(&iter)).k))
159                 BUG_ON(k.k->p.offset != --i);
160
161         BUG_ON(i);
162 err:
163         bch2_trans_iter_exit(&trans, &iter);
164         bch2_trans_exit(&trans);
165         return ret;
166 }
167
168 static int test_iterate_extents(struct bch_fs *c, u64 nr)
169 {
170         struct btree_trans trans;
171         struct btree_iter iter = { NULL };
172         struct bkey_s_c k;
173         u64 i;
174         int ret = 0;
175
176         bch2_trans_init(&trans, c, 0, 0);
177
178         delete_test_keys(c);
179
180         pr_info("inserting test extents");
181
182         for (i = 0; i < nr; i += 8) {
183                 struct bkey_i_cookie k;
184
185                 bkey_cookie_init(&k.k_i);
186                 k.k.p.offset = i + 8;
187                 k.k.p.snapshot = U32_MAX;
188                 k.k.size = 8;
189
190                 ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
191                                         NULL, NULL, 0);
192                 if (ret) {
193                         bch_err(c, "insert error in test_iterate_extents: %i", ret);
194                         goto err;
195                 }
196         }
197
198         pr_info("iterating forwards");
199
200         i = 0;
201
202         for_each_btree_key(&trans, iter, BTREE_ID_extents,
203                            POS_MIN, 0, k, ret) {
204                 BUG_ON(bkey_start_offset(k.k) != i);
205                 i = k.k->p.offset;
206         }
207
208         BUG_ON(i != nr);
209
210         pr_info("iterating backwards");
211
212         while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(&iter)).k)) {
213                 BUG_ON(k.k->p.offset != i);
214                 i = bkey_start_offset(k.k);
215         }
216
217         BUG_ON(i);
218 err:
219         bch2_trans_iter_exit(&trans, &iter);
220         bch2_trans_exit(&trans);
221         return ret;
222 }
223
224 static int test_iterate_slots(struct bch_fs *c, u64 nr)
225 {
226         struct btree_trans trans;
227         struct btree_iter iter = { NULL };
228         struct bkey_s_c k;
229         u64 i;
230         int ret = 0;
231
232         bch2_trans_init(&trans, c, 0, 0);
233
234         delete_test_keys(c);
235
236         pr_info("inserting test keys");
237
238         for (i = 0; i < nr; i++) {
239                 struct bkey_i_cookie k;
240
241                 bkey_cookie_init(&k.k_i);
242                 k.k.p.offset = i * 2;
243                 k.k.p.snapshot = U32_MAX;
244
245                 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &k.k_i,
246                                         NULL, NULL, 0);
247                 if (ret) {
248                         bch_err(c, "insert error in test_iterate_slots: %i", ret);
249                         goto err;
250                 }
251         }
252
253         pr_info("iterating forwards");
254
255         i = 0;
256
257         for_each_btree_key(&trans, iter, BTREE_ID_xattrs, POS_MIN,
258                            0, k, ret) {
259                 if (k.k->p.inode)
260                         break;
261
262                 BUG_ON(k.k->p.offset != i);
263                 i += 2;
264         }
265         bch2_trans_iter_exit(&trans, &iter);
266
267         BUG_ON(i != nr * 2);
268
269         pr_info("iterating forwards by slots");
270
271         i = 0;
272
273         for_each_btree_key(&trans, iter, BTREE_ID_xattrs, POS_MIN,
274                            BTREE_ITER_SLOTS, k, ret) {
275                 BUG_ON(k.k->p.offset != i);
276                 BUG_ON(bkey_deleted(k.k) != (i & 1));
277
278                 i++;
279                 if (i == nr * 2)
280                         break;
281         }
282         bch2_trans_iter_exit(&trans, &iter);
283 err:
284         bch2_trans_exit(&trans);
285         return ret;
286 }
287
288 static int test_iterate_slots_extents(struct bch_fs *c, u64 nr)
289 {
290         struct btree_trans trans;
291         struct btree_iter iter = { NULL };
292         struct bkey_s_c k;
293         u64 i;
294         int ret = 0;
295
296         bch2_trans_init(&trans, c, 0, 0);
297
298         delete_test_keys(c);
299
300         pr_info("inserting test keys");
301
302         for (i = 0; i < nr; i += 16) {
303                 struct bkey_i_cookie k;
304
305                 bkey_cookie_init(&k.k_i);
306                 k.k.p.offset = i + 16;
307                 k.k.p.snapshot = U32_MAX;
308                 k.k.size = 8;
309
310                 ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
311                                         NULL, NULL, 0);
312                 if (ret) {
313                         bch_err(c, "insert error in test_iterate_slots_extents: %i", ret);
314                         goto err;
315                 }
316         }
317
318         pr_info("iterating forwards");
319
320         i = 0;
321
322         for_each_btree_key(&trans, iter, BTREE_ID_extents, POS_MIN,
323                            0, k, ret) {
324                 BUG_ON(bkey_start_offset(k.k) != i + 8);
325                 BUG_ON(k.k->size != 8);
326                 i += 16;
327         }
328         bch2_trans_iter_exit(&trans, &iter);
329
330         BUG_ON(i != nr);
331
332         pr_info("iterating forwards by slots");
333
334         i = 0;
335
336         for_each_btree_key(&trans, iter, BTREE_ID_extents, POS_MIN,
337                            BTREE_ITER_SLOTS, k, ret) {
338                 BUG_ON(bkey_deleted(k.k) != !(i % 16));
339
340                 BUG_ON(bkey_start_offset(k.k) != i);
341                 BUG_ON(k.k->size != 8);
342                 i = k.k->p.offset;
343
344                 if (i == nr)
345                         break;
346         }
347         bch2_trans_iter_exit(&trans, &iter);
348 err:
349         bch2_trans_exit(&trans);
350         return 0;
351 }
352
353 /*
354  * XXX: we really want to make sure we've got a btree with depth > 0 for these
355  * tests
356  */
357 static int test_peek_end(struct bch_fs *c, u64 nr)
358 {
359         struct btree_trans trans;
360         struct btree_iter iter;
361         struct bkey_s_c k;
362
363         bch2_trans_init(&trans, c, 0, 0);
364         bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs, POS_MIN, 0);
365
366         k = bch2_btree_iter_peek(&iter);
367         BUG_ON(k.k);
368
369         k = bch2_btree_iter_peek(&iter);
370         BUG_ON(k.k);
371
372         bch2_trans_iter_exit(&trans, &iter);
373         bch2_trans_exit(&trans);
374         return 0;
375 }
376
377 static int test_peek_end_extents(struct bch_fs *c, u64 nr)
378 {
379         struct btree_trans trans;
380         struct btree_iter iter;
381         struct bkey_s_c k;
382
383         bch2_trans_init(&trans, c, 0, 0);
384         bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents, POS_MIN, 0);
385
386         k = bch2_btree_iter_peek(&iter);
387         BUG_ON(k.k);
388
389         k = bch2_btree_iter_peek(&iter);
390         BUG_ON(k.k);
391
392         bch2_trans_iter_exit(&trans, &iter);
393         bch2_trans_exit(&trans);
394         return 0;
395 }
396
397 /* extent unit tests */
398
399 u64 test_version;
400
401 static int insert_test_extent(struct bch_fs *c,
402                               u64 start, u64 end)
403 {
404         struct bkey_i_cookie k;
405         int ret;
406
407         //pr_info("inserting %llu-%llu v %llu", start, end, test_version);
408
409         bkey_cookie_init(&k.k_i);
410         k.k_i.k.p.offset = end;
411         k.k_i.k.p.snapshot = U32_MAX;
412         k.k_i.k.size = end - start;
413         k.k_i.k.version.lo = test_version++;
414
415         ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i,
416                                 NULL, NULL, 0);
417         if (ret)
418                 bch_err(c, "insert error in insert_test_extent: %i", ret);
419         return ret;
420 }
421
422 static int __test_extent_overwrite(struct bch_fs *c,
423                                     u64 e1_start, u64 e1_end,
424                                     u64 e2_start, u64 e2_end)
425 {
426         int ret;
427
428         ret   = insert_test_extent(c, e1_start, e1_end) ?:
429                 insert_test_extent(c, e2_start, e2_end);
430
431         delete_test_keys(c);
432         return ret;
433 }
434
435 static int test_extent_overwrite_front(struct bch_fs *c, u64 nr)
436 {
437         return  __test_extent_overwrite(c, 0, 64, 0, 32) ?:
438                 __test_extent_overwrite(c, 8, 64, 0, 32);
439 }
440
441 static int test_extent_overwrite_back(struct bch_fs *c, u64 nr)
442 {
443         return  __test_extent_overwrite(c, 0, 64, 32, 64) ?:
444                 __test_extent_overwrite(c, 0, 64, 32, 72);
445 }
446
447 static int test_extent_overwrite_middle(struct bch_fs *c, u64 nr)
448 {
449         return __test_extent_overwrite(c, 0, 64, 32, 40);
450 }
451
452 static int test_extent_overwrite_all(struct bch_fs *c, u64 nr)
453 {
454         return  __test_extent_overwrite(c, 32, 64,  0,  64) ?:
455                 __test_extent_overwrite(c, 32, 64,  0, 128) ?:
456                 __test_extent_overwrite(c, 32, 64, 32,  64) ?:
457                 __test_extent_overwrite(c, 32, 64, 32, 128);
458 }
459
460 /* perf tests */
461
462 static u64 test_rand(void)
463 {
464         u64 v;
465 #if 0
466         v = prandom_u32();
467 #else
468         prandom_bytes(&v, sizeof(v));
469 #endif
470         return v;
471 }
472
473 static int rand_insert(struct bch_fs *c, u64 nr)
474 {
475         struct btree_trans trans;
476         struct bkey_i_cookie k;
477         int ret = 0;
478         u64 i;
479
480         bch2_trans_init(&trans, c, 0, 0);
481
482         for (i = 0; i < nr; i++) {
483                 bkey_cookie_init(&k.k_i);
484                 k.k.p.offset = test_rand();
485                 k.k.p.snapshot = U32_MAX;
486
487                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
488                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k.k_i));
489                 if (ret) {
490                         bch_err(c, "error in rand_insert: %i", ret);
491                         break;
492                 }
493         }
494
495         bch2_trans_exit(&trans);
496         return ret;
497 }
498
499 static int rand_insert_multi(struct bch_fs *c, u64 nr)
500 {
501         struct btree_trans trans;
502         struct bkey_i_cookie k[8];
503         int ret = 0;
504         unsigned j;
505         u64 i;
506
507         bch2_trans_init(&trans, c, 0, 0);
508
509         for (i = 0; i < nr; i += ARRAY_SIZE(k)) {
510                 for (j = 0; j < ARRAY_SIZE(k); j++) {
511                         bkey_cookie_init(&k[j].k_i);
512                         k[j].k.p.offset = test_rand();
513                         k[j].k.p.snapshot = U32_MAX;
514                 }
515
516                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
517                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[0].k_i) ?:
518                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[1].k_i) ?:
519                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[2].k_i) ?:
520                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[3].k_i) ?:
521                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[4].k_i) ?:
522                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[5].k_i) ?:
523                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[6].k_i) ?:
524                         __bch2_btree_insert(&trans, BTREE_ID_xattrs, &k[7].k_i));
525                 if (ret) {
526                         bch_err(c, "error in rand_insert_multi: %i", ret);
527                         break;
528                 }
529         }
530
531         bch2_trans_exit(&trans);
532         return ret;
533 }
534
535 static int rand_lookup(struct bch_fs *c, u64 nr)
536 {
537         struct btree_trans trans;
538         struct btree_iter iter;
539         struct bkey_s_c k;
540         int ret = 0;
541         u64 i;
542
543         bch2_trans_init(&trans, c, 0, 0);
544         bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs, POS_MIN, 0);
545
546         for (i = 0; i < nr; i++) {
547                 bch2_btree_iter_set_pos(&iter, POS(0, test_rand()));
548
549                 k = bch2_btree_iter_peek(&iter);
550                 ret = bkey_err(k);
551                 if (ret) {
552                         bch_err(c, "error in rand_lookup: %i", ret);
553                         break;
554                 }
555         }
556
557         bch2_trans_iter_exit(&trans, &iter);
558         bch2_trans_exit(&trans);
559         return ret;
560 }
561
562 static int rand_mixed_trans(struct btree_trans *trans,
563                             struct btree_iter *iter,
564                             struct bkey_i_cookie *cookie,
565                             u64 i, u64 pos)
566 {
567         struct bkey_s_c k;
568         int ret;
569
570         bch2_btree_iter_set_pos(iter, POS(0, pos));
571
572         k = bch2_btree_iter_peek(iter);
573         ret = bkey_err(k);
574         if (ret && ret != -EINTR)
575                 bch_err(trans->c, "lookup error in rand_mixed: %i", ret);
576         if (ret)
577                 return ret;
578
579         if (!(i & 3) && k.k) {
580                 bkey_cookie_init(&cookie->k_i);
581                 cookie->k.p = iter->pos;
582                 bch2_trans_update(trans, iter, &cookie->k_i, 0);
583         }
584
585         return 0;
586 }
587
588 static int rand_mixed(struct bch_fs *c, u64 nr)
589 {
590         struct btree_trans trans;
591         struct btree_iter iter;
592         struct bkey_i_cookie cookie;
593         int ret = 0;
594         u64 i, rand;
595
596         bch2_trans_init(&trans, c, 0, 0);
597         bch2_trans_iter_init(&trans, &iter, BTREE_ID_xattrs, POS_MIN, 0);
598
599         for (i = 0; i < nr; i++) {
600                 rand = test_rand();
601                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
602                         rand_mixed_trans(&trans, &iter, &cookie, i, rand));
603                 if (ret) {
604                         bch_err(c, "update error in rand_mixed: %i", ret);
605                         break;
606                 }
607         }
608
609         bch2_trans_iter_exit(&trans, &iter);
610         bch2_trans_exit(&trans);
611         return ret;
612 }
613
614 static int __do_delete(struct btree_trans *trans, struct bpos pos)
615 {
616         struct btree_iter iter;
617         struct bkey_i delete;
618         struct bkey_s_c k;
619         int ret = 0;
620
621         bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs, pos,
622                              BTREE_ITER_INTENT);
623         k = bch2_btree_iter_peek(&iter);
624         ret = bkey_err(k);
625         if (ret)
626                 goto err;
627
628         if (!k.k)
629                 goto err;
630
631         bkey_init(&delete.k);
632         delete.k.p = k.k->p;
633
634         ret = bch2_trans_update(trans, &iter, &delete, 0);
635 err:
636         bch2_trans_iter_exit(trans, &iter);
637         return ret;
638 }
639
640 static int rand_delete(struct bch_fs *c, u64 nr)
641 {
642         struct btree_trans trans;
643         int ret = 0;
644         u64 i;
645
646         bch2_trans_init(&trans, c, 0, 0);
647
648         for (i = 0; i < nr; i++) {
649                 struct bpos pos = POS(0, test_rand());
650
651                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
652                         __do_delete(&trans, pos));
653                 if (ret) {
654                         bch_err(c, "error in rand_delete: %i", ret);
655                         break;
656                 }
657         }
658
659         bch2_trans_exit(&trans);
660         return ret;
661 }
662
663 static int seq_insert(struct bch_fs *c, u64 nr)
664 {
665         struct btree_trans trans;
666         struct btree_iter iter;
667         struct bkey_s_c k;
668         struct bkey_i_cookie insert;
669         int ret = 0;
670         u64 i = 0;
671
672         bkey_cookie_init(&insert.k_i);
673
674         bch2_trans_init(&trans, c, 0, 0);
675
676         for_each_btree_key(&trans, iter, BTREE_ID_xattrs, POS_MIN,
677                            BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
678                 insert.k.p = iter.pos;
679
680                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
681                         bch2_btree_iter_traverse(&iter) ?:
682                         bch2_trans_update(&trans, &iter, &insert.k_i, 0));
683                 if (ret) {
684                         bch_err(c, "error in seq_insert: %i", ret);
685                         break;
686                 }
687
688                 if (++i == nr)
689                         break;
690         }
691         bch2_trans_iter_exit(&trans, &iter);
692
693         bch2_trans_exit(&trans);
694         return ret;
695 }
696
697 static int seq_lookup(struct bch_fs *c, u64 nr)
698 {
699         struct btree_trans trans;
700         struct btree_iter iter;
701         struct bkey_s_c k;
702         int ret = 0;
703
704         bch2_trans_init(&trans, c, 0, 0);
705
706         for_each_btree_key(&trans, iter, BTREE_ID_xattrs, POS_MIN, 0, k, ret)
707                 ;
708         bch2_trans_iter_exit(&trans, &iter);
709
710         bch2_trans_exit(&trans);
711         return ret;
712 }
713
714 static int seq_overwrite(struct bch_fs *c, u64 nr)
715 {
716         struct btree_trans trans;
717         struct btree_iter iter;
718         struct bkey_s_c k;
719         int ret = 0;
720
721         bch2_trans_init(&trans, c, 0, 0);
722
723         for_each_btree_key(&trans, iter, BTREE_ID_xattrs, POS_MIN,
724                            BTREE_ITER_INTENT, k, ret) {
725                 struct bkey_i_cookie u;
726
727                 bkey_reassemble(&u.k_i, k);
728
729                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
730                         bch2_btree_iter_traverse(&iter) ?:
731                         bch2_trans_update(&trans, &iter, &u.k_i, 0));
732                 if (ret) {
733                         bch_err(c, "error in seq_overwrite: %i", ret);
734                         break;
735                 }
736         }
737         bch2_trans_iter_exit(&trans, &iter);
738
739         bch2_trans_exit(&trans);
740         return ret;
741 }
742
743 static int seq_delete(struct bch_fs *c, u64 nr)
744 {
745         int ret;
746
747         ret = bch2_btree_delete_range(c, BTREE_ID_xattrs,
748                                       POS(0, 0), POS(0, U64_MAX),
749                                       NULL);
750         if (ret)
751                 bch_err(c, "error in seq_delete: %i", ret);
752         return ret;
753 }
754
755 typedef int (*perf_test_fn)(struct bch_fs *, u64);
756
757 struct test_job {
758         struct bch_fs                   *c;
759         u64                             nr;
760         unsigned                        nr_threads;
761         perf_test_fn                    fn;
762
763         atomic_t                        ready;
764         wait_queue_head_t               ready_wait;
765
766         atomic_t                        done;
767         struct completion               done_completion;
768
769         u64                             start;
770         u64                             finish;
771         int                             ret;
772 };
773
774 static int btree_perf_test_thread(void *data)
775 {
776         struct test_job *j = data;
777         int ret;
778
779         if (atomic_dec_and_test(&j->ready)) {
780                 wake_up(&j->ready_wait);
781                 j->start = sched_clock();
782         } else {
783                 wait_event(j->ready_wait, !atomic_read(&j->ready));
784         }
785
786         ret = j->fn(j->c, div64_u64(j->nr, j->nr_threads));
787         if (ret)
788                 j->ret = ret;
789
790         if (atomic_dec_and_test(&j->done)) {
791                 j->finish = sched_clock();
792                 complete(&j->done_completion);
793         }
794
795         return 0;
796 }
797
798 int bch2_btree_perf_test(struct bch_fs *c, const char *testname,
799                          u64 nr, unsigned nr_threads)
800 {
801         struct test_job j = { .c = c, .nr = nr, .nr_threads = nr_threads };
802         char name_buf[20], nr_buf[20], per_sec_buf[20];
803         unsigned i;
804         u64 time;
805
806         atomic_set(&j.ready, nr_threads);
807         init_waitqueue_head(&j.ready_wait);
808
809         atomic_set(&j.done, nr_threads);
810         init_completion(&j.done_completion);
811
812 #define perf_test(_test)                                \
813         if (!strcmp(testname, #_test)) j.fn = _test
814
815         perf_test(rand_insert);
816         perf_test(rand_insert_multi);
817         perf_test(rand_lookup);
818         perf_test(rand_mixed);
819         perf_test(rand_delete);
820
821         perf_test(seq_insert);
822         perf_test(seq_lookup);
823         perf_test(seq_overwrite);
824         perf_test(seq_delete);
825
826         /* a unit test, not a perf test: */
827         perf_test(test_delete);
828         perf_test(test_delete_written);
829         perf_test(test_iterate);
830         perf_test(test_iterate_extents);
831         perf_test(test_iterate_slots);
832         perf_test(test_iterate_slots_extents);
833         perf_test(test_peek_end);
834         perf_test(test_peek_end_extents);
835
836         perf_test(test_extent_overwrite_front);
837         perf_test(test_extent_overwrite_back);
838         perf_test(test_extent_overwrite_middle);
839         perf_test(test_extent_overwrite_all);
840
841         if (!j.fn) {
842                 pr_err("unknown test %s", testname);
843                 return -EINVAL;
844         }
845
846         //pr_info("running test %s:", testname);
847
848         if (nr_threads == 1)
849                 btree_perf_test_thread(&j);
850         else
851                 for (i = 0; i < nr_threads; i++)
852                         kthread_run(btree_perf_test_thread, &j,
853                                     "bcachefs perf test[%u]", i);
854
855         while (wait_for_completion_interruptible(&j.done_completion))
856                 ;
857
858         time = j.finish - j.start;
859
860         scnprintf(name_buf, sizeof(name_buf), "%s:", testname);
861         bch2_hprint(&PBUF(nr_buf), nr);
862         bch2_hprint(&PBUF(per_sec_buf), div64_u64(nr * NSEC_PER_SEC, time));
863         printk(KERN_INFO "%-12s %s with %u threads in %5llu sec, %5llu nsec per iter, %5s per sec\n",
864                 name_buf, nr_buf, nr_threads,
865                 div_u64(time, NSEC_PER_SEC),
866                 div_u64(time * nr_threads, nr),
867                 per_sec_buf);
868         return j.ret;
869 }
870
871 #endif /* CONFIG_BCACHEFS_TESTS */