mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
synced 2024-11-30 02:04:35 +00:00
VmaReplay: Added parameter --DefragmentAfterLine.
This commit is contained in:
parent
dec65ac4eb
commit
e97495dd73
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user