VmaReplay: Added parameter --DefragmentAfterLine.

This commit is contained in:
Adam Sawicki 2018-11-06 16:42:23 +01:00
parent dec65ac4eb
commit e97495dd73

View File

@ -41,6 +41,7 @@ enum CMD_LINE_OPT
CMD_LINE_OPT_VK_LAYER_LUNARG_STANDARD_VALIDATION, CMD_LINE_OPT_VK_LAYER_LUNARG_STANDARD_VALIDATION,
CMD_LINE_OPT_MEM_STATS, CMD_LINE_OPT_MEM_STATS,
CMD_LINE_OPT_DUMP_STATS_AFTER_LINE, CMD_LINE_OPT_DUMP_STATS_AFTER_LINE,
CMD_LINE_OPT_DEFRAGMENT_AFTER_LINE,
CMD_LINE_OPT_DUMP_DETAILED_STATS_AFTER_LINE, CMD_LINE_OPT_DUMP_DETAILED_STATS_AFTER_LINE,
}; };
@ -138,7 +139,9 @@ struct StatsAfterLineEntry
bool operator==(const StatsAfterLineEntry& rhs) const { return line == rhs.line; } bool operator==(const StatsAfterLineEntry& rhs) const { return line == rhs.line; }
}; };
static std::vector<StatsAfterLineEntry> g_DumpStatsAfterLine; static std::vector<StatsAfterLineEntry> g_DumpStatsAfterLine;
static std::vector<size_t> g_DefragmentAfterLine;
static size_t g_DumpStatsAfterLineNextIndex = 0; static size_t g_DumpStatsAfterLineNextIndex = 0;
static size_t g_DefragmentAfterLineNextIndex = 0;
static bool ValidateFileVersion() static bool ValidateFileVersion()
{ {
@ -921,6 +924,7 @@ public:
void ApplyConfig(ConfigurationParser& configParser); void ApplyConfig(ConfigurationParser& configParser);
void ExecuteLine(size_t lineNumber, const StrRange& line); void ExecuteLine(size_t lineNumber, const StrRange& line);
void DumpStats(const char* fileNameFormat, size_t lineNumber, bool detailed); void DumpStats(const char* fileNameFormat, size_t lineNumber, bool detailed);
void Defragment();
void PrintStats(); void PrintStats();
@ -1017,6 +1021,9 @@ private:
void ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& csvSplit); void ExecuteMakePoolAllocationsLost(size_t lineNumber, const CsvSplit& csvSplit);
void DestroyAllocation(size_t lineNumber, const CsvSplit& csvSplit); void DestroyAllocation(size_t lineNumber, const CsvSplit& csvSplit);
void PrintStats(const VmaStats& stats, const char* suffix);
void PrintStatInfo(const VmaStatInfo& info);
}; };
Player::Player() Player::Player()
@ -1625,6 +1632,92 @@ void Player::RegisterDebugCallbacks()
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
void Player::Defragment()
{
VmaStats stats;
vmaCalculateStats(m_Allocator, &stats);
PrintStats(stats, "before defragmentation");
const size_t allocCount = m_Allocations.size();
std::vector<VmaAllocation> allocations(allocCount);
size_t notNullAllocCount = 0;
for(const auto& it : m_Allocations)
{
if(it.second.allocation != VK_NULL_HANDLE)
{
allocations[notNullAllocCount] = it.second.allocation;
++notNullAllocCount;
}
}
if(notNullAllocCount == 0)
{
printf(" Nothing to defragment.\n");
return;
}
allocations.resize(notNullAllocCount);
std::vector<VkBool32> allocationsChanged(notNullAllocCount);
VmaDefragmentationInfo2 defragInfo = {};
defragInfo.allocationCount = (uint32_t)notNullAllocCount;
defragInfo.pAllocations = allocations.data();
defragInfo.pAllocationsChanged = allocationsChanged.data();
defragInfo.maxCpuAllocationsToMove = UINT32_MAX;
defragInfo.maxCpuBytesToMove = VK_WHOLE_SIZE;
defragInfo.maxGpuAllocationsToMove = UINT32_MAX;
defragInfo.maxGpuBytesToMove = VK_WHOLE_SIZE;
defragInfo.flags = VMA_DEFRAGMENTATION_CAN_MAKE_LOST_BIT;
VmaDefragmentationStats defragStats = {};
VmaDefragmentationContext defragCtx = VK_NULL_HANDLE;
VkResult res = vmaDefragmentationBegin(m_Allocator, &defragInfo, &defragStats, &defragCtx);
if(res >= VK_SUCCESS)
{
// TODO use commandBuffer for GPU defrag.
vmaDefragmentationEnd(m_Allocator, defragCtx);
// If anything changed.
if(defragStats.allocationsLost > 0 || defragStats.allocationsMoved > 0)
{
// Go over allocation that changed and destroy their buffers and images.
size_t i = 0;
for(auto& it : m_Allocations)
{
if(allocationsChanged[i] != VK_FALSE)
{
if(it.second.buffer != VK_NULL_HANDLE)
{
vkDestroyBuffer(m_Device, it.second.buffer, nullptr);
it.second.buffer = VK_NULL_HANDLE;
}
if(it.second.image != VK_NULL_HANDLE)
{
vkDestroyImage(m_Device, it.second.image, nullptr);
it.second.image = VK_NULL_HANDLE;
}
}
++i;
}
}
// Print statistics
printf(" VmaDefragmentationStats:\n");
printf(" bytesMoved: %llu\n", defragStats.bytesMoved);
printf(" bytesFreed: %llu\n", defragStats.bytesFreed);
printf(" allocationsMoved: %u\n", defragStats.allocationsMoved);
printf(" deviceMemoryBlocksMoved: %u\n", defragStats.deviceMemoryBlocksFreed);
printf(" allocationsLost: %u\n", defragStats.allocationsLost);
vmaCalculateStats(m_Allocator, &stats);
PrintStats(stats, "after defragmentation");
}
else
{
printf("vmaDefragmentationBegin failed (%d).\n", res);
}
}
void Player::PrintStats() void Player::PrintStats()
{ {
if(g_Verbosity == VERBOSITY::MINIMUM) if(g_Verbosity == VERBOSITY::MINIMUM)
@ -1996,6 +2089,9 @@ void Player::ExecuteCreateBuffer(size_t lineNumber, const CsvSplit& csvSplit)
{ {
FindPool(lineNumber, origPool, allocCreateInfo.pool); FindPool(lineNumber, origPool, allocCreateInfo.pool);
// Forcing VK_SHARING_MODE_EXCLUSIVE because we use only one queue anyway.
bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if(csvSplit.GetCount() > FIRST_PARAM_INDEX + 11) if(csvSplit.GetCount() > FIRST_PARAM_INDEX + 11)
{ {
PrepareUserData( PrepareUserData(
@ -2060,6 +2156,42 @@ void Player::DestroyAllocation(size_t lineNumber, const CsvSplit& csvSplit)
} }
} }
void Player::PrintStats(const VmaStats& stats, const char* suffix)
{
printf(" VmaStats %s:\n", suffix);
printf(" total:\n");
PrintStatInfo(stats.total);
if(g_Verbosity == VERBOSITY::MAXIMUM)
{
for(uint32_t i = 0; i < m_MemProps->memoryHeapCount; ++i)
{
printf(" memoryHeap[%u]:\n", i);
PrintStatInfo(stats.memoryHeap[i]);
}
for(uint32_t i = 0; i < m_MemProps->memoryTypeCount; ++i)
{
printf(" memoryType[%u]:\n", i);
PrintStatInfo(stats.memoryType[i]);
}
}
}
void Player::PrintStatInfo(const VmaStatInfo& info)
{
printf(" blockCount: %u\n", info.blockCount);
printf(" allocationCount: %u\n", info.allocationCount);
printf(" unusedRangeCount: %u\n", info.unusedRangeCount);
printf(" usedBytes: %llu\n", info.usedBytes);
printf(" unusedBytes: %llu\n", info.unusedBytes);
printf(" allocationSizeMin: %llu\n", info.allocationSizeMin);
printf(" allocationSizeAvg: %llu\n", info.allocationSizeAvg);
printf(" allocationSizeMax: %llu\n", info.allocationSizeMax);
printf(" unusedRangeSizeMin: %llu\n", info.unusedRangeSizeMin);
printf(" unusedRangeSizeAvg: %llu\n", info.unusedRangeSizeAvg);
printf(" unusedRangeSizeMax: %llu\n", info.unusedRangeSizeMax);
}
void Player::ExecuteCreateImage(size_t lineNumber, const CsvSplit& csvSplit) void Player::ExecuteCreateImage(size_t lineNumber, const CsvSplit& csvSplit)
{ {
m_Stats.RegisterFunctionCall(VMA_FUNCTION::CreateImage); m_Stats.RegisterFunctionCall(VMA_FUNCTION::CreateImage);
@ -2094,6 +2226,9 @@ void Player::ExecuteCreateImage(size_t lineNumber, const CsvSplit& csvSplit)
{ {
FindPool(lineNumber, origPool, allocCreateInfo.pool); FindPool(lineNumber, origPool, allocCreateInfo.pool);
// Forcing VK_SHARING_MODE_EXCLUSIVE because we use only one queue anyway.
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if(csvSplit.GetCount() > FIRST_PARAM_INDEX + 20) if(csvSplit.GetCount() > FIRST_PARAM_INDEX + 20)
{ {
PrepareUserData( PrepareUserData(
@ -2620,6 +2755,8 @@ static void PrintCommandLineSyntax()
" File is written to current directory with name: VmaReplay_Line####.json.\n" " File is written to current directory with name: VmaReplay_Line####.json.\n"
" This parameter can be repeated.\n" " This parameter can be repeated.\n"
" --DumpDetailedStatsAfterLine <Line> - Like command above, but includes detailed map.\n" " --DumpDetailedStatsAfterLine <Line> - Like command above, but includes detailed map.\n"
" --DefragmentAfterLine <Line> - Defragment memory after specified source file line and print statistics.\n"
" It also prints detailed statistics to files VmaReplay_Line####_Defragment*.json\n"
" --Lines <Ranges> - Replay only limited set of lines from file\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" " 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" " --PhysicalDevice <Index> - Choice of Vulkan physical device. Default: 0.\n"
@ -2638,6 +2775,7 @@ static int ProcessFile(size_t iterationIndex, const char* data, size_t numBytes,
const bool useLineRanges = !g_LineRanges.IsEmpty(); const bool useLineRanges = !g_LineRanges.IsEmpty();
const bool useDumpStatsAfterLine = !g_DumpStatsAfterLine.empty(); const bool useDumpStatsAfterLine = !g_DumpStatsAfterLine.empty();
const bool useDefragmentAfterLine = !g_DefragmentAfterLine.empty();
LineSplit lineSplit(data, numBytes); LineSplit lineSplit(data, numBytes);
StrRange line; StrRange line;
@ -2733,6 +2871,25 @@ static int ProcessFile(size_t iterationIndex, const char* data, size_t numBytes,
++g_DumpStatsAfterLineNextIndex; ++g_DumpStatsAfterLineNextIndex;
} }
while(useDefragmentAfterLine &&
g_DefragmentAfterLineNextIndex < g_DefragmentAfterLine.size() &&
currLineNumber >= g_DefragmentAfterLine[g_DefragmentAfterLineNextIndex])
{
const size_t requestedLine = g_DefragmentAfterLine[g_DefragmentAfterLineNextIndex];
if(g_Verbosity >= VERBOSITY::DEFAULT)
{
printf("Defragmenting after line %zu actual line %zu...\n",
requestedLine,
currLineNumber);
}
player.DumpStats("VmaReplay_Line%04zu_Defragment_1Before.json", requestedLine, true);
player.Defragment();
player.DumpStats("VmaReplay_Line%04zu_Defragment_2After.json", requestedLine, true);
++g_DefragmentAfterLineNextIndex;
}
} }
const duration playDuration = std::chrono::high_resolution_clock::now() - timeBeg; const duration playDuration = std::chrono::high_resolution_clock::now() - timeBeg;
@ -2831,6 +2988,7 @@ static int main2(int argc, char** argv)
cmdLineParser.RegisterOpt(CMD_LINE_OPT_VK_LAYER_LUNARG_STANDARD_VALIDATION, VALIDATION_LAYER_NAME, 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.RegisterOpt(CMD_LINE_OPT_MEM_STATS, "MemStats", true);
cmdLineParser.RegisterOpt(CMD_LINE_OPT_DUMP_STATS_AFTER_LINE, "DumpStatsAfterLine", true); cmdLineParser.RegisterOpt(CMD_LINE_OPT_DUMP_STATS_AFTER_LINE, "DumpStatsAfterLine", true);
cmdLineParser.RegisterOpt(CMD_LINE_OPT_DEFRAGMENT_AFTER_LINE, "DefragmentAfterLine", true);
cmdLineParser.RegisterOpt(CMD_LINE_OPT_DUMP_DETAILED_STATS_AFTER_LINE, "DumpDetailedStatsAfterLine", true); cmdLineParser.RegisterOpt(CMD_LINE_OPT_DUMP_DETAILED_STATS_AFTER_LINE, "DumpDetailedStatsAfterLine", true);
CmdLineParser::RESULT res; CmdLineParser::RESULT res;
@ -2940,6 +3098,20 @@ static int main2(int argc, char** argv)
} }
} }
break; break;
case CMD_LINE_OPT_DEFRAGMENT_AFTER_LINE:
{
size_t line;
if(StrRangeToUint(StrRange(cmdLineParser.GetParameter()), line))
{
g_DefragmentAfterLine.push_back(line);
}
else
{
PrintCommandLineSyntax();
return RESULT_ERROR_COMMAND_LINE;
}
}
break;
default: default:
assert(0); assert(0);
} }
@ -2978,6 +3150,12 @@ static int main2(int argc, char** argv)
std::unique(g_DumpStatsAfterLine.begin(), g_DumpStatsAfterLine.end()), std::unique(g_DumpStatsAfterLine.begin(), g_DumpStatsAfterLine.end()),
g_DumpStatsAfterLine.end()); g_DumpStatsAfterLine.end());
// Sort g_DefragmentAfterLine and make unique.
std::sort(g_DefragmentAfterLine.begin(), g_DefragmentAfterLine.end());
g_DefragmentAfterLine.erase(
std::unique(g_DefragmentAfterLine.begin(), g_DefragmentAfterLine.end()),
g_DefragmentAfterLine.end());
return ProcessFile(); return ProcessFile();
} }