mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-22 23:04:35 +00:00
Added debug printing of unfreed allocation
Closes #130 Also made fixes for compilation errors on Android - see #223 Code by @medranSolus
This commit is contained in:
parent
f88a69ba1c
commit
12d128d8f7
@ -2387,7 +2387,7 @@ VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty(
|
|||||||
*/
|
*/
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(
|
VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(
|
||||||
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
||||||
VmaVirtualAllocation VMA_NOT_NULL allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo);
|
VmaVirtualAllocation allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo);
|
||||||
|
|
||||||
/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock.
|
/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock.
|
||||||
|
|
||||||
@ -2412,7 +2412,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(
|
|||||||
*/
|
*/
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(
|
VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(
|
||||||
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
||||||
VmaVirtualAllocation VMA_NULLABLE allocation);
|
VmaVirtualAllocation allocation);
|
||||||
|
|
||||||
/** \brief Frees all virtual allocations inside given #VmaVirtualBlock.
|
/** \brief Frees all virtual allocations inside given #VmaVirtualBlock.
|
||||||
|
|
||||||
@ -2429,7 +2429,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock(
|
|||||||
*/
|
*/
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(
|
VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(
|
||||||
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
||||||
VmaVirtualAllocation VMA_NOT_NULL allocation,
|
VmaVirtualAllocation allocation,
|
||||||
void* VMA_NULLABLE pUserData);
|
void* VMA_NULLABLE pUserData);
|
||||||
|
|
||||||
/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock.
|
/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock.
|
||||||
@ -5997,12 +5997,14 @@ public:
|
|||||||
virtual void Clear() = 0;
|
virtual void Clear() = 0;
|
||||||
|
|
||||||
virtual void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) = 0;
|
virtual void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) = 0;
|
||||||
|
virtual void DebugLogAllAllocations() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
|
const VkAllocationCallbacks* GetAllocationCallbacks() const { return m_pAllocationCallbacks; }
|
||||||
VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
|
VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }
|
||||||
VkDeviceSize GetDebugMargin() const { return IsVirtual() ? 0 : VMA_DEBUG_MARGIN; }
|
VkDeviceSize GetDebugMargin() const { return IsVirtual() ? 0 : VMA_DEBUG_MARGIN; }
|
||||||
|
|
||||||
|
void DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const;
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
void PrintDetailedMap_Begin(class VmaJsonWriter& json,
|
void PrintDetailedMap_Begin(class VmaJsonWriter& json,
|
||||||
VkDeviceSize unusedBytes,
|
VkDeviceSize unusedBytes,
|
||||||
@ -6031,6 +6033,36 @@ VmaBlockMetadata::VmaBlockMetadata(const VkAllocationCallbacks* pAllocationCallb
|
|||||||
m_BufferImageGranularity(bufferImageGranularity),
|
m_BufferImageGranularity(bufferImageGranularity),
|
||||||
m_IsVirtual(isVirtual) {}
|
m_IsVirtual(isVirtual) {}
|
||||||
|
|
||||||
|
void VmaBlockMetadata::DebugLogAllocation(VkDeviceSize offset, VkDeviceSize size, void* userData) const
|
||||||
|
{
|
||||||
|
if (IsVirtual())
|
||||||
|
{
|
||||||
|
VMA_DEBUG_LOG("UNFREED VIRTUAL ALLOCATION; Offset: %llu; Size: %llu; UserData: %p", offset, size, userData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VMA_ASSERT(userData != VMA_NULL);
|
||||||
|
VmaAllocation allocation = reinterpret_cast<VmaAllocation>(userData);
|
||||||
|
|
||||||
|
userData = allocation->GetUserData();
|
||||||
|
if (userData != VMA_NULL && allocation->IsUserDataString())
|
||||||
|
{
|
||||||
|
VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %s; Type: %s; Usage: %u",
|
||||||
|
offset, size, reinterpret_cast<const char*>(userData),
|
||||||
|
VMA_SUBALLOCATION_TYPE_NAMES[allocation->GetSuballocationType()],
|
||||||
|
allocation->GetBufferImageUsage());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VMA_DEBUG_LOG("UNFREED ALLOCATION; Offset: %llu; Size: %llu; UserData: %p; Type: %s; Usage: %u",
|
||||||
|
offset, size, userData,
|
||||||
|
VMA_SUBALLOCATION_TYPE_NAMES[allocation->GetSuballocationType()],
|
||||||
|
allocation->GetBufferImageUsage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
|
void VmaBlockMetadata::PrintDetailedMap_Begin(class VmaJsonWriter& json,
|
||||||
VkDeviceSize unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
|
VkDeviceSize unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
|
||||||
@ -6391,6 +6423,7 @@ public:
|
|||||||
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
||||||
|
void DebugLogAllAllocations() const override;
|
||||||
|
|
||||||
// For defragmentation
|
// For defragmentation
|
||||||
bool IsBufferImageGranularityConflictPossible(
|
bool IsBufferImageGranularityConflictPossible(
|
||||||
@ -6808,6 +6841,15 @@ void VmaBlockMetadata_Generic::SetAllocationUserData(VmaAllocHandle allocHandle,
|
|||||||
suballoc.userData = userData;
|
suballoc.userData = userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VmaBlockMetadata_Generic::DebugLogAllAllocations() const
|
||||||
|
{
|
||||||
|
for (const auto& suballoc : m_Suballocations)
|
||||||
|
{
|
||||||
|
if (suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
|
DebugLogAllocation(suballoc.offset, suballoc.size, suballoc.userData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VmaSuballocationList::iterator VmaBlockMetadata_Generic::FindAtOffset(VkDeviceSize offset)
|
VmaSuballocationList::iterator VmaBlockMetadata_Generic::FindAtOffset(VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
VMA_HEAVY_ASSERT(!m_Suballocations.empty());
|
VMA_HEAVY_ASSERT(!m_Suballocations.empty());
|
||||||
@ -7231,6 +7273,7 @@ public:
|
|||||||
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
||||||
|
void DebugLogAllAllocations() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
@ -8357,6 +8400,19 @@ void VmaBlockMetadata_Linear::SetAllocationUserData(VmaAllocHandle allocHandle,
|
|||||||
suballoc.userData = userData;
|
suballoc.userData = userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VmaBlockMetadata_Linear::DebugLogAllAllocations() const
|
||||||
|
{
|
||||||
|
const SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
||||||
|
for (auto it = suballocations1st.begin() + m_1stNullItemsBeginCount; it != suballocations1st.end(); ++it)
|
||||||
|
if (it->type != VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
|
DebugLogAllocation(it->offset, it->size, it->userData);
|
||||||
|
|
||||||
|
const SuballocationVectorType& suballocations2nd = AccessSuballocations2nd();
|
||||||
|
for (auto it = suballocations2nd.begin(); it != suballocations2nd.end(); ++it)
|
||||||
|
if (it->type != VMA_SUBALLOCATION_TYPE_FREE)
|
||||||
|
DebugLogAllocation(it->offset, it->size, it->userData);
|
||||||
|
}
|
||||||
|
|
||||||
VmaSuballocation& VmaBlockMetadata_Linear::FindSuballocation(VkDeviceSize offset)
|
VmaSuballocation& VmaBlockMetadata_Linear::FindSuballocation(VkDeviceSize offset)
|
||||||
{
|
{
|
||||||
SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
SuballocationVectorType& suballocations1st = AccessSuballocations1st();
|
||||||
@ -8840,6 +8896,7 @@ public:
|
|||||||
bool IsEmpty() const override { return m_Root->type == Node::TYPE_FREE; }
|
bool IsEmpty() const override { return m_Root->type == Node::TYPE_FREE; }
|
||||||
VkResult CheckCorruption(const void* pBlockData) override { return VK_ERROR_FEATURE_NOT_PRESENT; }
|
VkResult CheckCorruption(const void* pBlockData) override { return VK_ERROR_FEATURE_NOT_PRESENT; }
|
||||||
VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle; };
|
VkDeviceSize GetAllocationOffset(VmaAllocHandle allocHandle) const override { return (VkDeviceSize)allocHandle; };
|
||||||
|
void DebugLogAllAllocations() const override { DebugLogAllAllocationNode(m_Root, 0); }
|
||||||
|
|
||||||
void Init(VkDeviceSize size) override;
|
void Init(VkDeviceSize size) override;
|
||||||
bool Validate() const override;
|
bool Validate() const override;
|
||||||
@ -8952,6 +9009,7 @@ private:
|
|||||||
// node->type must be FREE.
|
// node->type must be FREE.
|
||||||
// node->free.prev, next stay untouched.
|
// node->free.prev, next stay untouched.
|
||||||
void RemoveFromFreeList(uint32_t level, Node* node);
|
void RemoveFromFreeList(uint32_t level, Node* node);
|
||||||
|
void DebugLogAllAllocationNode(Node* node, uint32_t level) const;
|
||||||
|
|
||||||
#if VMA_STATS_STRING_ENABLED
|
#if VMA_STATS_STRING_ENABLED
|
||||||
void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
|
void PrintDetailedMapNode(class VmaJsonWriter& json, const Node* node, VkDeviceSize levelNodeSize) const;
|
||||||
@ -9453,6 +9511,25 @@ void VmaBlockMetadata_Buddy::RemoveFromFreeList(uint32_t level, Node* node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VmaBlockMetadata_Buddy::DebugLogAllAllocationNode(Node* node, uint32_t level) const
|
||||||
|
{
|
||||||
|
switch (node->type)
|
||||||
|
{
|
||||||
|
case Node::TYPE_ALLOCATION:
|
||||||
|
DebugLogAllocation(node->offset, LevelToNodeSize(level), node->allocation.userData);
|
||||||
|
break;
|
||||||
|
case Node::TYPE_SPLIT:
|
||||||
|
{
|
||||||
|
++level;
|
||||||
|
DebugLogAllAllocationNode(node->split.leftChild, level);
|
||||||
|
DebugLogAllAllocationNode(node->split.leftChild->buddy, level);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VMA_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#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
|
||||||
{
|
{
|
||||||
@ -9525,6 +9602,7 @@ public:
|
|||||||
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
void GetAllocationInfo(VmaAllocHandle allocHandle, VmaVirtualAllocationInfo& outInfo) override;
|
||||||
void Clear() override;
|
void Clear() override;
|
||||||
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
void SetAllocationUserData(VmaAllocHandle allocHandle, void* userData) override;
|
||||||
|
void DebugLogAllAllocations() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// According to original paper it should be preferable 4 or 5:
|
// According to original paper it should be preferable 4 or 5:
|
||||||
@ -10086,6 +10164,13 @@ void VmaBlockMetadata_TLSF::SetAllocationUserData(VmaAllocHandle allocHandle, vo
|
|||||||
block->UserData() = userData;
|
block->UserData() = userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VmaBlockMetadata_TLSF::DebugLogAllAllocations() const
|
||||||
|
{
|
||||||
|
for (Block* block = m_NullBlock->prevPhysical; block != VMA_NULL; block = block->prevPhysical)
|
||||||
|
if (!block->IsFree())
|
||||||
|
DebugLogAllocation(block->offset, block->size, block->UserData());
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t VmaBlockMetadata_TLSF::SizeToMemoryClass(VkDeviceSize size) const
|
uint8_t VmaBlockMetadata_TLSF::SizeToMemoryClass(VkDeviceSize size) const
|
||||||
{
|
{
|
||||||
if (size > SMALL_BUFFER_SIZE)
|
if (size > SMALL_BUFFER_SIZE)
|
||||||
@ -10891,7 +10976,10 @@ VmaVirtualBlock_T::VmaVirtualBlock_T(const VmaVirtualBlockCreateInfo& createInfo
|
|||||||
|
|
||||||
VmaVirtualBlock_T::~VmaVirtualBlock_T()
|
VmaVirtualBlock_T::~VmaVirtualBlock_T()
|
||||||
{
|
{
|
||||||
// This is an important assert!!!
|
// Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations
|
||||||
|
if (!m_Metadata->IsEmpty())
|
||||||
|
m_Metadata->DebugLogAllAllocations();
|
||||||
|
// This is the most important assert in the entire library.
|
||||||
// Hitting it means you have some memory leak - unreleased virtual allocations.
|
// Hitting it means you have some memory leak - unreleased virtual allocations.
|
||||||
VMA_ASSERT(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!");
|
VMA_ASSERT(m_Metadata->IsEmpty() && "Some virtual allocations were not freed before destruction of this virtual block!");
|
||||||
|
|
||||||
@ -11382,6 +11470,9 @@ void VmaDeviceMemoryBlock::Init(
|
|||||||
|
|
||||||
void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
|
void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
|
||||||
{
|
{
|
||||||
|
// Define macro VMA_DEBUG_LOG to receive the list of the unfreed allocations
|
||||||
|
if (!m_pMetadata->IsEmpty())
|
||||||
|
m_pMetadata->DebugLogAllAllocations();
|
||||||
// This is the most important assert in the entire library.
|
// This is the most important assert in the entire library.
|
||||||
// Hitting it means you have some memory leak - unreleased VmaAllocation objects.
|
// Hitting it means you have some memory leak - unreleased VmaAllocation objects.
|
||||||
VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
|
VMA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
|
||||||
@ -11681,10 +11772,10 @@ VmaAllocHandle VmaAllocation_T::GetAllocHandle() const
|
|||||||
case ALLOCATION_TYPE_BLOCK:
|
case ALLOCATION_TYPE_BLOCK:
|
||||||
return m_BlockAllocation.m_AllocHandle;
|
return m_BlockAllocation.m_AllocHandle;
|
||||||
case ALLOCATION_TYPE_DEDICATED:
|
case ALLOCATION_TYPE_DEDICATED:
|
||||||
return VMA_NULL;
|
return VK_NULL_HANDLE;
|
||||||
default:
|
default:
|
||||||
VMA_ASSERT(0);
|
VMA_ASSERT(0);
|
||||||
return VMA_NULL;
|
return VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17654,7 +17745,7 @@ VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty(VmaVirtualBlock VMA_N
|
|||||||
}
|
}
|
||||||
|
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
||||||
VmaVirtualAllocation VMA_NOT_NULL allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo)
|
VmaVirtualAllocation allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo)
|
||||||
{
|
{
|
||||||
VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pVirtualAllocInfo != VMA_NULL);
|
VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && pVirtualAllocInfo != VMA_NULL);
|
||||||
VMA_DEBUG_LOG("vmaGetVirtualAllocationInfo");
|
VMA_DEBUG_LOG("vmaGetVirtualAllocationInfo");
|
||||||
@ -17672,7 +17763,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_N
|
|||||||
return virtualBlock->Allocate(*pCreateInfo, *pAllocation, pOffset);
|
return virtualBlock->Allocate(*pCreateInfo, *pAllocation, pOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation VMA_NULLABLE allocation)
|
VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation allocation)
|
||||||
{
|
{
|
||||||
if(virtualBlock != VMA_NULL)
|
if(virtualBlock != VMA_NULL)
|
||||||
{
|
{
|
||||||
@ -17692,7 +17783,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock(VmaVirtualBlock VMA_NOT_NUL
|
|||||||
}
|
}
|
||||||
|
|
||||||
VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData(VmaVirtualBlock VMA_NOT_NULL virtualBlock,
|
||||||
VmaVirtualAllocation VMA_NOT_NULL allocation, void* VMA_NULLABLE pUserData)
|
VmaVirtualAllocation allocation, void* VMA_NULLABLE pUserData)
|
||||||
{
|
{
|
||||||
VMA_ASSERT(virtualBlock != VK_NULL_HANDLE);
|
VMA_ASSERT(virtualBlock != VK_NULL_HANDLE);
|
||||||
VMA_DEBUG_LOG("vmaSetVirtualAllocationUserData");
|
VMA_DEBUG_LOG("vmaSetVirtualAllocationUserData");
|
||||||
|
Loading…
Reference in New Issue
Block a user