VmaReplay: Added parameter --MemStats and memory statistics.
diff --git a/src/VmaReplay/VmaReplay.cpp b/src/VmaReplay/VmaReplay.cpp
index f9370cf..c714d6f 100644
--- a/src/VmaReplay/VmaReplay.cpp
+++ b/src/VmaReplay/VmaReplay.cpp
@@ -39,6 +39,7 @@
     CMD_LINE_OPT_USER_DATA,

     CMD_LINE_OPT_VK_KHR_DEDICATED_ALLOCATION,

     CMD_LINE_OPT_VK_LAYER_LUNARG_STANDARD_VALIDATION,

+    CMD_LINE_OPT_MEM_STATS,

 };

 

 static enum class VERBOSITY

@@ -118,6 +119,7 @@
 static uint32_t g_PhysicalDeviceIndex = 0;

 static RangeSequence<size_t> g_LineRanges;

 static bool g_UserDataEnabled = true;

+static bool g_MemStatsEnabled = true;

 VULKAN_EXTENSION_REQUEST g_VK_KHR_dedicated_allocation_request = VULKAN_EXTENSION_REQUEST::DEFAULT;

 VULKAN_EXTENSION_REQUEST g_VK_LAYER_LUNARG_standard_validation = VULKAN_EXTENSION_REQUEST::DEFAULT;

 

@@ -155,7 +157,9 @@
     static uint32_t BufferUsageToClass(uint32_t usage);

     static uint32_t ImageUsageToClass(uint32_t usage);

 

-    Statistics() { }

+    Statistics();

+    void Init(uint32_t memHeapCount, uint32_t memTypeCount);

+    void PrintMemStats() const;

 

     const size_t* GetFunctionCallCount() const { return m_FunctionCallCount; }

     size_t GetImageCreationCount(uint32_t imgClass) const { return m_ImageCreationCount[imgClass]; }

@@ -170,13 +174,38 @@
     void RegisterCreatePool();

     void RegisterCreateAllocation();

 

+    void UpdateMemStats(const VmaStats& currStats);

+

 private:

+    uint32_t m_MemHeapCount = 0;

+    uint32_t m_MemTypeCount = 0;

+

     size_t m_FunctionCallCount[(size_t)VMA_FUNCTION::Count] = {};

     size_t m_ImageCreationCount[4] = { };

     size_t m_LinearImageCreationCount = 0;

     size_t m_BufferCreationCount[4] = { };

     size_t m_AllocationCreationCount = 0; // Also includes buffers and images, and lost allocations.

     size_t m_PoolCreationCount = 0;

+    

+    // Structure similar to VmaStatInfo, but not the same.

+    struct MemStatInfo

+    {

+        uint32_t blockCount;

+        uint32_t allocationCount;

+        uint32_t unusedRangeCount;

+        VkDeviceSize usedBytes;

+        VkDeviceSize unusedBytes;

+        VkDeviceSize totalBytes;

+    };

+    struct MemStats

+    {

+        MemStatInfo memoryType[VK_MAX_MEMORY_TYPES];

+        MemStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS];

+        MemStatInfo total;

+    } m_PeakMemStats;

+

+    void UpdateMemStatInfo(MemStatInfo& inoutPeakInfo, const VmaStatInfo& currInfo);

+    static void PrintMemStatInfo(const MemStatInfo& info);

 };

 

 uint32_t Statistics::BufferUsageToClass(uint32_t usage)

@@ -242,6 +271,45 @@
     }

 }

 

+Statistics::Statistics()

+{

+    ZeroMemory(&m_PeakMemStats, sizeof(m_PeakMemStats));

+}

+

+void Statistics::Init(uint32_t memHeapCount, uint32_t memTypeCount)

+{

+    m_MemHeapCount = memHeapCount;

+    m_MemTypeCount = memTypeCount;

+}

+

+void Statistics::PrintMemStats() const

+{

+    printf("Memory statistics:\n");

+

+    printf("    Total:\n");

+    PrintMemStatInfo(m_PeakMemStats.total);

+

+    for(uint32_t i = 0; i < m_MemHeapCount; ++i)

+    {

+        const MemStatInfo& info = m_PeakMemStats.memoryHeap[i];

+        if(info.blockCount > 0 || info.totalBytes > 0)

+        {

+            printf("    Heap %u:\n", i);

+            PrintMemStatInfo(info);

+        }

+    }

+

+    for(uint32_t i = 0; i < m_MemTypeCount; ++i)

+    {

+        const MemStatInfo& info = m_PeakMemStats.memoryType[i];

+        if(info.blockCount > 0 || info.totalBytes > 0)

+        {

+            printf("    Type %u:\n", i);

+            PrintMemStatInfo(info);

+        }

+    }

+}

