From 8c4863f13e7aa08e9c12b13a5939f1e5f0fe6eb4 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 15 May 2024 02:20:47 -0500 Subject: [PATCH] Attempted to optimized lfsr_file_t by moving the cfg field first Because of the invasive linked-lists, this was a bit more complicated than the related move in lfs_t. But we already have similar field-relative offsets in lfsr_dir_t for the dir + bookmark mdirs. Added some helpers to help with this: - lfsr_opened_dir - lfsr_opened_constdir - lfsr_opened_bookmark - lfsr_opened_constbookmark - lfsr_opened_file - lfsr_opened_constfile Unfortunately this resulted in less savings than in lfs_t, and actually costs us code, likely because of how often we go from lfsr_file_t <-> lfsr_opened_t: code stack before: 33358 2632 after: 33402 (+0.1%) 2632 (+0.0%) --- lfs.c | 324 +++++++++++++++++++++++++++++++--------------------------- lfs.h | 2 +- 2 files changed, 177 insertions(+), 149 deletions(-) diff --git a/lfs.c b/lfs.c index 77b61b6f..303a9244 100644 --- a/lfs.c +++ b/lfs.c @@ -5155,6 +5155,163 @@ static int lfsr_btree_traverse(lfs_t *lfs, const lfsr_btree_t *btree, +// metadata-id things + +static inline lfsr_mid_t lfsr_mleafweight(const lfs_t *lfs) { + return 1 << lfs->mleaf_bits; +} + +#define LFSR_MID(_lfs, _bid, _rid) \ + (((_bid) & ~((1 << (_lfs)->mleaf_bits)-1)) + (_rid)) + +static inline lfsr_sbid_t lfsr_mid_bid(const lfs_t *lfs, lfsr_smid_t mid) { + return mid | ((1 << lfs->mleaf_bits) - 1); +} + +static inline lfsr_srid_t lfsr_mid_rid(const lfs_t *lfs, lfsr_smid_t mid) { + // bit of a strange mapping, but we want to preserve mid=-1 => rid=-1 + return (mid >> (8*sizeof(lfsr_smid_t)-1)) + | (mid & ((1 << lfs->mleaf_bits) - 1)); +} + + +// metadata-pointer things + +// the mroot anchor, mdir 0x{0,1} is the entry point into the filesystem +#define LFSR_MPTR_MROOTANCHOR() ((const lfsr_mptr_t){{0, 1}}) + +static inline int lfsr_mptr_cmp( + const lfsr_mptr_t *a, + const lfsr_mptr_t *b) { + // note these can be in either order + if (lfs_max32(a->blocks[0], a->blocks[1]) + != lfs_max32(b->blocks[0], b->blocks[1])) { + return lfs_max32(a->blocks[0], a->blocks[1]) + - lfs_max32(b->blocks[0], b->blocks[1]); + } else { + return lfs_min32(a->blocks[0], a->blocks[1]) + - lfs_min32(b->blocks[0], b->blocks[1]); + } +} + +static inline bool lfsr_mptr_ismrootanchor(const lfsr_mptr_t *mptr) { + // mrootanchor is always at 0x{0,1} + // just check that the first block is in mroot anchor range + return mptr->blocks[0] <= 1; +} + +// mptr encoding: +// .---+- -+- -+- -+- -. blocks: 2 leb128s <=2x5 bytes +// | block x 2 | total: <=10 bytes +// + + +// | | +// '---+- -+- -+- -+- -' +// +#define LFSR_MPTR_DSIZE (5+5) + +#define LFSR_DATA_MPTR_(_mptr, _buffer) \ + ((struct {lfsr_data_t d;}){lfsr_data_frommptr(_mptr, _buffer)}.d) + +#define LFSR_DATA_MPTR(_mptr) \ + LFSR_DATA_MPTR_(_mptr, (uint8_t[LFSR_MPTR_DSIZE]){0}) + +static lfsr_data_t lfsr_data_frommptr(const lfsr_mptr_t *mptr, + uint8_t buffer[static LFSR_MPTR_DSIZE]) { + // blocks should not exceed 31-bits + LFS_ASSERT(mptr->blocks[0] <= 0x7fffffff); + LFS_ASSERT(mptr->blocks[1] <= 0x7fffffff); + + lfs_ssize_t d = 0; + for (int i = 0; i < 2; i++) { + lfs_ssize_t d_ = lfs_toleb128(mptr->blocks[i], &buffer[d], 5); + LFS_ASSERT(d_ >= 0); + d += d_; + } + + return LFSR_DATA_BUF(buffer, d); +} + +static int lfsr_data_readmptr(lfs_t *lfs, lfsr_data_t *data, + lfsr_mptr_t *mptr) { + for (int i = 0; i < 2; i++) { + int err = lfsr_data_readleb128(lfs, data, &mptr->blocks[i]); + if (err) { + return err; + } + } + + return 0; +} + + +// track opened mdirs to keep state in-sync +static bool lfsr_opened_isopen(lfs_t *lfs, const lfsr_opened_t *o) { + for (lfsr_opened_t *o_ = lfs->opened; o_; o_ = o_->next) { + if (o_ == o) { + return true; + } + } + + return false; +} + +static void lfsr_opened_add(lfs_t *lfs, lfsr_opened_t *o) { + LFS_ASSERT(!lfsr_opened_isopen(lfs, o)); + o->next = lfs->opened; + lfs->opened = o; +} + +static void lfsr_opened_remove(lfs_t *lfs, lfsr_opened_t *o) { + LFS_ASSERT(lfsr_opened_isopen(lfs, o)); + for (lfsr_opened_t **o_ = &lfs->opened; *o_; o_ = &(*o_)->next) { + if (*o_ == o) { + *o_ = (*o_)->next; + break; + } + } +} + +static bool lfsr_mid_isopen(lfs_t *lfs, lfsr_smid_t mid) { + for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { + // we really only care about regular open files here, all + // others are either transient (dirs) or fake (orphans) + if (o->type == LFS_TYPE_REG && o->mdir.mid == mid) { + return true; + } + } + + return false; +} + +// various opened mdir casts +static inline lfsr_dir_t *lfsr_opened_dir(lfsr_opened_t *o) { + return (lfsr_dir_t*)o; +} + +static inline const lfsr_dir_t *lfsr_opened_constdir( + const lfsr_opened_t *o) { + return (lfsr_dir_t*)o; +} + +static inline lfsr_dir_t *lfsr_opened_bookmark(lfsr_opened_t *o) { + return (lfsr_dir_t*)(o - 1); +} + +static inline const lfsr_dir_t *lfsr_opened_constbookmark( + const lfsr_opened_t *o) { + return (const lfsr_dir_t*)(o - 1); +} + +static inline lfsr_file_t *lfsr_opened_file(lfsr_opened_t *o) { + return (lfsr_file_t*)((struct lfs_file_config**)o - 1); +} + +static inline const lfsr_file_t *lfsr_opened_constfile( + const lfsr_opened_t *o) { + return (const lfsr_file_t*)((struct lfs_file_config*const *)o - 1); +} + + /// shrub/sprout things /// // needed in shrub/sprout/mdir/etc @@ -5195,7 +5352,7 @@ static lfs_ssize_t lfsr_sprout_estimate(lfs_t *lfs, // only include the last reference const lfsr_sprout_t *last = NULL; for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && lfsr_bshrub_isbsprout(&file_->m.mdir, &file_->bshrub) && lfsr_sprout_cmp(&file_->bshrub.u.bsprout, sprout) == 0) { @@ -5224,7 +5381,7 @@ static int lfsr_sprout_compact(lfs_t *lfs, const lfsr_rbyd_t *rbyd_, // stage any opened inlined files with their new location so we // can update these later if our commit is a success for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && lfsr_bshrub_isbsprout(&file_->m.mdir, &file_->bshrub) && lfsr_sprout_cmp( @@ -5329,7 +5486,7 @@ static lfs_ssize_t lfsr_shrub_estimate(lfs_t *lfs, // only include the last reference const lfsr_shrub_t *last = NULL; for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && lfsr_bshrub_isbshrub(&file_->m.mdir, &file_->bshrub) && lfsr_shrub_cmp(&file_->bshrub.u.bshrub, shrub) == 0) { @@ -5361,7 +5518,7 @@ static int lfsr_shrub_compact(lfs_t *lfs, lfsr_rbyd_t *rbyd_, // // this should include our current bshrub for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && lfsr_bshrub_isbshrub(&file_->m.mdir, &file_->bshrub) && lfsr_shrub_cmp(&file_->bshrub.u.bshrub, shrub) == 0) { @@ -5417,98 +5574,8 @@ static int lfsr_shrub_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd_, } - /// Metadata pair stuff /// -// metadata-id things - -static inline lfsr_mid_t lfsr_mleafweight(const lfs_t *lfs) { - return 1 << lfs->mleaf_bits; -} - -#define LFSR_MID(_lfs, _bid, _rid) \ - (((_bid) & ~((1 << (_lfs)->mleaf_bits)-1)) + (_rid)) - -static inline lfsr_sbid_t lfsr_mid_bid(const lfs_t *lfs, lfsr_smid_t mid) { - return mid | ((1 << lfs->mleaf_bits) - 1); -} - -static inline lfsr_srid_t lfsr_mid_rid(const lfs_t *lfs, lfsr_smid_t mid) { - // bit of a strange mapping, but we want to preserve mid=-1 => rid=-1 - return (mid >> (8*sizeof(lfsr_smid_t)-1)) - | (mid & ((1 << lfs->mleaf_bits) - 1)); -} - - -// metadata-pointer things - -// the mroot anchor, mdir 0x{0,1} is the entry point into the filesystem -#define LFSR_MPTR_MROOTANCHOR() ((const lfsr_mptr_t){{0, 1}}) - -static inline int lfsr_mptr_cmp( - const lfsr_mptr_t *a, - const lfsr_mptr_t *b) { - // note these can be in either order - if (lfs_max32(a->blocks[0], a->blocks[1]) - != lfs_max32(b->blocks[0], b->blocks[1])) { - return lfs_max32(a->blocks[0], a->blocks[1]) - - lfs_max32(b->blocks[0], b->blocks[1]); - } else { - return lfs_min32(a->blocks[0], a->blocks[1]) - - lfs_min32(b->blocks[0], b->blocks[1]); - } -} - -static inline bool lfsr_mptr_ismrootanchor(const lfsr_mptr_t *mptr) { - // mrootanchor is always at 0x{0,1} - // just check that the first block is in mroot anchor range - return mptr->blocks[0] <= 1; -} - -// mptr encoding: -// .---+- -+- -+- -+- -. blocks: 2 leb128s <=2x5 bytes -// | block x 2 | total: <=10 bytes -// + + -// | | -// '---+- -+- -+- -+- -' -// -#define LFSR_MPTR_DSIZE (5+5) - -#define LFSR_DATA_MPTR_(_mptr, _buffer) \ - ((struct {lfsr_data_t d;}){lfsr_data_frommptr(_mptr, _buffer)}.d) - -#define LFSR_DATA_MPTR(_mptr) \ - LFSR_DATA_MPTR_(_mptr, (uint8_t[LFSR_MPTR_DSIZE]){0}) - -static lfsr_data_t lfsr_data_frommptr(const lfsr_mptr_t *mptr, - uint8_t buffer[static LFSR_MPTR_DSIZE]) { - // blocks should not exceed 31-bits - LFS_ASSERT(mptr->blocks[0] <= 0x7fffffff); - LFS_ASSERT(mptr->blocks[1] <= 0x7fffffff); - - lfs_ssize_t d = 0; - for (int i = 0; i < 2; i++) { - lfs_ssize_t d_ = lfs_toleb128(mptr->blocks[i], &buffer[d], 5); - LFS_ASSERT(d_ >= 0); - d += d_; - } - - return LFSR_DATA_BUF(buffer, d); -} - -static int lfsr_data_readmptr(lfs_t *lfs, lfsr_data_t *data, - lfsr_mptr_t *mptr) { - for (int i = 0; i < 2; i++) { - int err = lfsr_data_readleb128(lfs, data, &mptr->blocks[i]); - if (err) { - return err; - } - } - - return 0; -} - - // mdir convenience functions static inline const lfsr_mptr_t *lfsr_mdir_mptr(const lfsr_mdir_t *mdir) { return (const lfsr_mptr_t*)mdir->rbyd.blocks; @@ -5664,45 +5731,6 @@ static int lfsr_mdir_suplookup(lfs_t *lfs, const lfsr_mdir_t *mdir, return 0; } -// track opened mdirs to keep state in-sync -static bool lfsr_opened_isopen(lfs_t *lfs, const lfsr_opened_t *o) { - for (lfsr_opened_t *o_ = lfs->opened; o_; o_ = o_->next) { - if (o_ == o) { - return true; - } - } - - return false; -} - -static void lfsr_opened_add(lfs_t *lfs, lfsr_opened_t *o) { - LFS_ASSERT(!lfsr_opened_isopen(lfs, o)); - o->next = lfs->opened; - lfs->opened = o; -} - -static void lfsr_opened_remove(lfs_t *lfs, lfsr_opened_t *o) { - LFS_ASSERT(lfsr_opened_isopen(lfs, o)); - for (lfsr_opened_t **o_ = &lfs->opened; *o_; o_ = &(*o_)->next) { - if (*o_ == o) { - *o_ = (*o_)->next; - break; - } - } -} - -static bool lfsr_mid_isopen(lfs_t *lfs, lfsr_smid_t mid) { - for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - // we really only care about regular open files here, all - // others are either transient (dirs) or fake (orphans) - if (o->type == LFS_TYPE_REG && o->mdir.mid == mid) { - return true; - } - } - - return false; -} - /// Metadata-tree things /// @@ -6071,7 +6099,7 @@ static int lfsr_mdir_commit__(lfs_t *lfs, lfsr_mdir_t *mdir, // we're not quite done! we also need to bring over any // unsynced files for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file = (lfsr_file_t*)o; + lfsr_file_t *file = lfsr_opened_file(o); // belongs to our mid? if (file->m.type != LFS_TYPE_REG || file->m.mdir.mid != mdir__->mid) { @@ -6311,7 +6339,7 @@ static lfs_ssize_t lfsr_mdir_estimate__(lfs_t *lfs, const lfsr_mdir_t *mdir, // files, I suppose if this becomes a problem we could sort // opened files by mid for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file = (lfsr_file_t*)o; + lfsr_file_t *file = lfsr_opened_file(o); // belongs to our mdir + rid? if (file->m.type != LFS_TYPE_REG || lfsr_mdir_cmp(&file->m.mdir, mdir) != 0 @@ -6457,7 +6485,7 @@ static int lfsr_mdir_compact__(lfs_t *lfs, lfsr_mdir_t *mdir_, // we're not quite done! we also need to bring over any unsynced files for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file = (lfsr_file_t*)o; + lfsr_file_t *file = lfsr_opened_file(o); // belongs to our mdir? if (file->m.type != LFS_TYPE_REG || lfsr_mdir_cmp(&file->m.mdir, mdir) != 0 @@ -6655,7 +6683,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // stage any bsprouts/bshrubs if (o->type == LFS_TYPE_REG) { - lfsr_file_t *file = (lfsr_file_t*)o; + lfsr_file_t *file = lfsr_opened_file(o); file->bshrub_ = file->bshrub; } } @@ -7091,17 +7119,17 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, o->mdir.mid += attrs[i].delta; // adjust dir position? if (o->type == LFS_TYPE_DIR) { - ((lfsr_dir_t*)o)->pos += attrs[i].delta; + lfsr_opened_dir(o)->pos += attrs[i].delta; } else if (o->type == LFS_TYPE_BOOKMARK) { - ((lfsr_dir_t*)(o-1))->pos -= attrs[i].delta; + lfsr_opened_bookmark(o)->pos -= attrs[i].delta; } } } else if (o->mdir.mid > mid) { // adjust dir position? if (o->type == LFS_TYPE_DIR) { - ((lfsr_dir_t*)o)->pos += attrs[i].delta; + lfsr_opened_dir(o)->pos += attrs[i].delta; } else if (o->type == LFS_TYPE_BOOKMARK) { - ((lfsr_dir_t*)(o-1))->pos -= attrs[i].delta; + lfsr_opened_bookmark(o)->pos -= attrs[i].delta; } } } @@ -7116,7 +7144,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // update any staged bsprouts/bshrubs for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { if (o->type == LFS_TYPE_REG) { - lfsr_file_t *file = (lfsr_file_t*)o; + lfsr_file_t *file = lfsr_opened_file(o); file->bshrub = file->bshrub_; } } @@ -7461,8 +7489,8 @@ typedef struct lfsr_traversal { // we really don't want to pay the RAM cost for a full file, // so only store the relevant bits, is this a hack? yes struct { - lfsr_opened_t m; const struct lfs_file_config *cfg; + lfsr_opened_t m; lfsr_bshrub_t bshrub; } file; lfsr_btraversal_t bt; @@ -7805,7 +7833,7 @@ static int lfsr_traversal_read(lfs_t *lfs, lfsr_traversal_t *t, } // start traversing the file - const lfsr_file_t *file = (const lfsr_file_t*)t->u.o; + const lfsr_file_t *file = lfsr_opened_constfile(t->u.o); t->file.m.mdir = file->m.mdir; t->file.bshrub = file->bshrub; t->bt = LFSR_BTRAVERSAL(); @@ -9972,7 +10000,7 @@ static lfs_ssize_t lfsr_bshrub_estimate(lfs_t *lfs, const lfsr_file_t *file) { // this includes our current shrub for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && file_->m.mdir.mid == file->m.mdir.mid) { if (lfsr_bshrub_isbsprout(&file_->m.mdir, &file_->bshrub)) { @@ -10209,7 +10237,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file, // as unerased if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) { for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && file_ != file && lfsr_bshrub_isbshruborbtree(&file_->bshrub) @@ -10300,7 +10328,7 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file, // update _all_ shrubs with the new estimate for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && file_->m.mdir.mid == file->m.mdir.mid && lfsr_bshrub_isbshrub(&file_->m.mdir, &file_->bshrub)) { @@ -11504,7 +11532,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) { // but do update other file handles for (lfsr_opened_t *o = lfs->opened; o; o = o->next) { - lfsr_file_t *file_ = (lfsr_file_t*)o; + lfsr_file_t *file_ = lfsr_opened_file(o); if (file_->m.type == LFS_TYPE_REG && file_->m.mdir.mid == file->m.mdir.mid // don't double update diff --git a/lfs.h b/lfs.h index 02dcffdf..4070e669 100644 --- a/lfs.h +++ b/lfs.h @@ -510,8 +510,8 @@ typedef struct lfsr_bshrub { } lfsr_bshrub_t; typedef struct lfsr_file { - lfsr_opened_t m; const struct lfs_file_config *cfg; + lfsr_opened_t m; // files contain both an active bshrub and staging bshrub, to allow // staging during mdir compacts