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