t: Moved lookahead population into lfsr_mtree_gc/lfs_alloc

It was a bit weird to have this in lfsr_mtree_traverse, which doesn't
change any filesystem state otherwise.

At the very least we should call lfs_alloc_markinuse and
lfs_alloc_markfree in the same function, and rerouting
lfsr_mtree_traverse eot to handle this would have added code cost
anyways.

The main cost is stack:

           code          stack
  before: 36256           2680
  after:  36288 (+0.1%)   2704 (+0.9%)

Unfortunately this reveals one of the bigger issues with our optional
return parameters: if a function with optional return parameters needs
the structs to perform work, in this case lfsr_mtree_traverse needs
lfsr_bptr_t in case ckmeta/ckdata is requested, it requires an
additional stack allocation.

In theory, these stack allocations could be elided if the return structs
are provided, but you can't really express this in standard C.

Combine this with the fact that lfs_alloc is sensitive to stack changes,
and lives at the bottom at every hot-path, and the end result is more
stack usage.

Note that the additional stack cost, 24 bytes, is exactly equal to one
tag + one bptr, 4 bytes + 20 bytes.
This commit is contained in:
Christopher Haster
2024-07-19 14:26:32 -05:00
parent 51fa5b9831
commit 46488ebc7f
+36 -24
View File
@@ -8622,11 +8622,12 @@ static int lfsr_mtree_traverse_(lfs_t *lfs, lfsr_traversal_t *t,
}
// needed in lfsr_mtree_traverse
static void lfs_alloc_markinuse(lfs_t *lfs, lfs_block_t block);
static void lfs_alloc_markinuse(lfs_t *lfs,
lfsr_tag_t tag, const lfsr_bptr_t *bptr);
// high-level immutable traversal, handle extra features here,
// but no mutation! (we're called in lfs_alloc, so things would end up
// recursive)
// recursive, which would be a bit bad!)
static int lfsr_mtree_traverse(lfs_t *lfs, lfsr_traversal_t *t,
lfsr_tag_t *tag_, lfsr_bptr_t *bptr_) {
lfsr_tag_t tag;
@@ -8661,25 +8662,6 @@ static int lfsr_mtree_traverse(lfs_t *lfs, lfsr_traversal_t *t,
}
}
// track in-use blocks
if (lfsr_t_islookahead(t->o.o.flags)) {
if (tag == LFSR_TAG_MDIR) {
lfsr_mdir_t *mdir = (lfsr_mdir_t*)bptr.data.u.buffer;
lfs_alloc_markinuse(lfs, mdir->rbyd.blocks[0]);
lfs_alloc_markinuse(lfs, mdir->rbyd.blocks[1]);
} else if (tag == LFSR_TAG_BRANCH) {
lfsr_rbyd_t *rbyd = (lfsr_rbyd_t*)bptr.data.u.buffer;
lfs_alloc_markinuse(lfs, rbyd->blocks[0]);
} else if (tag == LFSR_TAG_BLOCK) {
lfs_alloc_markinuse(lfs, bptr.data.u.disk.block);
} else {
LFS_UNREACHABLE();
}
}
if (tag_) {
*tag_ = tag;
}
@@ -8734,6 +8716,11 @@ dropped:;
}
}
// track in-use blocks?
if (lfsr_t_islookahead(t->o.o.flags)) {
lfs_alloc_markinuse(lfs, tag, &bptr);
}
// compacting mdirs?
if (lfsr_t_iscompact(t->o.o.flags)
&& tag == LFSR_TAG_MDIR
@@ -8913,7 +8900,7 @@ static void lfs_alloc_discard(lfs_t *lfs) {
}
// mark a block as in-use
static void lfs_alloc_markinuse(lfs_t *lfs, lfs_block_t block) {
static void lfs_alloc_markinuse_(lfs_t *lfs, lfs_block_t block) {
// translate to lookahead-relative
lfs_block_t block_ = ((
(lfs_sblock_t)(block
@@ -8933,6 +8920,26 @@ static void lfs_alloc_markinuse(lfs_t *lfs, lfs_block_t block) {
}
}
// mark some filesystem object as in-use
static void lfs_alloc_markinuse(lfs_t *lfs,
lfsr_tag_t tag, const lfsr_bptr_t *bptr) {
if (tag == LFSR_TAG_MDIR) {
lfsr_mdir_t *mdir = (lfsr_mdir_t*)bptr->data.u.buffer;
lfs_alloc_markinuse_(lfs, mdir->rbyd.blocks[0]);
lfs_alloc_markinuse_(lfs, mdir->rbyd.blocks[1]);
} else if (tag == LFSR_TAG_BRANCH) {
lfsr_rbyd_t *rbyd = (lfsr_rbyd_t*)bptr->data.u.buffer;
lfs_alloc_markinuse_(lfs, rbyd->blocks[0]);
} else if (tag == LFSR_TAG_BLOCK) {
lfs_alloc_markinuse_(lfs, bptr->data.u.disk.block);
} else {
LFS_UNREACHABLE();
}
}
// needed in lfs_alloc_markfree
static lfs_sblock_t lfs_alloc_findfree(lfs_t *lfs);
@@ -9036,18 +9043,23 @@ static lfs_sblock_t lfs_alloc(lfs_t *lfs, bool erase) {
// no blocks in our lookahead buffer?
//
// traverse the filesystem, building up knowledge of what blocks are
// in use in the next lookahead window
// in-use in the next lookahead window
//
lfsr_traversal_t t = LFSR_TRAVERSAL(LFS_T_LOOKAHEAD);
while (true) {
lfsr_tag_t tag;
lfsr_bptr_t bptr;
int err = lfsr_mtree_traverse(lfs, &t,
NULL, NULL);
&tag, &bptr);
if (err) {
if (err == LFS_ERR_NOENT) {
break;
}
return err;
}
// track in-use blocks
lfs_alloc_markinuse(lfs, tag, &bptr);
}
// mark anything not seen as free