Vulkan中GPU执行时间
本文总结Vulkan中使用QueryPool记录GPU执行时间的方法。
记录GPU执行时间需要用到 VkQueryPool
的
VK_QUERY_TYPE_TIMESTAMP
查询类型。 在程序中使用方法:
声明变量
VkQueryPool m_QueryPool;
。
创建 QueryPool 对象
1 | const VkQueryPoolCreateInfo queryPoolCreateInfo = |
记录时间戳
根据不同的 PIPELINE Stage,比如transfer 或者 compute stage 等,在执行开始和执行结束分别打上时间戳。
1 | vkCmdWriteTimestamp(cmd_buf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_QueryPool, offset); |
查询时间戳
需要延后查询,如果程序是online需要在下一帧开始查询,有可能GPU未执行完成没有查询结果。如果是offline,则可以在等待GPU操作完成,比如
vkWaitForFences()
后查询。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// timestampPeriod is the number of nanoseconds per timestamp value increment
double microsecondsPerTick = (1e-3f * m_pDevice->GetPhysicalDeviceProperries().limits.timestampPeriod);
UINT64 TimingsInTicks[256] = {};
VkResult res = vkGetQueryPoolResults(m_pDevice->GetDevice(), m_QueryPool, offset, measurements, measurements * sizeof(UINT64), &TimingsInTicks, sizeof(UINT64), VK_QUERY_RESULT_64_BIT);
if (res == VK_SUCCESS)
{
for (uint32_t i = 1; i < measurements; i++)
{
float ts = float(microsecondsPerTick * (double)(TimingsInTicks[i] - TimingsInTicks[i - 1]));
}
// compute total
float ts = float(microsecondsPerTick * (double)(TimingsInTicks[measurements - 1] - TimingsInTicks[0]));
}
获取一组queries的状态和结果:
1 | // Provided by VK_VERSION_1_0 |
device
持有该query pool的逻辑设备。queryPool
管理着包含所求结果的queries的query pool。firstQuery
第一个query的索引。queryCount
要读取的queries的数量。dataSize
pData所指向的缓冲的字节大小。pData
指向一个由用户分配的缓冲,结果将写入该缓冲中。stride
在pData中,queries的每个结果之间的字节跨度。flags
一个VkQueryResultFlagBits的bitmask,指出了结果将如何与何时返回。
查询返回的值为 microsecond(us),需要转换成 millisecond(ms)。
重置QueryPool
记录前或者获取完查询结果后进行重置。必须需要在
vkBeginCommandBuffer()
后使用。 1
vkCmdResetQueryPool(cmd_buf, m_QueryPool, offset, MaxValuesPerFrame);
参考: