Implemented vmaBuildVirtualBlockStatsString, vmaFreeVirtualBlockStatsString

This commit is contained in:
Adam Sawicki 2021-10-28 17:00:17 +02:00
parent dfa2051cd2
commit c6432507c5
2 changed files with 121 additions and 64 deletions

View File

@ -3279,10 +3279,19 @@ static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char
memcpy(result, srcStr, len + 1); memcpy(result, srcStr, len + 1);
return result; return result;
} }
else return VMA_NULL;
}
static char* VmaCreateStringCopy(const VkAllocationCallbacks* allocs, const char* srcStr, size_t strLen)
{
if(srcStr != VMA_NULL)
{ {
return VMA_NULL; char* const result = vma_new_array(allocs, char, strLen + 1);
memcpy(result, srcStr, strLen);
result[strLen] = '\0';
return result;
} }
return VMA_NULL;
} }
static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str) static void VmaFreeString(const VkAllocationCallbacks* allocs, char* str)
@ -5121,8 +5130,7 @@ protected:
size_t allocationCount, size_t allocationCount,
size_t unusedRangeCount) const; size_t unusedRangeCount) const;
void PrintDetailedMap_Allocation(class VmaJsonWriter& json, void PrintDetailedMap_Allocation(class VmaJsonWriter& json,
VkDeviceSize offset, VkDeviceSize offset, VkDeviceSize size, void* userData) const;
VmaAllocation hAllocation) const;
void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json, void PrintDetailedMap_UnusedRange(class VmaJsonWriter& json,
VkDeviceSize offset, VkDeviceSize offset,
VkDeviceSize size) const; VkDeviceSize size) const;
@ -6852,6 +6860,37 @@ private:
#endif // #if VMA_MEMORY_BUDGET #endif // #if VMA_MEMORY_BUDGET
}; };
class VmaStringBuilder;
static void InitStatInfo(VmaStatInfo& outInfo)
{
memset(&outInfo, 0, sizeof(outInfo));
outInfo.allocationSizeMin = UINT64_MAX;
outInfo.unusedRangeSizeMin = UINT64_MAX;
}
// Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
{
inoutInfo.blockCount += srcInfo.blockCount;
inoutInfo.allocationCount += srcInfo.allocationCount;
inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
inoutInfo.usedBytes += srcInfo.usedBytes;
inoutInfo.unusedBytes += srcInfo.unusedBytes;
inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
}
static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
{
inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
}
struct VmaVirtualBlock_T struct VmaVirtualBlock_T
{ {
VMA_CLASS_NO_COPY(VmaVirtualBlock_T) VMA_CLASS_NO_COPY(VmaVirtualBlock_T)
@ -6894,7 +6933,11 @@ public:
void CalculateStats(VmaStatInfo& outStatInfo) const void CalculateStats(VmaStatInfo& outStatInfo) const
{ {
m_Metadata->CalcAllocationStatInfo(outStatInfo); m_Metadata->CalcAllocationStatInfo(outStatInfo);
VmaPostprocessCalcStatInfo(outStatInfo);
} }
#if VMA_STATS_STRING_ENABLED
void BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const;
#endif
private: private:
VmaBlockMetadata* m_Metadata; VmaBlockMetadata* m_Metadata;
@ -6954,7 +6997,7 @@ static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
class VmaStringBuilder class VmaStringBuilder
{ {
public: public:
VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { } VmaStringBuilder(const VkAllocationCallbacks* allocationCallbacks) : m_Data(VmaStlAllocator<char>(allocationCallbacks)) { }
size_t GetLength() const { return m_Data.size(); } size_t GetLength() const { return m_Data.size(); }
const char* GetData() const { return m_Data.data(); } const char* GetData() const { return m_Data.data(); }
@ -7701,15 +7744,33 @@ void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
} }
void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json, void VmaBlockMetadata::PrintDetailedMap_Allocation(class VmaJsonWriter& json,
VkDeviceSize offset, VkDeviceSize offset, VkDeviceSize size, void* userData) const
VmaAllocation hAllocation) const
{ {
json.BeginObject(true); json.BeginObject(true);
json.WriteString("Offset"); json.WriteString("Offset");
json.WriteNumber(offset); json.WriteNumber(offset);
hAllocation->PrintParameters(json); if(IsVirtual())
{
json.WriteString("Type");
json.WriteString("VirtualAllocation");
json.WriteString("Size");
json.WriteNumber(size);
if(userData != VMA_NULL)
{
json.WriteString("UserData");
json.BeginString();
json.ContinueString_Pointer(userData);
json.EndString();
}
}
else
{
((VmaAllocation)userData)->PrintParameters(json);
}
json.EndObject(); json.EndObject();
} }
@ -7934,8 +7995,7 @@ void VmaBlockMetadata_Generic::PrintDetailedMap(class VmaJsonWriter& json) const
} }
else else
{ {
VMA_ASSERT(!IsVirtual()); // TODO? PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
PrintDetailedMap_Allocation(json, suballoc.offset, (VmaAllocation)suballoc.userData);
} }
} }
@ -9575,7 +9635,7 @@ void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
// 2. Process this allocation. // 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size. // There is allocation with suballoc.offset, suballoc.size.
PrintDetailedMap_Allocation(json, suballoc.offset, (VmaAllocation)suballoc.userData); PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
// 3. Prepare for next iteration. // 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size; lastOffset = suballoc.offset + suballoc.size;
@ -9622,7 +9682,7 @@ void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
// 2. Process this allocation. // 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size. // There is allocation with suballoc.offset, suballoc.size.
PrintDetailedMap_Allocation(json, suballoc.offset, (VmaAllocation)suballoc.userData); PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
// 3. Prepare for next iteration. // 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size; lastOffset = suballoc.offset + suballoc.size;
@ -9670,7 +9730,7 @@ void VmaBlockMetadata_Linear::PrintDetailedMap(class VmaJsonWriter& json) const
// 2. Process this allocation. // 2. Process this allocation.
// There is allocation with suballoc.offset, suballoc.size. // There is allocation with suballoc.offset, suballoc.size.
PrintDetailedMap_Allocation(json, suballoc.offset, (VmaAllocation)suballoc.userData); PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
// 3. Prepare for next iteration. // 3. Prepare for next iteration.
lastOffset = suballoc.offset + suballoc.size; lastOffset = suballoc.offset + suballoc.size;
@ -11123,8 +11183,8 @@ void VmaBlockMetadata_Buddy::PrintDetailedMapNode(class VmaJsonWriter& json, con
case Node::TYPE_ALLOCATION: case Node::TYPE_ALLOCATION:
{ {
VmaAllocation const alloc = (VmaAllocation)node->allocation.userData; VmaAllocation const alloc = (VmaAllocation)node->allocation.userData;
PrintDetailedMap_Allocation(json, node->offset, alloc);
const VkDeviceSize allocSize = alloc->GetSize(); const VkDeviceSize allocSize = alloc->GetSize();
PrintDetailedMap_Allocation(json, node->offset, allocSize, node->allocation.userData);
if(allocSize < levelNodeSize) if(allocSize < levelNodeSize)
{ {
PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize); PrintDetailedMap_UnusedRange(json, node->offset + allocSize, levelNodeSize - allocSize);
@ -11376,35 +11436,6 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory(
return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext);
} }
static void InitStatInfo(VmaStatInfo& outInfo)
{
memset(&outInfo, 0, sizeof(outInfo));
outInfo.allocationSizeMin = UINT64_MAX;
outInfo.unusedRangeSizeMin = UINT64_MAX;
}
// Adds statistics srcInfo into inoutInfo, like: inoutInfo += srcInfo.
static void VmaAddStatInfo(VmaStatInfo& inoutInfo, const VmaStatInfo& srcInfo)
{
inoutInfo.blockCount += srcInfo.blockCount;
inoutInfo.allocationCount += srcInfo.allocationCount;
inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
inoutInfo.usedBytes += srcInfo.usedBytes;
inoutInfo.unusedBytes += srcInfo.unusedBytes;
inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
}
static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
{
inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
}
VmaPool_T::VmaPool_T( VmaPool_T::VmaPool_T(
VmaAllocator hAllocator, VmaAllocator hAllocator,
const VmaPoolCreateInfo& createInfo, const VmaPoolCreateInfo& createInfo,
@ -16713,6 +16744,28 @@ VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& creat
return VK_ERROR_OUT_OF_DEVICE_MEMORY; return VK_ERROR_OUT_OF_DEVICE_MEMORY;
} }
#if VMA_STATS_STRING_ENABLED
void VmaVirtualBlock_T::BuildStatsString(bool detailedMap, VmaStringBuilder& sb) const
{
VmaJsonWriter json(GetAllocationCallbacks(), sb);
json.BeginObject();
VmaStatInfo stat = {};
CalculateStats(stat);
json.WriteString("Stats");
VmaPrintStatInfo(json, stat);
if(detailedMap)
{
json.WriteString("Details");
m_Metadata->PrintDetailedMap(json);
}
json.EndObject();
}
#endif // #if VMA_STATS_STRING_ENABLED
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Public interface // Public interface
@ -16819,7 +16872,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
VMA_ASSERT(allocator && ppStatsString); VMA_ASSERT(allocator && ppStatsString);
VMA_DEBUG_GLOBAL_MUTEX_LOCK VMA_DEBUG_GLOBAL_MUTEX_LOCK
VmaStringBuilder sb(allocator); VmaStringBuilder sb(allocator->GetAllocationCallbacks());
{ {
VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb); VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
json.BeginObject(); json.BeginObject();
@ -16942,14 +16995,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString(
json.EndObject(); json.EndObject();
} }
const size_t len = sb.GetLength(); *ppStatsString = VmaCreateStringCopy(allocator->GetAllocationCallbacks(), sb.GetData(), sb.GetLength());
char* const pChars = vma_new_array(allocator, char, len + 1);
if(len > 0)
{
memcpy(pChars, sb.GetData(), len);
}
pChars[len] = '\0';
*ppStatsString = pChars;
} }
VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
@ -16959,8 +17005,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString(
if(pStatsString != VMA_NULL) if(pStatsString != VMA_NULL)
{ {
VMA_ASSERT(allocator); VMA_ASSERT(allocator);
size_t len = strlen(pStatsString); VmaFreeString(allocator->GetAllocationCallbacks(), pStatsString);
vma_delete_array(allocator, pStatsString, len + 1);
} }
} }
@ -18431,16 +18476,30 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStats(VmaVirtualBlock VM
virtualBlock->CalculateStats(*pStatInfo); virtualBlock->CalculateStats(*pStatInfo);
} }
#if VMA_STATS_STRING_ENABLED
VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap)
{ {
VMA_ASSERT(0 && "TODO implement"); VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && ppStatsString != VMA_NULL);
VMA_DEBUG_GLOBAL_MUTEX_LOCK;
const VkAllocationCallbacks* allocationCallbacks = virtualBlock->GetAllocationCallbacks();
VmaStringBuilder sb(allocationCallbacks);
virtualBlock->BuildStatsString(detailedMap != VK_FALSE, sb);
*ppStatsString = VmaCreateStringCopy(allocationCallbacks, sb.GetData(), sb.GetLength());
} }
#endif // #if VMA_STATS_STRING_ENABLED
VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
char* VMA_NULLABLE pStatsString) char* VMA_NULLABLE pStatsString)
{ {
VMA_ASSERT(0 && "TODO implement"); if(pStatsString != VMA_NULL)
{
VMA_ASSERT(virtualBlock != VK_NULL_HANDLE);
VMA_DEBUG_GLOBAL_MUTEX_LOCK;
VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString);
}
} }
#endif // #ifdef VMA_IMPLEMENTATION #endif // #ifdef VMA_IMPLEMENTATION

View File

@ -2756,18 +2756,16 @@ static void TestVirtualBlocks()
TEST(statInfo.usedBytes == blockSize); TEST(statInfo.usedBytes == blockSize);
TEST(statInfo.unusedBytes + statInfo.usedBytes == blockSize); TEST(statInfo.unusedBytes + statInfo.usedBytes == blockSize);
#if 0
// # Generate JSON dump // # Generate JSON dump
WCHAR* json = nullptr; char* json = nullptr;
block->BuildStatsString(&json); vmaBuildVirtualBlockStatsString(block, &json, VK_TRUE);
{ {
std::wstring str(json); std::string str(json);
CHECK_BOOL( str.find(L"\"UserData\": 1") != std::wstring::npos ); TEST( str.find("\"UserData\": \"0000000000000001\"") != std::string::npos );
CHECK_BOOL( str.find(L"\"UserData\": 2") != std::wstring::npos ); TEST( str.find("\"UserData\": \"0000000000000002\"") != std::string::npos );
} }
block->FreeStatsString(json); vmaFreeVirtualBlockStatsString(block, json);
#endif
// # Free alloc0, leave alloc2 unfreed. // # Free alloc0, leave alloc2 unfreed.