mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +00:00
Changed behavior of buddy allocator to align allocation sizes to power of 2 instead of accounting the remaining space (internal fragmentation) as free
Also fixed major bug in VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode.
This commit is contained in:
parent
c24517fd92
commit
62a25b6b4c
@ -5542,14 +5542,9 @@ private:
|
|||||||
|
|
||||||
struct ValidationContext
|
struct ValidationContext
|
||||||
{
|
{
|
||||||
size_t calculatedAllocationCount;
|
size_t calculatedAllocationCount = 0;
|
||||||
size_t calculatedFreeCount;
|
size_t calculatedFreeCount = 0;
|
||||||
VkDeviceSize calculatedSumFreeSize;
|
VkDeviceSize calculatedSumFreeSize = 0;
|
||||||
|
|
||||||
ValidationContext() :
|
|
||||||
calculatedAllocationCount(0),
|
|
||||||
calculatedFreeCount(0),
|
|
||||||
calculatedSumFreeSize(0) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
@ -5596,7 +5591,8 @@ private:
|
|||||||
size_t m_AllocationCount;
|
size_t m_AllocationCount;
|
||||||
// Number of nodes in the tree with type == TYPE_FREE.
|
// Number of nodes in the tree with type == TYPE_FREE.
|
||||||
size_t m_FreeCount;
|
size_t m_FreeCount;
|
||||||
// This includes space wasted due to internal fragmentation. Doesn't include unusable size.
|
// Doesn't include space wasted due to internal fragmentation - allocation sizes are just aligned up to node sizes.
|
||||||
|
// Doesn't include unusable size.
|
||||||
VkDeviceSize m_SumFreeSize;
|
VkDeviceSize m_SumFreeSize;
|
||||||
|
|
||||||
VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
|
VkDeviceSize GetUnusableSize() const { return GetSize() - m_UsableSize; }
|
||||||
@ -10783,8 +10779,6 @@ VkDeviceSize VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const
|
|||||||
|
|
||||||
void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
|
void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
|
||||||
{
|
{
|
||||||
const VkDeviceSize unusableSize = GetUnusableSize();
|
|
||||||
|
|
||||||
outInfo.blockCount = 1;
|
outInfo.blockCount = 1;
|
||||||
|
|
||||||
outInfo.allocationCount = outInfo.unusedRangeCount = 0;
|
outInfo.allocationCount = outInfo.unusedRangeCount = 0;
|
||||||
@ -10796,6 +10790,7 @@ void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const
|
|||||||
|
|
||||||
CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
|
CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));
|
||||||
|
|
||||||
|
const VkDeviceSize unusableSize = GetUnusableSize();
|
||||||
if(unusableSize > 0)
|
if(unusableSize > 0)
|
||||||
{
|
{
|
||||||
++outInfo.unusedRangeCount;
|
++outInfo.unusedRangeCount;
|
||||||
@ -10826,7 +10821,7 @@ void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const
|
|||||||
|
|
||||||
void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
|
void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const
|
||||||
{
|
{
|
||||||
// TODO optimize
|
// TODO optimize - this was already calculated.
|
||||||
VmaStatInfo stat;
|
VmaStatInfo stat;
|
||||||
CalcAllocationStatInfo(stat);
|
CalcAllocationStatInfo(stat);
|
||||||
|
|
||||||
@ -10930,6 +10925,8 @@ void VmaBlockMetadata_Buddy::Alloc(
|
|||||||
VkDeviceSize allocSize,
|
VkDeviceSize allocSize,
|
||||||
void* userData)
|
void* userData)
|
||||||
{
|
{
|
||||||
|
allocSize = VmaNextPow2(allocSize);
|
||||||
|
|
||||||
VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
|
VMA_ASSERT(request.type == VmaAllocationRequestType::Normal);
|
||||||
|
|
||||||
const uint32_t targetLevel = AllocSizeToLevel(allocSize);
|
const uint32_t targetLevel = AllocSizeToLevel(allocSize);
|
||||||
@ -10981,7 +10978,7 @@ void VmaBlockMetadata_Buddy::Alloc(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
We can be sure that currNode, as left child of node previously split,
|
We can be sure that currNode, as left child of node previously split,
|
||||||
also fullfills the alignment requirement.
|
also fulfills the alignment requirement.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11042,8 +11039,10 @@ bool VmaBlockMetadata_Buddy::ValidateNode(ValidationContext& ctx, const Node* pa
|
|||||||
break;
|
break;
|
||||||
case Node::TYPE_ALLOCATION:
|
case Node::TYPE_ALLOCATION:
|
||||||
++ctx.calculatedAllocationCount;
|
++ctx.calculatedAllocationCount;
|
||||||
|
if(!IsVirtual())
|
||||||
|
{
|
||||||
VMA_VALIDATE(curr->allocation.userData != VMA_NULL);
|
VMA_VALIDATE(curr->allocation.userData != VMA_NULL);
|
||||||
ctx.calculatedSumFreeSize += levelNodeSize - ((VmaAllocation)(curr->allocation.userData))->GetSize();
|
}
|
||||||
break;
|
break;
|
||||||
case Node::TYPE_SPLIT:
|
case Node::TYPE_SPLIT:
|
||||||
{
|
{
|
||||||
@ -11118,7 +11117,7 @@ void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation allocForValidation, VkDe
|
|||||||
|
|
||||||
++m_FreeCount;
|
++m_FreeCount;
|
||||||
--m_AllocationCount;
|
--m_AllocationCount;
|
||||||
m_SumFreeSize += alloc->GetSize();
|
m_SumFreeSize += levelNodeSize;
|
||||||
|
|
||||||
node->type = Node::TYPE_FREE;
|
node->type = Node::TYPE_FREE;
|
||||||
|
|
||||||
@ -11143,32 +11142,19 @@ void VmaBlockMetadata_Buddy::FreeAtOffset(VmaAllocation allocForValidation, VkDe
|
|||||||
|
|
||||||
void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
|
void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const
|
||||||
{
|
{
|
||||||
VMA_ASSERT(!IsVirtual()); // TODO
|
|
||||||
switch(node->type)
|
switch(node->type)
|
||||||
{
|
{
|
||||||
case Node::TYPE_FREE:
|
case Node::TYPE_FREE:
|
||||||
++outInfo.unusedRangeCount;
|
++outInfo.unusedRangeCount;
|
||||||
outInfo.unusedBytes += levelNodeSize;
|
outInfo.unusedBytes += levelNodeSize;
|
||||||
outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
|
outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);
|
||||||
outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, levelNodeSize);
|
outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, levelNodeSize);
|
||||||
break;
|
break;
|
||||||
case Node::TYPE_ALLOCATION:
|
case Node::TYPE_ALLOCATION:
|
||||||
{
|
|
||||||
const VkDeviceSize allocSize = ((VmaAllocation)(node->allocation.userData))->GetSize();
|
|
||||||
++outInfo.allocationCount;
|
++outInfo.allocationCount;
|
||||||
outInfo.usedBytes += allocSize;
|
outInfo.usedBytes += levelNodeSize;
|
||||||
outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, allocSize);
|
outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, levelNodeSize);
|
||||||
outInfo.allocationSizeMin = VMA_MAX(outInfo.allocationSizeMin, allocSize);
|
outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, levelNodeSize);
|
||||||
|
|
||||||
const VkDeviceSize unusedRangeSize = levelNodeSize - allocSize;
|
|
||||||
if(unusedRangeSize > 0)
|
|
||||||
{
|
|
||||||
++outInfo.unusedRangeCount;
|
|
||||||
outInfo.unusedBytes += unusedRangeSize;
|
|
||||||
outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);
|
|
||||||
outInfo.unusedRangeSizeMin = VMA_MAX(outInfo.unusedRangeSizeMin, unusedRangeSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Node::TYPE_SPLIT:
|
case Node::TYPE_SPLIT:
|
||||||
{
|
{
|
||||||
@ -11240,22 +11226,13 @@ void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
|
|||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
|
void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const
|
||||||
{
|
{
|
||||||
VMA_ASSERT(!IsVirtual()); // TODO
|
|
||||||
switch(node->type)
|
switch(node->type)
|
||||||
{
|
{
|
||||||
case Node::TYPE_FREE:
|
case Node::TYPE_FREE:
|
||||||
PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
|
PrintDetailedMap_UnusedRange(json, node->offset, levelNodeSize);
|
||||||
break;
|
break;
|
||||||
case Node::TYPE_ALLOCATION:
|
case Node::TYPE_ALLOCATION:
|
||||||
{
|
PrintDetailedMap_Allocation(json, node->offset, levelNodeSize, node->allocation.userData);
|
||||||
VmaAllocation const alloc = (VmaAllocation)node->allocation.userData;
|
|
||||||
const VkDeviceSize allocSize = alloc->GetSize();
|
|
||||||
PrintDetailedMap_Allocation(json, node->offset, allocSize, node->allocation.userData);
|
|
||||||
if(allocSize < levelNodeSize)
|
|
||||||
{
|
|
||||||
PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Node::TYPE_SPLIT:
|
case Node::TYPE_SPLIT:
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user