Refactoring: Added function VmaAddStatInfoAllocation, VmaAddStatInfoUnusedRange

Submitting improved tests.
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
index 5d1e378..2134a8c 100644
--- a/include/vk_mem_alloc.h
+++ b/include/vk_mem_alloc.h
@@ -5091,6 +5091,7 @@
     virtual bool IsEmpty() const = 0;

     virtual void GetAllocationInfo(VkDeviceSize offset, VmaVirtualAllocationInfo& outInfo) = 0;

 

+    // Must set blockCount to 1.

     virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const = 0;

     // Shouldn't modify blockCount.

     virtual void AddPoolStats(VmaPoolStats& inoutStats) const = 0;

@@ -5603,7 +5604,7 @@
     bool ValidateNode(ValidationContext& ctx, const Node* parent, const Node* curr, uint32_t level, VkDeviceSize levelNodeSize) const;

     uint32_t AllocSizeToLevel(VkDeviceSize allocSize) const;

     inline VkDeviceSize LevelToNodeSize(uint32_t level) const { return m_UsableSize >> level; }

-    void CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const;

+    void CalcAllocationStatInfoNode(VmaStatInfo& inoutInfo, const Node* node, VkDeviceSize levelNodeSize) const;

     // Adds node to the front of FreeList at given level.

     // node->type must be FREE.

     // node->free.prev, next can be undefined.

@@ -6869,7 +6870,7 @@
 

 class VmaStringBuilder;

 

-static void InitStatInfo(VmaStatInfo& outInfo)

+static void VmaInitStatInfo(VmaStatInfo& outInfo)

 {

     memset(&outInfo, 0, sizeof(outInfo));

     outInfo.allocationSizeMin = UINT64_MAX;

@@ -6890,6 +6891,34 @@
     inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);

 }

 

+static void VmaAddStatInfoAllocation(VmaStatInfo& inoutInfo, VkDeviceSize size)

+{

+    ++inoutInfo.allocationCount;

+    inoutInfo.usedBytes += size;

+    if(size < inoutInfo.allocationSizeMin)

+    {

+        inoutInfo.allocationSizeMin = size;

+    }

+    if(size > inoutInfo.allocationSizeMax)

+    {

+        inoutInfo.allocationSizeMax = size;

+    }

+}

+

+static void VmaAddStatInfoUnusedRange(VmaStatInfo& inoutInfo, VkDeviceSize size)

+{

+    ++inoutInfo.unusedRangeCount;

+    inoutInfo.unusedBytes += size;

+    if(size < inoutInfo.unusedRangeSizeMin)

+    {

+        inoutInfo.unusedRangeSizeMin = size;

+    }

+    if(size > inoutInfo.unusedRangeSizeMax)

+    {

+        inoutInfo.unusedRangeSizeMax = size;

+    }

+}

+

 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)

 {

     inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?

@@ -7941,31 +7970,19 @@
 

 void VmaBlockMetadata_Generic::CalcAllocationStatInfo(VmaStatInfo& outInfo) const

 {

-    outInfo.blockCount = 1;

-

     const uint32_t rangeCount = (uint32_t)m_Suballocations.size();

-    outInfo.allocationCount = rangeCount - m_FreeCount;

-    outInfo.unusedRangeCount = m_FreeCount;

-

-    outInfo.unusedBytes = m_SumFreeSize;

-    outInfo.usedBytes = GetSize() - outInfo.unusedBytes;

-

-    outInfo.allocationSizeMin = UINT64_MAX;

-    outInfo.allocationSizeMax = 0;

-    outInfo.unusedRangeSizeMin = UINT64_MAX;

-    outInfo.unusedRangeSizeMax = 0;

+    VmaInitStatInfo(outInfo);

+    outInfo.blockCount = 1;

 

     for(const auto& suballoc : m_Suballocations)

     {

         if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)

         {

-            outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);

-            outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);

+            VmaAddStatInfoAllocation(outInfo, suballoc.size);

         }

         else

         {

-            outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);

-            outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);

+            VmaAddStatInfoUnusedRange(outInfo, suballoc.size);

         }

     }

 }

@@ -9077,14 +9094,8 @@
     const size_t suballoc1stCount = suballocations1st.size();

     const size_t suballoc2ndCount = suballocations2nd.size();

 

+    VmaInitStatInfo(outInfo);

     outInfo.blockCount = 1;

