6a96866737
Note that because we amortize the traversal cost over the number of entries, mtree traversal may have some strange looking results when compared to mtree lookup. Though it's interesting to note this is a valid result. In mtree lookups we need to fetch the mdir for each entry, which is expensive. However mtree traversal can strictly avoid fetching each mdir more than once. This does make mdir traversal faster when iterating over all mdirs in order. This can be represented in big O notation if we treat the number of entries (n) and block size (b) as variables: - mtree traversal via lookup = O(nb+nlog(b)logb(n)) - mtree traversal via traversal = O(nlog(b)logb(n))
202 lines
5.7 KiB
TOML
202 lines
5.7 KiB
TOML
|
|
# 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;
|
|
'''
|
|
|
|
[cases.bench_mtree_traversal]
|
|
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.VALIDATE = [false, true]
|
|
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;
|
|
}
|
|
|
|
// traverse the mtree
|
|
BENCH_START();
|
|
lfsr_mtree_traversal_t traversal = LFSR_MTREE_TRAVERSAL_INIT(
|
|
VALIDATE ? LFSR_MTREE_TRAVERSAL_VALIDATE : 0);
|
|
|
|
for (lfs_block_t i = 0;; i++) {
|
|
// a bit hacky, but this catches infinite loops
|
|
assert(i < 2*(1+N));
|
|
|
|
lfs_size_t mid_;
|
|
lfsr_tag_t tag_;
|
|
lfsr_data_t data_;
|
|
int err = lfsr_mtree_traversal_next(&lfs, &traversal,
|
|
&mid_, &tag_, &data_);
|
|
assert(!err || err == LFS_ERR_NOENT);
|
|
if (err == LFS_ERR_NOENT) {
|
|
break;
|
|
}
|
|
|
|
assert(tag_ == LFSR_TAG_BTREE || tag_ == LFSR_TAG_MDIR);
|
|
}
|
|
BENCH_STOP();
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|