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 <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
6e690f7d11
commit
87a66be550
@@ -174,6 +174,7 @@ public:
|
|||||||
inline void Allocate(uint16 start, uint16 numBlocks);
|
inline void Allocate(uint16 start, uint16 numBlocks);
|
||||||
inline void Free(uint16 start, uint16 numBlocks);
|
inline void Free(uint16 start, uint16 numBlocks);
|
||||||
inline bool IsUsed(uint16 block);
|
inline bool IsUsed(uint16 block);
|
||||||
|
inline uint32 NextFree(uint16 startBlock);
|
||||||
|
|
||||||
status_t SetTo(AllocationGroup& group, uint16 block);
|
status_t SetTo(AllocationGroup& group, uint16 block);
|
||||||
status_t SetToWritable(Transaction& transaction, AllocationGroup& group,
|
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
|
void
|
||||||
AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
|
AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
|
||||||
{
|
{
|
||||||
@@ -838,6 +863,12 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, int32 groupIndex,
|
|||||||
block = group.NumBitmapBlocks();
|
block = group.NumBitmapBlocks();
|
||||||
break;
|
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++;
|
currentBit++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user