+

 void Statistics::RegisterFunctionCall(VMA_FUNCTION func)

 {

     ++m_FunctionCallCount[(size_t)func];

@@ -278,6 +346,51 @@
     ++m_AllocationCreationCount;

 }

 

+void Statistics::UpdateMemStats(const VmaStats& currStats)

+{

+    UpdateMemStatInfo(m_PeakMemStats.total, currStats.total);

+    

+    for(uint32_t i = 0; i < m_MemHeapCount; ++i)

+    {

+        UpdateMemStatInfo(m_PeakMemStats.memoryHeap[i], currStats.memoryHeap[i]);

+    }

+

+    for(uint32_t i = 0; i < m_MemTypeCount; ++i)

+    {

+        UpdateMemStatInfo(m_PeakMemStats.memoryType[i], currStats.memoryType[i]);

+    }

+}

+

+void Statistics::UpdateMemStatInfo(MemStatInfo& inoutPeakInfo, const VmaStatInfo& currInfo)

+{

+#define SET_PEAK(inoutDst, src) \

+    if((src) > (inoutDst)) \

+    { \

+        (inoutDst) = (src); \

+    }

+

+    SET_PEAK(inoutPeakInfo.blockCount, currInfo.blockCount);

+    SET_PEAK(inoutPeakInfo.allocationCount, currInfo.allocationCount);

+    SET_PEAK(inoutPeakInfo.unusedRangeCount, currInfo.unusedRangeCount);

+    SET_PEAK(inoutPeakInfo.usedBytes, currInfo.usedBytes);

+    SET_PEAK(inoutPeakInfo.unusedBytes, currInfo.unusedBytes);

+    SET_PEAK(inoutPeakInfo.totalBytes, currInfo.usedBytes + currInfo.unusedBytes);

+

+#undef SET_PEAK

+}

+

+void Statistics::PrintMemStatInfo(const MemStatInfo& info)

+{

+    printf("        Peak blocks %u, allocations %u, unused ranges %u\n",

+        info.blockCount,

+        info.allocationCount,

+        info.unusedRangeCount);

+    printf("        Peak total bytes: %llu, used bytes %llu, unused bytes %llu\n",

+        info.totalBytes,

+        info.usedBytes,

+        info.unusedBytes);

+}

+

 ////////////////////////////////////////////////////////////////////////////////

 // class Player

 

@@ -383,6 +496,7 @@
     uint32_t m_GraphicsQueueFamilyIndex = UINT_MAX;

     VkDevice m_Device = VK_NULL_HANDLE;

     VmaAllocator m_Allocator = VK_NULL_HANDLE;

+    const VkPhysicalDeviceMemoryProperties* m_MemProps = nullptr;

 

     PFN_vkCreateDebugReportCallbackEXT m_pvkCreateDebugReportCallbackEXT;

     PFN_vkDebugReportMessageEXT m_pvkDebugReportMessageEXT;

@@ -440,6 +554,8 @@
     // If failed, prints warning, returns false, and sets allocCreateInfo.pUserData to null.

     bool PrepareUserData(size_t lineNumber, uint32_t allocCreateFlags, const StrRange& userDataColumn, const StrRange& wholeLine, void*& outUserData);

 

+    void UpdateMemStats();

+

     void ExecuteCreatePool(size_t lineNumber, const CsvSplit& csvSplit);

     void ExecuteDestroyPool(size_t lineNumber, const CsvSplit& csvSplit);

     void ExecuteSetAllocationUserData(size_t lineNumber, const CsvSplit& csvSplit);

@@ -468,7 +584,15 @@
 

 int Player::Init()

 {

-    return InitVulkan();

+    int result = InitVulkan();

+    

+    if(result == 0)

+    {

+        m_Stats.Init(m_MemProps->memoryHeapCount, m_MemProps->memoryTypeCount);

+        UpdateMemStats();

+    }

+    

+    return result;

 }

 

 Player::~Player()

@@ -940,6 +1064,8 @@
         return RESULT_ERROR_VULKAN;

     }

 

+    vmaGetMemoryProperties(m_Allocator, &m_MemProps);

+

     return 0;

 }

 

@@ -1129,6 +1255,11 @@
             }

         }

     }

+

+    if(g_MemStatsEnabled)

+    {

+        m_Stats.PrintMemStats();

+    }

 }

 

 bool Player::ValidateFunctionParameterCount(size_t lineNumber, const CsvSplit& csvSplit, size_t expectedParamCount, bool lastUnbound)

@@ -1187,6 +1318,18 @@
     return false;

 }

 

+void Player::UpdateMemStats()

+{

+    if(!g_MemStatsEnabled)

+    {

+        return;

+    }

+

+    VmaStats stats;

+    vmaCalculateStats(m_Allocator, &stats);

+    m_Stats.UpdateMemStats(stats);

+}

