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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user