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 <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
Augustin Cavalier 2024-09-02 16:17:11 -04:00 committed by waddlesplash
parent 6e690f7d11
commit 87a66be550

View File

@ -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++;
}