-    outInfo.allocationCount = (uint32_t)GetAllocationCount();

-    outInfo.unusedRangeCount = 0;

-    outInfo.usedBytes = 0;

-    outInfo.allocationSizeMin = UINT64_MAX;

-    outInfo.allocationSizeMax = 0;

-    outInfo.unusedRangeSizeMin = UINT64_MAX;

-    outInfo.unusedRangeSizeMax = 0;

 

     VkDeviceSize lastOffset = 0;

 

@@ -9111,17 +9122,12 @@
                 {

                     // There is free space from lastOffset to suballoc.offset.

                     const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;

-                    ++outInfo.unusedRangeCount;

-                    outInfo.unusedBytes += unusedRangeSize;

-                    outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                    outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                    VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

                 }

 

                 // 2. Process this allocation.

                 // There is allocation with suballoc.offset, suballoc.size.

-                outInfo.usedBytes += suballoc.size;

-                outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);

-                outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);

+                VmaAddStatInfoAllocation(outInfo, suballoc.size);

 

                 // 3. Prepare for next iteration.

                 lastOffset = suballoc.offset + suballoc.size;

@@ -9134,10 +9140,7 @@
                 if(lastOffset < freeSpace2ndTo1stEnd)

                 {

                     const VkDeviceSize unusedRangeSize = freeSpace2ndTo1stEnd - lastOffset;

-                    ++outInfo.unusedRangeCount;

-                    outInfo.unusedBytes += unusedRangeSize;

-                    outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                    outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                    VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

                }

 

                 // End of loop.

@@ -9168,17 +9171,12 @@
             {

                 // There is free space from lastOffset to suballoc.offset.

                 const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;

-                ++outInfo.unusedRangeCount;

-                outInfo.unusedBytes += unusedRangeSize;

-                outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

             }

 

             // 2. Process this allocation.

             // There is allocation with suballoc.offset, suballoc.size.

-            outInfo.usedBytes += suballoc.size;

-            outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);

-            outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);

+            VmaAddStatInfoAllocation(outInfo, suballoc.size);

 

             // 3. Prepare for next iteration.

             lastOffset = suballoc.offset + suballoc.size;

@@ -9191,10 +9189,7 @@
             if(lastOffset < freeSpace1stTo2ndEnd)

             {

                 const VkDeviceSize unusedRangeSize = freeSpace1stTo2ndEnd - lastOffset;

-                ++outInfo.unusedRangeCount;

-                outInfo.unusedBytes += unusedRangeSize;

-                outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

            }

 

             // End of loop.

@@ -9224,17 +9219,12 @@
                 {

                     // There is free space from lastOffset to suballoc.offset.

                     const VkDeviceSize unusedRangeSize = suballoc.offset - lastOffset;

-                    ++outInfo.unusedRangeCount;

-                    outInfo.unusedBytes += unusedRangeSize;

-                    outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                    outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                    VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

                 }

 

                 // 2. Process this allocation.

                 // There is allocation with suballoc.offset, suballoc.size.

-                outInfo.usedBytes += suballoc.size;

-                outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);

-                outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);

+                VmaAddStatInfoAllocation(outInfo, suballoc.size);

 

                 // 3. Prepare for next iteration.

                 lastOffset = suballoc.offset + suballoc.size;

@@ -9247,10 +9237,7 @@
                 if(lastOffset < size)

                 {

                     const VkDeviceSize unusedRangeSize = size - lastOffset;

-                    ++outInfo.unusedRangeCount;

-                    outInfo.unusedBytes += unusedRangeSize;

-                    outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusedRangeSize);

-                    outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusedRangeSize);

+                    VmaAddStatInfoUnusedRange(outInfo, unusedRangeSize);

                }

 

                 // End of loop.

@@ -10761,24 +10748,15 @@
 

 void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const

 {

+    VmaInitStatInfo(outInfo);

     outInfo.blockCount = 1;

 

-    outInfo.allocationCount = outInfo.unusedRangeCount = 0;

-    outInfo.usedBytes = outInfo.unusedBytes = 0;

-

-    outInfo.allocationSizeMax = outInfo.unusedRangeSizeMax = 0;

-    outInfo.allocationSizeMin = outInfo.unusedRangeSizeMin = UINT64_MAX;

-    outInfo.allocationSizeAvg = outInfo.unusedRangeSizeAvg = 0; // Unused.

-

     CalcAllocationStatInfoNode(outInfo, m_Root, LevelToNodeSize(0));

 

     const VkDeviceSize unusableSize = GetUnusableSize();

     if(unusableSize > 0)

     {

-        ++outInfo.unusedRangeCount;

-        outInfo.unusedBytes += unusableSize;

-        outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, unusableSize);

-        outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, unusableSize);