+

 void Player::ExecuteCreatePool(size_t lineNumber, const CsvSplit& csvSplit)

 {

     m_Stats.RegisterFunctionCall(VMA_FUNCTION::CreatePool);

@@ -1259,6 +1402,8 @@
                     }

                 }

             }

+

+            UpdateMemStats();

         }

         else

         {

@@ -1286,6 +1431,7 @@
                 if(it != m_Pools.end())

                 {

                     vmaDestroyPool(m_Allocator, it->second.pool);

+                    UpdateMemStats();

                     m_Pools.erase(it);

                 }

                 else

@@ -1395,6 +1541,7 @@
             Allocation allocDesc = { };

             allocDesc.allocationFlags = allocCreateInfo.flags;

             VkResult res = vmaCreateBuffer(m_Allocator, &bufCreateInfo, &allocCreateInfo, &allocDesc.buffer, &allocDesc.allocation, nullptr);

+            UpdateMemStats();

             AddAllocation(lineNumber, origPtr, res, "vmaCreateBuffer", std::move(allocDesc));

         }

         else

@@ -1421,6 +1568,7 @@
                 if(it != m_Allocations.end())

                 {

                     Destroy(it->second);

+                    UpdateMemStats();

                     m_Allocations.erase(it);

                 }

                 else

@@ -1491,6 +1639,7 @@
             Allocation allocDesc = {};

             allocDesc.allocationFlags = allocCreateInfo.flags;

             VkResult res = vmaCreateImage(m_Allocator, &imageCreateInfo, &allocCreateInfo, &allocDesc.image, &allocDesc.allocation, nullptr);

+            UpdateMemStats();

             AddAllocation(lineNumber, origPtr, res, "vmaCreateImage", std::move(allocDesc));

         }

         else

@@ -1515,6 +1664,7 @@
         {

             Allocation allocDesc = {};

             vmaCreateLostAllocation(m_Allocator, &allocDesc.allocation);

+            UpdateMemStats();

             m_Stats.RegisterCreateAllocation();

 

             AddAllocation(lineNumber, origPtr, VK_SUCCESS, "vmaCreateLostAllocation", std::move(allocDesc));

@@ -1563,6 +1713,7 @@
                     allocCreateInfo.pUserData);

             }

 

+            UpdateMemStats();

             m_Stats.RegisterCreateAllocation();

 

             Allocation allocDesc = {};

@@ -1641,6 +1792,7 @@
                 m_AllocateForBufferImageWarningIssued = true;

             }

 

+            UpdateMemStats();

             m_Stats.RegisterCreateAllocation();

 

             Allocation allocDesc = {};

@@ -1956,6 +2108,7 @@
                 if(it != m_Pools.end())

                 {

                     vmaMakePoolAllocationsLost(m_Allocator, it->second.pool, nullptr);

+                    UpdateMemStats();

                 }

                 else

                 {

@@ -1991,6 +2144,8 @@
         "        2 - Maximum verbosity. Prints a lot of information.\n"

         "    -i <Number> - Repeat playback given number of times (iterations)\n"

         "        Default is 1. Vulkan is reinitialized with every iteration.\n"

+        "    --MemStats <Value> - 0 to disable or 1 to enable memory statistics.\n"

+        "        Default is 1. Enabling it may negatively impact playback performance.\n"

         "    --Lines <Ranges> - Replay only limited set of lines from file\n"

         "        Ranges is comma-separated list of ranges, e.g. \"-10,15,18-25,31-\".\n"

         "    --PhysicalDevice <Index> - Choice of Vulkan physical device. Default: 0.\n"

@@ -2158,6 +2313,7 @@
     cmdLineParser.RegisterOpt(CMD_LINE_OPT_USER_DATA, "UserData", true);

     cmdLineParser.RegisterOpt(CMD_LINE_OPT_VK_KHR_DEDICATED_ALLOCATION, "VK_KHR_dedicated_allocation", true);

     cmdLineParser.RegisterOpt(CMD_LINE_OPT_VK_LAYER_LUNARG_STANDARD_VALIDATION, VALIDATION_LAYER_NAME, true);

+    cmdLineParser.RegisterOpt(CMD_LINE_OPT_MEM_STATS, "MemStats", true);

 

     CmdLineParser::RESULT res;

     while((res = cmdLineParser.ReadNext()) != CmdLineParser::RESULT_END)

@@ -2242,6 +2398,13 @@
                     }

                 }

                 break;

+            case CMD_LINE_OPT_MEM_STATS:

+                if(!StrRangeToBool(StrRange(cmdLineParser.GetParameter()), g_MemStatsEnabled))

+                {

+                    PrintCommandLineSyntax();

+                    return RESULT_ERROR_COMMAND_LINE;

+                }

+                break;

             default:

                 assert(0);

             }