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