From f7d4497b80213a03123dba2769dc5e30e44da7b2 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Thu, 18 May 2023 12:35:29 -0500 Subject: [PATCH] Added some simple mtree benchmarks It's interesting to note the different performance characteristics of purely CoW btrees vs our mutable mtree. The main downside of our mtree is the need to fetch leaf mdirs. This fetch is expensive, and can be avoided in CoW btrees by storing the trunk in each branch's parent. On the other hand, btrees need to propagate all changes upwards to the root. An interesting takeaway is that a sort of mdir-trunk cache may be a very interesting optimization for relatively little RAM cost. This may be something to explore in the future. --- benches/bench_mtree.toml | 135 +++++++++++++++++++++++++++++++++++++++ tests/test_mtree.toml | 4 ++ 2 files changed, 139 insertions(+) create mode 100644 benches/bench_mtree.toml diff --git a/benches/bench_mtree.toml b/benches/bench_mtree.toml new file mode 100644 index 00000000..ab5f274f --- /dev/null +++ b/benches/bench_mtree.toml @@ -0,0 +1,135 @@ + +# maximize lookahead buffer, we don't actually gc so we only get one pass +# of the disk for these tests +defines.LOOKAHEAD_SIZE = 'BLOCK_COUNT / 8' + +[cases.bench_mtree_lookup] +defines.N = [8, 16, 32, 64, 128, 256, 1024] +# 0 = in-order +# 1 = reversed-order +# 2 = random-order +defines.ORDER = [0, 1, 2] +defines.SEED = 42 +in = 'lfs.c' +code = ''' + uint32_t prng = SEED; + const char *alphas = "abcdefghijklmnopqrstuvwxyz"; + + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // create an mtree with N entries + for (lfs_size_t i = 0; i < N; i++) { + // choose an mid + lfs_ssize_t mid + = lfsr_mtree_weight(&lfs) == 0 ? -1 + : (ORDER == 0) ? (lfs_ssize_t)(lfsr_mtree_weight(&lfs)-1) + : (ORDER == 1) ? 0 + : (lfs_ssize_t)(BENCH_PRNG(&prng) % lfsr_mtree_weight(&lfs)); + // fetch mdir + lfsr_mdir_t mdir; + lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; + + // choose rid + lfs_ssize_t rid + = (ORDER == 0) ? lfsr_mdir_weight(&mdir) + : (ORDER == 1) ? 0 + : BENCH_PRNG(&prng) % (lfsr_mdir_weight(&mdir)+1); + + // create an entry + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( + LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0; + } + + // bench lookup + BENCH_START(); + // choose an mid + lfs_ssize_t mid + = lfsr_mtree_weight(&lfs) == 0 ? -1 + : (lfs_ssize_t)(BENCH_PRNG(&prng) % lfsr_mtree_weight(&lfs)); + // fetch mdir + lfsr_mdir_t mdir; + lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; + + // choose rid + lfs_ssize_t rid = BENCH_PRNG(&prng) % lfsr_mdir_weight(&mdir); + + // lookup + uint8_t buffer[4]; + lfsr_mdir_get(&lfs, &mdir, rid, LFSR_TAG_INLINED, buffer, 4) => 1; + BENCH_STOP(); + + lfsr_unmount(&lfs) => 0; +''' + +[cases.bench_mtree_commit] +defines.N = [8, 16, 32, 64, 128, 256, 1024] +# 0 = in-order +# 1 = reversed-order +# 2 = random-order +defines.ORDER = [0, 1, 2] +defines.SEED = 42 +defines.AMORTIZED = false +in = 'lfs.c' +code = ''' + uint32_t prng = SEED; + const char *alphas = "abcdefghijklmnopqrstuvwxyz"; + + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // create an mtree with N entries + if (AMORTIZED) { + BENCH_START(); + } + for (lfs_size_t i = 0; i < N; i++) { + // choose an mid + lfs_ssize_t mid + = lfsr_mtree_weight(&lfs) == 0 ? -1 + : (ORDER == 0) ? (lfs_ssize_t)(lfsr_mtree_weight(&lfs)-1) + : (ORDER == 1) ? 0 + : (lfs_ssize_t)(BENCH_PRNG(&prng) % lfsr_mtree_weight(&lfs)); + // fetch mdir + lfsr_mdir_t mdir; + lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; + + // choose rid + lfs_ssize_t rid + = (ORDER == 0) ? lfsr_mdir_weight(&mdir) + : (ORDER == 1) ? 0 + : BENCH_PRNG(&prng) % (lfsr_mdir_weight(&mdir)+1); + + // create an entry + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( + LFSR_ATTR(rid, MKINLINED, +1, &alphas[i % 26], 1))) => 0; + } + + // bench commit + if (!AMORTIZED) { + BENCH_START(); + } + // choose an mid + lfs_ssize_t mid + = lfsr_mtree_weight(&lfs) == 0 ? -1 + : (ORDER == 0) ? (lfs_ssize_t)(lfsr_mtree_weight(&lfs)-1) + : (ORDER == 1) ? 0 + : (lfs_ssize_t)(BENCH_PRNG(&prng) % lfsr_mtree_weight(&lfs)); + // fetch mdir + lfsr_mdir_t mdir; + lfsr_mtree_lookup(&lfs, mid, &mdir) => 0; + + // choose rid + lfs_ssize_t rid + = (ORDER == 0) ? lfsr_mdir_weight(&mdir) + : (ORDER == 1) ? 0 + : BENCH_PRNG(&prng) % (lfsr_mdir_weight(&mdir)+1); + + // create an entry + lfsr_mdir_commit(&lfs, &mdir, &rid, LFSR_ATTRS( + LFSR_ATTR(rid, MKINLINED, +1, "C", 1))) => 0; + BENCH_STOP(); + + lfsr_unmount(&lfs) => 0; +''' diff --git a/tests/test_mtree.toml b/tests/test_mtree.toml index 06f92c2f..44f4b955 100644 --- a/tests/test_mtree.toml +++ b/tests/test_mtree.toml @@ -1,3 +1,7 @@ +# maximize lookahead buffer, we don't actually gc so we only get one pass +# of the disk for these tests +defines.LOOKAHEAD_SIZE = 'BLOCK_COUNT / 8' + # test a single mroot [cases.test_mtree_one_mroot] code = '''