]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/tests.c
Update bcachefs sources to b91a514413 bcachefs: Don't try to delete stripes when RO
[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_DIRENTS,
22                                       POS(0, 0), POS(0, U64_MAX),
23                                       NULL);
24         BUG_ON(ret);
25 }
26
27 /* unit tests */
28
29 static void 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
38         bch2_trans_init(&trans, c, 0, 0);
39
40         iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS, k.k.p,
41                                    BTREE_ITER_INTENT);
42
43         ret = bch2_btree_iter_traverse(iter);
44         BUG_ON(ret);
45
46         bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &k.k_i));
47         ret = bch2_trans_commit(&trans, NULL, NULL, 0);
48         BUG_ON(ret);
49
50         pr_info("deleting once");
51         ret = bch2_btree_delete_at(&trans, iter, 0);
52         BUG_ON(ret);
53
54         pr_info("deleting twice");
55         ret = bch2_btree_delete_at(&trans, iter, 0);
56         BUG_ON(ret);
57
58         bch2_trans_exit(&trans);
59 }
60
61 static void test_delete_written(struct bch_fs *c, u64 nr)
62 {
63         struct btree_trans trans;
64         struct btree_iter *iter;
65         struct bkey_i_cookie k;
66         int ret;
67
68         bkey_cookie_init(&k.k_i);
69
70         bch2_trans_init(&trans, c, 0, 0);
71
72         iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS, k.k.p,
73                                    BTREE_ITER_INTENT);
74
75         ret = bch2_btree_iter_traverse(iter);
76         BUG_ON(ret);
77
78         bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &k.k_i));
79         ret = bch2_trans_commit(&trans, NULL, NULL, 0);
80         BUG_ON(ret);
81
82         bch2_journal_flush_all_pins(&c->journal);
83
84         ret = bch2_btree_delete_at(&trans, iter, 0);
85         BUG_ON(ret);
86
87         bch2_trans_exit(&trans);
88 }
89
90 static void test_iterate(struct bch_fs *c, u64 nr)
91 {
92         struct btree_trans trans;
93         struct btree_iter *iter;
94         struct bkey_s_c k;
95         u64 i;
96         int ret;
97
98         bch2_trans_init(&trans, c, 0, 0);
99
100         delete_test_keys(c);
101
102         pr_info("inserting test keys");
103
104         for (i = 0; i < nr; i++) {
105                 struct bkey_i_cookie k;
106
107                 bkey_cookie_init(&k.k_i);
108                 k.k.p.offset = i;
109
110                 ret = bch2_btree_insert(c, BTREE_ID_DIRENTS, &k.k_i,
111                                         NULL, NULL, 0);
112                 BUG_ON(ret);
113         }
114
115         pr_info("iterating forwards");
116
117         i = 0;
118
119         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS,
120                            POS_MIN, 0, k, ret)
121                 BUG_ON(k.k->p.offset != i++);
122
123         BUG_ON(i != nr);
124
125         pr_info("iterating backwards");
126
127         while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(iter)).k))
128                 BUG_ON(k.k->p.offset != --i);
129
130         BUG_ON(i);
131
132         bch2_trans_exit(&trans);
133 }
134
135 static void test_iterate_extents(struct bch_fs *c, u64 nr)
136 {
137         struct btree_trans trans;
138         struct btree_iter *iter;
139         struct bkey_s_c k;
140         u64 i;
141         int ret;
142
143         bch2_trans_init(&trans, c, 0, 0);
144
145         delete_test_keys(c);
146
147         pr_info("inserting test extents");
148
149         for (i = 0; i < nr; i += 8) {
150                 struct bkey_i_cookie k;
151
152                 bkey_cookie_init(&k.k_i);
153                 k.k.p.offset = i + 8;
154                 k.k.size = 8;
155
156                 ret = bch2_btree_insert(c, BTREE_ID_EXTENTS, &k.k_i,
157                                         NULL, NULL, 0);
158                 BUG_ON(ret);
159         }
160
161         pr_info("iterating forwards");
162
163         i = 0;
164
165         for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS,
166                            POS_MIN, 0, k, ret) {
167                 BUG_ON(bkey_start_offset(k.k) != i);
168                 i = k.k->p.offset;
169         }
170
171         BUG_ON(i != nr);
172
173         pr_info("iterating backwards");
174
175         while (!IS_ERR_OR_NULL((k = bch2_btree_iter_prev(iter)).k)) {
176                 BUG_ON(k.k->p.offset != i);
177                 i = bkey_start_offset(k.k);
178         }
179
180         BUG_ON(i);
181
182         bch2_trans_exit(&trans);
183 }
184
185 static void test_iterate_slots(struct bch_fs *c, u64 nr)
186 {
187         struct btree_trans trans;
188         struct btree_iter *iter;
189         struct bkey_s_c k;
190         u64 i;
191         int ret;
192
193         bch2_trans_init(&trans, c, 0, 0);
194
195         delete_test_keys(c);
196
197         pr_info("inserting test keys");
198
199         for (i = 0; i < nr; i++) {
200                 struct bkey_i_cookie k;
201
202                 bkey_cookie_init(&k.k_i);
203                 k.k.p.offset = i * 2;
204
205                 ret = bch2_btree_insert(c, BTREE_ID_DIRENTS, &k.k_i,
206                                         NULL, NULL, 0);
207                 BUG_ON(ret);
208         }
209
210         pr_info("iterating forwards");
211
212         i = 0;
213
214         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
215                            0, k, ret) {
216                 BUG_ON(k.k->p.offset != i);
217                 i += 2;
218         }
219         bch2_trans_iter_free(&trans, iter);
220
221         BUG_ON(i != nr * 2);
222
223         pr_info("iterating forwards by slots");
224
225         i = 0;
226
227         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
228                            BTREE_ITER_SLOTS, k, ret) {
229                 BUG_ON(bkey_deleted(k.k) != (i & 1));
230                 BUG_ON(k.k->p.offset != i++);
231
232                 if (i == nr * 2)
233                         break;
234         }
235
236         bch2_trans_exit(&trans);
237 }
238
239 static void test_iterate_slots_extents(struct bch_fs *c, u64 nr)
240 {
241         struct btree_trans trans;
242         struct btree_iter *iter;
243         struct bkey_s_c k;
244         u64 i;
245         int ret;
246
247         bch2_trans_init(&trans, c, 0, 0);
248
249         delete_test_keys(c);
250
251         pr_info("inserting test keys");
252
253         for (i = 0; i < nr; i += 16) {
254                 struct bkey_i_cookie k;
255
256                 bkey_cookie_init(&k.k_i);
257                 k.k.p.offset = i + 16;
258                 k.k.size = 8;
259
260                 ret = bch2_btree_insert(c, BTREE_ID_EXTENTS, &k.k_i,
261                                         NULL, NULL, 0);
262                 BUG_ON(ret);
263         }
264
265         pr_info("iterating forwards");
266
267         i = 0;
268
269         for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN,
270                            0, k, ret) {
271                 BUG_ON(bkey_start_offset(k.k) != i + 8);
272                 BUG_ON(k.k->size != 8);
273                 i += 16;
274         }
275         bch2_trans_iter_free(&trans, iter);
276
277         BUG_ON(i != nr);
278
279         pr_info("iterating forwards by slots");
280
281         i = 0;
282
283         for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, POS_MIN,
284                            BTREE_ITER_SLOTS, k, ret) {
285                 BUG_ON(bkey_deleted(k.k) != !(i % 16));
286
287                 BUG_ON(bkey_start_offset(k.k) != i);
288                 BUG_ON(k.k->size != 8);
289                 i = k.k->p.offset;
290
291                 if (i == nr)
292                         break;
293         }
294
295         bch2_trans_exit(&trans);
296 }
297
298 /*
299  * XXX: we really want to make sure we've got a btree with depth > 0 for these
300  * tests
301  */
302 static void test_peek_end(struct bch_fs *c, u64 nr)
303 {
304         struct btree_trans trans;
305         struct btree_iter *iter;
306         struct bkey_s_c k;
307
308         bch2_trans_init(&trans, c, 0, 0);
309
310         iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS, POS_MIN, 0);
311
312         k = bch2_btree_iter_peek(iter);
313         BUG_ON(k.k);
314
315         k = bch2_btree_iter_peek(iter);
316         BUG_ON(k.k);
317
318         bch2_trans_exit(&trans);
319 }
320
321 static void test_peek_end_extents(struct bch_fs *c, u64 nr)
322 {
323         struct btree_trans trans;
324         struct btree_iter *iter;
325         struct bkey_s_c k;
326
327         bch2_trans_init(&trans, c, 0, 0);
328
329         iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS, POS_MIN, 0);
330
331         k = bch2_btree_iter_peek(iter);
332         BUG_ON(k.k);
333
334         k = bch2_btree_iter_peek(iter);
335         BUG_ON(k.k);
336
337         bch2_trans_exit(&trans);
338 }
339
340 /* extent unit tests */
341
342 u64 test_version;
343
344 static void insert_test_extent(struct bch_fs *c,
345                                u64 start, u64 end)
346 {
347         struct bkey_i_cookie k;
348         int ret;
349
350         //pr_info("inserting %llu-%llu v %llu", start, end, test_version);
351
352         bkey_cookie_init(&k.k_i);
353         k.k_i.k.p.offset = end;
354         k.k_i.k.size = end - start;
355         k.k_i.k.version.lo = test_version++;
356
357         ret = bch2_btree_insert(c, BTREE_ID_EXTENTS, &k.k_i,
358                                 NULL, NULL, 0);
359         BUG_ON(ret);
360 }
361
362 static void __test_extent_overwrite(struct bch_fs *c,
363                                     u64 e1_start, u64 e1_end,
364                                     u64 e2_start, u64 e2_end)
365 {
366         insert_test_extent(c, e1_start, e1_end);
367         insert_test_extent(c, e2_start, e2_end);
368
369         delete_test_keys(c);
370 }
371
372 static void test_extent_overwrite_front(struct bch_fs *c, u64 nr)
373 {
374         __test_extent_overwrite(c, 0, 64, 0, 32);
375         __test_extent_overwrite(c, 8, 64, 0, 32);
376 }
377
378 static void test_extent_overwrite_back(struct bch_fs *c, u64 nr)
379 {
380         __test_extent_overwrite(c, 0, 64, 32, 64);
381         __test_extent_overwrite(c, 0, 64, 32, 72);
382 }
383
384 static void test_extent_overwrite_middle(struct bch_fs *c, u64 nr)
385 {
386         __test_extent_overwrite(c, 0, 64, 32, 40);
387 }
388
389 static void test_extent_overwrite_all(struct bch_fs *c, u64 nr)
390 {
391         __test_extent_overwrite(c, 32, 64,  0,  64);
392         __test_extent_overwrite(c, 32, 64,  0, 128);
393         __test_extent_overwrite(c, 32, 64, 32,  64);
394         __test_extent_overwrite(c, 32, 64, 32, 128);
395 }
396
397 /* perf tests */
398
399 static u64 test_rand(void)
400 {
401         u64 v;
402 #if 0
403         v = prandom_u32();
404 #else
405         prandom_bytes(&v, sizeof(v));
406 #endif
407         return v;
408 }
409
410 static void rand_insert(struct bch_fs *c, u64 nr)
411 {
412         struct bkey_i_cookie k;
413         int ret;
414         u64 i;
415
416         for (i = 0; i < nr; i++) {
417                 bkey_cookie_init(&k.k_i);
418                 k.k.p.offset = test_rand();
419
420                 ret = bch2_btree_insert(c, BTREE_ID_DIRENTS, &k.k_i,
421                                         NULL, NULL, 0);
422                 BUG_ON(ret);
423         }
424 }
425
426 static void rand_lookup(struct bch_fs *c, u64 nr)
427 {
428         struct btree_trans trans;
429         struct btree_iter *iter;
430         struct bkey_s_c k;
431         u64 i;
432
433         bch2_trans_init(&trans, c, 0, 0);
434
435         for (i = 0; i < nr; i++) {
436                 iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS,
437                                            POS(0, test_rand()), 0);
438
439                 k = bch2_btree_iter_peek(iter);
440                 bch2_trans_iter_free(&trans, iter);
441         }
442
443         bch2_trans_exit(&trans);
444 }
445
446 static void rand_mixed(struct bch_fs *c, u64 nr)
447 {
448         struct btree_trans trans;
449         struct btree_iter *iter;
450         struct bkey_s_c k;
451         int ret;
452         u64 i;
453
454         bch2_trans_init(&trans, c, 0, 0);
455
456         for (i = 0; i < nr; i++) {
457                 iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS,
458                                            POS(0, test_rand()), 0);
459
460                 k = bch2_btree_iter_peek(iter);
461
462                 if (!(i & 3) && k.k) {
463                         struct bkey_i_cookie k;
464
465                         bkey_cookie_init(&k.k_i);
466                         k.k.p = iter->pos;
467
468                         bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &k.k_i));
469                         ret = bch2_trans_commit(&trans, NULL, NULL, 0);
470                         BUG_ON(ret);
471                 }
472
473                 bch2_trans_iter_free(&trans, iter);
474         }
475
476         bch2_trans_exit(&trans);
477 }
478
479 static void rand_delete(struct bch_fs *c, u64 nr)
480 {
481         struct bkey_i k;
482         int ret;
483         u64 i;
484
485         for (i = 0; i < nr; i++) {
486                 bkey_init(&k.k);
487                 k.k.p.offset = test_rand();
488
489                 ret = bch2_btree_insert(c, BTREE_ID_DIRENTS, &k,
490                                         NULL, NULL, 0);
491                 BUG_ON(ret);
492         }
493 }
494
495 static void seq_insert(struct bch_fs *c, u64 nr)
496 {
497         struct btree_trans trans;
498         struct btree_iter *iter;
499         struct bkey_s_c k;
500         struct bkey_i_cookie insert;
501         int ret;
502         u64 i = 0;
503
504         bkey_cookie_init(&insert.k_i);
505
506         bch2_trans_init(&trans, c, 0, 0);
507
508         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
509                            BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
510                 insert.k.p = iter->pos;
511
512                 bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &insert.k_i));
513                 ret = bch2_trans_commit(&trans, NULL, NULL, 0);
514                 BUG_ON(ret);
515
516                 if (++i == nr)
517                         break;
518         }
519         bch2_trans_exit(&trans);
520 }
521
522 static void seq_lookup(struct bch_fs *c, u64 nr)
523 {
524         struct btree_trans trans;
525         struct btree_iter *iter;
526         struct bkey_s_c k;
527         int ret;
528
529         bch2_trans_init(&trans, c, 0, 0);
530
531         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN, 0, k, ret)
532                 ;
533         bch2_trans_exit(&trans);
534 }
535
536 static void seq_overwrite(struct bch_fs *c, u64 nr)
537 {
538         struct btree_trans trans;
539         struct btree_iter *iter;
540         struct bkey_s_c k;
541         int ret;
542
543         bch2_trans_init(&trans, c, 0, 0);
544
545         for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, POS_MIN,
546                            BTREE_ITER_INTENT, k, ret) {
547                 struct bkey_i_cookie u;
548
549                 bkey_reassemble(&u.k_i, k);
550
551                 bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &u.k_i));
552                 ret = bch2_trans_commit(&trans, NULL, NULL, 0);
553                 BUG_ON(ret);
554         }
555         bch2_trans_exit(&trans);
556 }
557
558 static void seq_delete(struct bch_fs *c, u64 nr)
559 {
560         int ret;
561
562         ret = bch2_btree_delete_range(c, BTREE_ID_DIRENTS,
563                                       POS(0, 0), POS(0, U64_MAX),
564                                       NULL);
565         BUG_ON(ret);
566 }
567
568 typedef void (*perf_test_fn)(struct bch_fs *, u64);
569
570 struct test_job {
571         struct bch_fs                   *c;
572         u64                             nr;
573         unsigned                        nr_threads;
574         perf_test_fn                    fn;
575
576         atomic_t                        ready;
577         wait_queue_head_t               ready_wait;
578
579         atomic_t                        done;
580         struct completion               done_completion;
581
582         u64                             start;
583         u64                             finish;
584 };
585
586 static int btree_perf_test_thread(void *data)
587 {
588         struct test_job *j = data;
589
590         if (atomic_dec_and_test(&j->ready)) {
591                 wake_up(&j->ready_wait);
592                 j->start = sched_clock();
593         } else {
594                 wait_event(j->ready_wait, !atomic_read(&j->ready));
595         }
596
597         j->fn(j->c, j->nr / j->nr_threads);
598
599         if (atomic_dec_and_test(&j->done)) {
600                 j->finish = sched_clock();
601                 complete(&j->done_completion);
602         }
603
604         return 0;
605 }
606
607 void bch2_btree_perf_test(struct bch_fs *c, const char *testname,
608                           u64 nr, unsigned nr_threads)
609 {
610         struct test_job j = { .c = c, .nr = nr, .nr_threads = nr_threads };
611         char name_buf[20], nr_buf[20], per_sec_buf[20];
612         unsigned i;
613         u64 time;
614
615         atomic_set(&j.ready, nr_threads);
616         init_waitqueue_head(&j.ready_wait);
617
618         atomic_set(&j.done, nr_threads);
619         init_completion(&j.done_completion);
620
621 #define perf_test(_test)                                \
622         if (!strcmp(testname, #_test)) j.fn = _test
623
624         perf_test(rand_insert);
625         perf_test(rand_lookup);
626         perf_test(rand_mixed);
627         perf_test(rand_delete);
628
629         perf_test(seq_insert);
630         perf_test(seq_lookup);
631         perf_test(seq_overwrite);
632         perf_test(seq_delete);
633
634         /* a unit test, not a perf test: */
635         perf_test(test_delete);
636         perf_test(test_delete_written);
637         perf_test(test_iterate);
638         perf_test(test_iterate_extents);
639         perf_test(test_iterate_slots);
640         perf_test(test_iterate_slots_extents);
641         perf_test(test_peek_end);
642         perf_test(test_peek_end_extents);
643
644         perf_test(test_extent_overwrite_front);
645         perf_test(test_extent_overwrite_back);
646         perf_test(test_extent_overwrite_middle);
647         perf_test(test_extent_overwrite_all);
648
649         if (!j.fn) {
650                 pr_err("unknown test %s", testname);
651                 return;
652         }
653
654         //pr_info("running test %s:", testname);
655
656         if (nr_threads == 1)
657                 btree_perf_test_thread(&j);
658         else
659                 for (i = 0; i < nr_threads; i++)
660                         kthread_run(btree_perf_test_thread, &j,
661                                     "bcachefs perf test[%u]", i);
662
663         while (wait_for_completion_interruptible(&j.done_completion))
664                 ;
665
666         time = j.finish - j.start;
667
668         scnprintf(name_buf, sizeof(name_buf), "%s:", testname);
669         bch2_hprint(&PBUF(nr_buf), nr);
670         bch2_hprint(&PBUF(per_sec_buf), nr * NSEC_PER_SEC / time);
671         printk(KERN_INFO "%-12s %s with %u threads in %5llu sec, %5llu nsec per iter, %5s per sec\n",
672                 name_buf, nr_buf, nr_threads,
673                 time / NSEC_PER_SEC,
674                 time * nr_threads / nr,
675                 per_sec_buf);
676 }
677
678 #endif /* CONFIG_BCACHEFS_TESTS */