From 87a66be5501b1025a680290b7425bfddee8a50fe Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 2 Sep 2024 16:17:11 -0400 Subject: [PATCH] BFS: Optimize the search for the next free block. We already started at the first-free in the block bitmap, but after that we would just check individual bits as we went along. Now we skip forwards to the next free block when encountering a used block, by comparing to UINT32_MAX (all blocks used) and using ffs() with a bitwise NOT (to find the first unused block in a chunk.) This will benefit fragmented partitions more than non-fragmented ones. I didn't see a significant speedup on my compile benchmark in a VM. Fixes #18929. X512 tested this patch and confirmed it reduces CPU usage on a partition that he saw long times spent in AllocateBlocks on. Change-Id: If71b5e24c585c2cc08879c8aefc80af8ae7da91f Reviewed-on: https://review.haiku-os.org/c/haiku/+/8186 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- .../file_systems/bfs/BlockAllocator.cpp | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index 5c070c223f..34bacc0bc9 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -174,6 +174,7 @@ public: inline void Allocate(uint16 start, uint16 numBlocks); inline void Free(uint16 start, uint16 numBlocks); inline bool IsUsed(uint16 block); + inline uint32 NextFree(uint16 startBlock); status_t SetTo(AllocationGroup& group, uint16 block); status_t SetToWritable(Transaction& transaction, AllocationGroup& group, @@ -270,6 +271,30 @@ AllocationBlock::IsUsed(uint16 block) } +uint32 +AllocationBlock::NextFree(uint16 startBlock) +{ + // Set all bits below the start block in the current chunk, to ignore them. + uint32 ignoreNext = (1UL << (startBlock % 32)) - 1; + + for (uint32 offset = ROUNDDOWN(startBlock, 32); + offset < fNumBits; offset += 32) { + uint32 chunk = Chunk(offset >> 5); + chunk |= ignoreNext; + ignoreNext = 0; + + if (chunk == UINT32_MAX) + continue; + uint32 result = offset + ffs(~chunk) - 1; + if (result >= fNumBits) + break; + return result; + } + + return fNumBits; +} + + void AllocationBlock::Allocate(uint16 start, uint16 numBlocks) { @@ -838,6 +863,12 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, int32 groupIndex, block = group.NumBitmapBlocks(); break; } + + // Advance the current bit to one before the next free (or last) bit, + // so that the next loop iteration will check the next free bit. + const uint32 nextFreeOffset = cached.NextFree(bit) - bit; + bit += nextFreeOffset - 1; + currentBit += nextFreeOffset - 1; } currentBit++; }