From 04d3002f3a9e4b6c61e3d9504b0d31140adeb6d0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 16 Apr 2025 23:42:15 -0500 Subject: [PATCH] Adopted ceiling division in mbits formula So now: (block_size) mbits = nlog2(----------) = nlog2(block_size) - 3 ( 8 ) Instead of: ( (block_size)) mbits = nlog2(floor(----------)) = nlog2(block_size & ~0x7) - 3 ( ( 8 )) This makes the post-log - 3 formula simpler, which we probably want to prefer as it avoids a division. And ceiling is arguably more intuitive corner case behavior. This may seem like a minor detail, but because mbits is purely block_size derived and not configurable, any quirks here will become a permanent compatibility requirement. And hey, it saves a couple bytes (I'm not really sure why, the division should've been optimized to a shift): code stack ctx before: 35528 2440 636 after: 35520 (-0.0%) 2440 (+0.0%) 636 (+0.0%) --- lfs.c | 27 ++++++++++++++++++--------- scripts/dbgbmap.py | 2 +- scripts/dbgbmapd3.py | 2 +- scripts/dbglfs.py | 2 +- scripts/dbgmtree.py | 2 +- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lfs.c b/lfs.c index f75609ed..253946e8 100644 --- a/lfs.c +++ b/lfs.c @@ -13160,31 +13160,40 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, // calculate the number of bits we need to reserve for mdir rids // // Worst case (or best case?) each metadata entry is a single tag. In - // theory each entry also needs a name, but with power-of-two rounding, - // this is negligible + // theory each entry also needs a did+name, but with power-of-two + // rounding, this is negligible // // Assuming a _perfect_ compaction algorithm (requires unbounded RAM), // each tag also needs ~1 alt, this gives us: // - // block_size block_size - // m = ---------- = ---------- - // a_inf 2t + // block_size block_size + // mrids = ---------- = ---------- + // a_inf 2t // // Assuming t=4 bytes, the minimum tag encoding: // - // block_size block_size - // m = ---------- = ---------- - // 2*4 8 + // block_size block_size + // mrids = ---------- = ---------- + // 2*4 8 // // Note we can't assume ~1/2 block utilization here, as an mdir may // temporarily fill with more mids before compaction occurs. // + // Rounding up to the nearest power of two: + // + // (block_size) + // mbits = nlog2(----------) = nlog2(block_size) - 3 + // ( 8 ) + // + // Note if you divide before the nlog2, make sure to use ceiling + // division for compatibility if block_size is not aligned to 8 bytes. + // // Note note our actual compaction algorithm is not perfect, and // requires 3t+4 bytes per tag, or with t=4 bytes => ~block_size/12 // metadata entries per block. But we intentionally don't leverage this // to maintain compatibility with a theoretical perfect implementation. // - lfs->mdir_bits = lfs_nlog2(lfs->cfg->block_size/8); + lfs->mdir_bits = lfs_nlog2(lfs->cfg->block_size) - 3; // zero linked-list of opened mdirs lfs->omdirs = NULL; diff --git a/scripts/dbgbmap.py b/scripts/dbgbmap.py index 13a2c546..eb106b83 100755 --- a/scripts/dbgbmap.py +++ b/scripts/dbgbmap.py @@ -1633,7 +1633,7 @@ class Mtree: def mbits_(block_size): if isinstance(block_size, Bd): block_size = block_size.block_size - return mt.ceil(mt.log2(block_size // 8)) + return mt.ceil(mt.log2(block_size)) - 3 # convenience function for creating mbits-dependent mids def mid(self, mbid, mrid=None): diff --git a/scripts/dbgbmapd3.py b/scripts/dbgbmapd3.py index fdc1288a..3fdced08 100755 --- a/scripts/dbgbmapd3.py +++ b/scripts/dbgbmapd3.py @@ -1663,7 +1663,7 @@ class Mtree: def mbits_(block_size): if isinstance(block_size, Bd): block_size = block_size.block_size - return mt.ceil(mt.log2(block_size // 8)) + return mt.ceil(mt.log2(block_size)) - 3 # convenience function for creating mbits-dependent mids def mid(self, mbid, mrid=None): diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index 13fc5d85..13d1a1cd 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -1590,7 +1590,7 @@ class Mtree: def mbits_(block_size): if isinstance(block_size, Bd): block_size = block_size.block_size - return mt.ceil(mt.log2(block_size // 8)) + return mt.ceil(mt.log2(block_size)) - 3 # convenience function for creating mbits-dependent mids def mid(self, mbid, mrid=None): diff --git a/scripts/dbgmtree.py b/scripts/dbgmtree.py index 0fb53070..aa474dda 100755 --- a/scripts/dbgmtree.py +++ b/scripts/dbgmtree.py @@ -1556,7 +1556,7 @@ class Mtree: def mbits_(block_size): if isinstance(block_size, Bd): block_size = block_size.block_size - return mt.ceil(mt.log2(block_size // 8)) + return mt.ceil(mt.log2(block_size)) - 3 # convenience function for creating mbits-dependent mids def mid(self, mbid, mrid=None):