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);
}