From 6a0a85a5c079ed15ac73ffcecec9cd842e886613 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Fri, 1 Jun 2018 15:20:49 +0200 Subject: [PATCH] Added subsequent, unique, numeric IDs to memory blocks and custom pools. They are dumped in JSON. JSON format changed: "Pools" and "Blocks" arrays are now objects, where key is pool/block ID, and value is as before. Applied appropriate changes in VmaDumpVis.py - it now shows pool and block ID from the dump. --- src/vk_mem_alloc.h | 44 +++++++++++++++++++++++------- tools/VmaDumpVis/VmaDumpVis.py | 50 ++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h index 177922e..ebe3a02 100644 --- a/src/vk_mem_alloc.h +++ b/src/vk_mem_alloc.h @@ -4147,12 +4147,14 @@ public: void Init( uint32_t newMemoryTypeIndex, VkDeviceMemory newMemory, - VkDeviceSize newSize); + VkDeviceSize newSize, + uint32_t id); // Always call before destruction. void Destroy(VmaAllocator allocator); VkDeviceMemory GetDeviceMemory() const { return m_hMemory; } uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } + uint32_t GetId() const { return m_Id; } void* GetMappedData() const { return m_pMappedData; } // Validates all data structures inside this object. If not valid, returns false. @@ -4173,6 +4175,7 @@ public: private: uint32_t m_MemoryTypeIndex; + uint32_t m_Id; VkDeviceMemory m_hMemory; // Protects access to m_hMemory so it's not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. @@ -4276,6 +4279,7 @@ private: of a VkDeviceMemory. */ bool m_HasEmptyBlock; VmaDefragmentator* m_pDefragmentator; + uint32_t m_NextBlockId; VkDeviceSize CalcMaxBlockSize() const; @@ -4295,17 +4299,21 @@ struct VmaPool_T public: VmaBlockVector m_BlockVector; - // Takes ownership. VmaPool_T( VmaAllocator hAllocator, const VmaPoolCreateInfo& createInfo); ~VmaPool_T(); VmaBlockVector& GetBlockVector() { return m_BlockVector; } + uint32_t GetId() const { return m_Id; } + void SetId(uint32_t id) { VMA_ASSERT(m_Id == 0); m_Id = id; } #if VMA_STATS_STRING_ENABLED //void PrintDetailedMap(class VmaStringBuilder& sb); #endif + +private: + uint32_t m_Id; }; class VmaDefragmentator @@ -4569,6 +4577,7 @@ private: VMA_MUTEX m_PoolsMutex; // Protected by m_PoolsMutex. Sorted by pointer value. VmaVector > m_Pools; + uint32_t m_NextPoolId; VmaVulkanFunctions m_VulkanFunctions; @@ -6366,6 +6375,7 @@ void VmaBlockMetadata::UnregisterFreeSuballocation(VmaSuballocationList::iterato VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) : m_Metadata(hAllocator), m_MemoryTypeIndex(UINT32_MAX), + m_Id(0), m_hMemory(VK_NULL_HANDLE), m_MapCount(0), m_pMappedData(VMA_NULL) @@ -6375,11 +6385,13 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) : void VmaDeviceMemoryBlock::Init( uint32_t newMemoryTypeIndex, VkDeviceMemory newMemory, - VkDeviceSize newSize) + VkDeviceSize newSize, + uint32_t id) { VMA_ASSERT(m_hMemory == VK_NULL_HANDLE); m_MemoryTypeIndex = newMemoryTypeIndex; + m_Id = id; m_hMemory = newMemory; m_Metadata.Init(newSize); @@ -6572,7 +6584,8 @@ VmaBlockVector::VmaBlockVector( m_IsCustomPool(isCustomPool), m_Blocks(VmaStlAllocator(hAllocator->GetAllocationCallbacks())), m_HasEmptyBlock(false), - m_pDefragmentator(VMA_NULL) + m_pDefragmentator(VMA_NULL), + m_NextBlockId(0) { } @@ -7000,7 +7013,8 @@ VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIn pBlock->Init( m_MemoryTypeIndex, mem, - allocInfo.allocationSize); + allocInfo.allocationSize, + m_NextBlockId++); m_Blocks.push_back(pBlock); if(pNewBlockIndex != VMA_NULL) @@ -7056,12 +7070,16 @@ void VmaBlockVector::PrintDetailedMap(class VmaJsonWriter& json) } json.WriteString("Blocks"); - json.BeginArray(); + json.BeginObject(); for(size_t i = 0; i < m_Blocks.size(); ++i) { + json.BeginString(); + json.ContinueString(m_Blocks[i]->GetId()); + json.EndString(); + m_Blocks[i]->m_Metadata.PrintDetailedMap(json); } - json.EndArray(); + json.EndObject(); json.EndObject(); } @@ -7481,7 +7499,8 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_PreferredLargeHeapBlockSize(0), m_PhysicalDevice(pCreateInfo->physicalDevice), m_CurrentFrameIndex(0), - m_Pools(VmaStlAllocator(GetAllocationCallbacks())) + m_Pools(VmaStlAllocator(GetAllocationCallbacks())), + m_NextPoolId(0) { VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device); @@ -8372,6 +8391,7 @@ VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPoo // Add to m_Pools. { VmaMutexLock lock(m_PoolsMutex, m_UseMutex); + (*pPool)->SetId(m_NextPoolId++); VmaVectorInsertSorted(m_Pools, *pPool); } @@ -8662,12 +8682,16 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) if(poolCount > 0) { json.WriteString("Pools"); - json.BeginArray(); + json.BeginObject(); for(size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex) { + json.BeginString(); + json.ContinueString(m_Pools[poolIndex]->GetId()); + json.EndString(); + m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json); } - json.EndArray(); + json.EndObject(); } } } diff --git a/tools/VmaDumpVis/VmaDumpVis.py b/tools/VmaDumpVis/VmaDumpVis.py index 455ee7e..f16913b 100644 --- a/tools/VmaDumpVis/VmaDumpVis.py +++ b/tools/VmaDumpVis/VmaDumpVis.py @@ -46,10 +46,10 @@ args = argParser.parse_args() data = {} -def ProcessBlock(dstBlockList, objBlock): +def ProcessBlock(dstBlockList, iBlockId, objBlock): iBlockSize = int(objBlock['TotalBytes']) arrSuballocs = objBlock['Suballocations'] - dstBlockObj = {'Size':iBlockSize, 'Suballocations':[]} + dstBlockObj = {'ID': iBlockId, 'Size':iBlockSize, 'Suballocations':[]} dstBlockList.append(dstBlockObj) for objSuballoc in arrSuballocs: dstBlockObj['Suballocations'].append((objSuballoc['Type'], int(objSuballoc['Size']), int(objSuballoc['Usage']) if ('Usage' in objSuballoc) else 0)) @@ -60,7 +60,7 @@ def GetDataForMemoryType(iMemTypeIndex): if iMemTypeIndex in data: return data[iMemTypeIndex] else: - newMemTypeData = {'DedicatedAllocations':[], 'DefaultPoolBlocks':[], 'CustomPoolBlocks':[]} + newMemTypeData = {'DedicatedAllocations':[], 'DefaultPoolBlocks':[], 'CustomPools':{}} data[iMemTypeIndex] = newMemTypeData return newMemTypeData @@ -81,9 +81,10 @@ def CalcParams(): iImgSizeY += len(dictMemType['DefaultPoolBlocks']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE) for objBlock in dictMemType['DefaultPoolBlocks']: iMaxBlockSize = max(iMaxBlockSize, objBlock['Size']) - iImgSizeY += len(dictMemType['CustomPoolBlocks']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE) - for objBlock in dictMemType['CustomPoolBlocks']: - iMaxBlockSize = max(iMaxBlockSize, objBlock['Size']) + iImgSizeY += len(dictMemType['CustomPools']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE) + for listPool in dictMemType['CustomPools'].values(): + for objBlock in listPool: + iMaxBlockSize = max(iMaxBlockSize, objBlock['Size']) fPixelsPerByte = (IMG_SIZE_X - IMG_MARGIN * 2) / float(iMaxBlockSize) return iImgSizeY, fPixelsPerByte @@ -180,16 +181,17 @@ if 'DefaultPools' in jsonSrc: assert sType[:5] == 'Type ' iType = int(sType[5:]) typeData = GetDataForMemoryType(iType) - for objBlock in tType[1]['Blocks']: - ProcessBlock(typeData['DefaultPoolBlocks'], objBlock) + for sBlockId, objBlock in tType[1]['Blocks'].items(): + ProcessBlock(typeData['DefaultPoolBlocks'], int(sBlockId), objBlock) if 'Pools' in jsonSrc: - arrPools = jsonSrc['Pools'] - for objPool in arrPools: + objPools = jsonSrc['Pools'] + for sPoolId, objPool in objPools.items(): iType = int(objPool['MemoryTypeIndex']) typeData = GetDataForMemoryType(iType) - arrBlocks = objPool['Blocks'] - for objBlock in arrBlocks: - ProcessBlock(typeData['CustomPoolBlocks'], objBlock) + objBlocks = objPool['Blocks'] + for sBlockId, objBlock in objBlocks.items(): + typeData['CustomPools'][int(sPoolId)] = [] + ProcessBlock(typeData['CustomPools'][int(sPoolId)], int(sBlockId), objBlock) iImgSizeY, fPixelsPerByte = CalcParams() @@ -230,20 +232,19 @@ for iMemTypeIndex in sorted(data.keys()): DrawDedicatedAllocationBlock(draw, y, tDedicatedAlloc) y += MAP_SIZE + IMG_MARGIN index += 1 - index = 0 for objBlock in dictMemType['DefaultPoolBlocks']: - draw.text((IMG_MARGIN, y), "Default pool block %d" % index, fill=COLOR_TEXT_H2, font=font) + draw.text((IMG_MARGIN, y), "Default pool block %d" % objBlock['ID'], fill=COLOR_TEXT_H2, font=font) y += FONT_SIZE + IMG_MARGIN DrawBlock(draw, y, objBlock) y += MAP_SIZE + IMG_MARGIN - index += 1 index = 0 - for objBlock in dictMemType['CustomPoolBlocks']: - draw.text((IMG_MARGIN, y), "Custom pool block %d" % index, fill=COLOR_TEXT_H2, font=font) - y += FONT_SIZE + IMG_MARGIN - DrawBlock(draw, y, objBlock) - y += MAP_SIZE + IMG_MARGIN - index += 1 + for iPoolId, listPool in dictMemType['CustomPools'].items(): + for objBlock in listPool: + draw.text((IMG_MARGIN, y), "Custom pool %d block %d" % (iPoolId, objBlock['ID']), fill=COLOR_TEXT_H2, font=font) + y += FONT_SIZE + IMG_MARGIN + DrawBlock(draw, y, objBlock) + y += MAP_SIZE + IMG_MARGIN + index += 1 del draw img.save(args.output) @@ -254,9 +255,12 @@ Main data structure - variable `data` - is a dictionary. Key is integer - memory - [1]: Size : integer - [2]: Usage : integer (0 if unknown) - Fixed key 'DefaultPoolBlocks'. Value is list of objects, each containing dictionary with: + - Fixed key 'ID'. Value is int. - Fixed key 'Size'. Value is int. - Fixed key 'Suballocations'. Value is list of tuples as above. -- Fixed key 'CustomPoolBlocks'. Value is list of objects, each containing dictionary with: +- Fixed key 'CustomPools'. Value is dictionary. + - Key is integer pool ID. Value is list of objects, each containing dictionary with: + - Fixed key 'ID'. Value is int. - Fixed key 'Size'. Value is int. - Fixed key 'Suballocations'. Value is list of tuples as above. """