+        VmaAddStatInfoUnusedRange(outInfo, unusableSize);

     }

 }

 

@@ -11135,29 +11113,23 @@
     AddToFreeListFront(level, node);

 }

 

-void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& outInfo, const Node* node, VkDeviceSize levelNodeSize) const

+void VmaBlockMetadata_Buddy::CalcAllocationStatInfoNode(VmaStatInfo& inoutInfo, const Node* node, VkDeviceSize levelNodeSize) const

 {

     switch(node->type)

     {

     case Node::TYPE_FREE:

-        ++outInfo.unusedRangeCount;

-        outInfo.unusedBytes += levelNodeSize;

-        outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, levelNodeSize);

-        outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, levelNodeSize);

+        VmaAddStatInfoUnusedRange(inoutInfo, levelNodeSize);

         break;

     case Node::TYPE_ALLOCATION:

-        ++outInfo.allocationCount;

-        outInfo.usedBytes += levelNodeSize;

-        outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, levelNodeSize);

-        outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, levelNodeSize);

+        VmaAddStatInfoAllocation(inoutInfo, levelNodeSize);

         break;

     case Node::TYPE_SPLIT:

         {

             const VkDeviceSize childrenNodeSize = levelNodeSize / 2;

             const Node* const leftChild = node->split.leftChild;

-            CalcAllocationStatInfoNode(outInfo, leftChild, childrenNodeSize);

+            CalcAllocationStatInfoNode(inoutInfo, leftChild, childrenNodeSize);

             const Node* const rightChild = leftChild->buddy;

-            CalcAllocationStatInfoNode(outInfo, rightChild, childrenNodeSize);

+            CalcAllocationStatInfoNode(inoutInfo, rightChild, childrenNodeSize);

         }

         break;

     default:

@@ -15658,11 +15630,11 @@
 void VmaAllocator_T::CalculateStats(VmaStats* pStats)

 {

     // Initialize.

-    InitStatInfo(pStats->total);

+    VmaInitStatInfo(pStats->total);

     for(size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)

-        InitStatInfo(pStats->memoryType[i]);

+        VmaInitStatInfo(pStats->memoryType[i]);

     for(size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)

-        InitStatInfo(pStats->memoryHeap[i]);

+        VmaInitStatInfo(pStats->memoryHeap[i]);

 

     // Process default pools.

     for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)

diff --git a/src/Tests.cpp b/src/Tests.cpp
index 50b34cc..1dde2dc 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -2824,7 +2824,7 @@
     RandomNumberGenerator rand{3454335};
     auto calcRandomAllocSize = [&rand]() -> VkDeviceSize { return rand.Generate() % 20 + 5; };
 
-    for(size_t algorithmIndex = 0; algorithmIndex < 1/*3*/; ++algorithmIndex)
+    for(size_t algorithmIndex = 0; algorithmIndex < 3; ++algorithmIndex)
     {
         // Create the block
         VmaVirtualBlockCreateInfo blockCreateInfo = {};
@@ -2841,7 +2841,7 @@
 
         struct AllocData
         {
-            VkDeviceSize offset, size;
+            VkDeviceSize offset, requestedSize, allocationSize;
         };
         std::vector<AllocData> allocations;
         
@@ -2858,9 +2858,15 @@
             else if(i < 18 && algorithmIndex == 1) allocCreateInfo.flags = VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT;
 
             AllocData alloc = {};
-            alloc.size = allocCreateInfo.size;
+            alloc.requestedSize = allocCreateInfo.size;
             res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
             TEST(res == VK_SUCCESS);
+            
+            VmaVirtualAllocationInfo allocInfo;
+            vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
+            TEST(allocInfo.size >= allocCreateInfo.size);
+            alloc.allocationSize = allocInfo.size;
+
             allocations.push_back(alloc);
         }
 
@@ -2880,9 +2886,15 @@
             allocCreateInfo.pUserData = (void*)(uintptr_t)(allocCreateInfo.size * 10);
 
             AllocData alloc = {};
-            alloc.size = allocCreateInfo.size;
+            alloc.requestedSize = allocCreateInfo.size;
             res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
             TEST(res == VK_SUCCESS);
+
+            VmaVirtualAllocationInfo allocInfo;
+            vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
+            TEST(allocInfo.size >= allocCreateInfo.size);
+            alloc.allocationSize = allocInfo.size;
+
             allocations.push_back(alloc);
         }
 
@@ -2895,10 +2907,16 @@
             allocCreateInfo.pUserData = (void*)(uintptr_t)(allocCreateInfo.size * 10);
 
             AllocData alloc = {};
-            alloc.size = allocCreateInfo.size;
+            alloc.requestedSize = allocCreateInfo.size;
             res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc.offset);
             TEST(res == VK_SUCCESS);
             TEST(alloc.offset % 16 == 0);
+
+            VmaVirtualAllocationInfo allocInfo;
+            vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
+            TEST(allocInfo.size >= allocCreateInfo.size);
+            alloc.allocationSize = allocInfo.size;
+
             allocations.push_back(alloc);
         }
 
@@ -2907,7 +2925,7 @@
             return lhs.offset < rhs.offset; });
         for(size_t i = 0; i < allocations.size() - 1; ++i)
         {
-            TEST(allocations[i+1].offset >= allocations[i].offset + allocations[i].size);
+            TEST(allocations[i+1].offset >= allocations[i].offset + allocations[i].allocationSize);
         }
 
         // Check pUserData
@@ -2915,7 +2933,7 @@
             const AllocData& alloc = allocations.back();
             VmaVirtualAllocationInfo allocInfo = {};
             vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
-            TEST((uintptr_t)allocInfo.pUserData == alloc.size * 10);
+            TEST((uintptr_t)allocInfo.pUserData == alloc.requestedSize * 10);
 
             vmaSetVirtualAllocationUserData(block, alloc.offset, (void*)(uintptr_t)666);
             vmaGetVirtualAllocationInfo(block, alloc.offset, &allocInfo);
@@ -2924,11 +2942,11 @@
 
         // Calculate statistics
         {
-            VkDeviceSize allocSizeMin = VK_WHOLE_SIZE, allocSizeMax = 0, allocSizeSum = 0;
+            VkDeviceSize actualAllocSizeMin = VK_WHOLE_SIZE, actualAllocSizeMax = 0, actualAllocSizeSum = 0;
             std::for_each(allocations.begin(), allocations.end(), [&](const AllocData& a) {
-                allocSizeMin = std::min(allocSizeMin, a.size);
-                allocSizeMax = std::max(allocSizeMax, a.size);
-                allocSizeSum += a.size;
+                actualAllocSizeMin = std::min(actualAllocSizeMin, a.allocationSize);
+                actualAllocSizeMax = std::max(actualAllocSizeMax, a.allocationSize);
+                actualAllocSizeSum += a.allocationSize;
             });
 
             VmaStatInfo statInfo = {};
@@ -2936,9 +2954,9 @@
             TEST(statInfo.allocationCount == allocations.size());
             TEST(statInfo.blockCount == 1);
             TEST(statInfo.usedBytes + statInfo.unusedBytes == blockCreateInfo.size);
-            TEST(statInfo.allocationSizeMax == allocSizeMax);
-            TEST(statInfo.allocationSizeMin == allocSizeMin);
-            TEST(statInfo.usedBytes >= allocSizeSum);
+            TEST(statInfo.allocationSizeMax == actualAllocSizeMax);
+            TEST(statInfo.allocationSizeMin == actualAllocSizeMin);
+            TEST(statInfo.usedBytes >= actualAllocSizeSum);
         }
 
         // Build JSON dump string
@@ -6834,6 +6852,7 @@
     {
         ////////////////////////////////////////////////////////////////////////////////
         // Temporarily insert custom tests here:
+        TestVirtualBlocks();
         TestVirtualBlocksAlgorithms();
         return;
     }
@@ -6842,6 +6861,7 @@
 
     TestBasics();
     TestVirtualBlocks();
+    TestVirtualBlocksAlgorithms();
     TestAllocationVersusResourceSize();
     //TestGpuData(); // Not calling this because it's just testing the testing environment.
 #if VMA_DEBUG_MARGIN