From 86954c766fac7e56985d8d435c7773ec663c641b Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Tue, 16 Jan 2024 14:41:23 +0000 Subject: [PATCH] radv: Ensure vkGetQueryPoolResults returns in finite-time When a device lost occured, we were not ensuring that vkGetQueryPoolResults with VK_QUERY_RESULT_WAIT_BIT was returning. We could have the caller stuck in our while(...) loop polling the query atomics forever which violates the finite-time guarantees of this function. This solves that by adding a timeout to this call to be double the default TDR timeout for the potential queues relating to this query. Signed-off-by: Joshua Ashton Reviewed-by: Samuel Pitoiset Reviewed-by: Friedrich Vock Part-of: --- src/amd/vulkan/radv_query.c | 66 +++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/src/amd/vulkan/radv_query.c b/src/amd/vulkan/radv_query.c index 13330ea5eb5..8ee45b1b963 100644 --- a/src/amd/vulkan/radv_query.c +++ b/src/amd/vulkan/radv_query.c @@ -1332,6 +1332,27 @@ radv_DestroyQueryPool(VkDevice _device, VkQueryPool _pool, const VkAllocationCal radv_destroy_query_pool(device, pAllocator, pool); } +static inline uint64_t +radv_get_rel_timeout_for_query(VkQueryType type) +{ + /* + * Certain queries are only possible on certain types of queues + * so pick the TDR timeout of the highest possible type + * and double it to ensure GetQueryPoolResults completes in finite-time. + * + * (compute has longer TDR than gfx, other rings) + */ + switch (type) { + case VK_QUERY_TYPE_OCCLUSION: + case VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT: + case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT: + case VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT: + return radv_get_tdr_timeout_for_ip(AMD_IP_GFX) * 2; + default: + return radv_get_tdr_timeout_for_ip(AMD_IP_COMPUTE) * 2; + } +} + VKAPI_ATTR VkResult VKAPI_CALL radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) @@ -1349,6 +1370,8 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first unsigned query = firstQuery + query_idx; char *src = pool->ptr + query * pool->stride; uint32_t available; + bool timed_out = false; + uint64_t atimeout = os_time_get_absolute_timeout(radv_get_rel_timeout_for_query(pool->vk.query_type)); switch (pool->vk.query_type) { case VK_QUERY_TYPE_TIMESTAMP: @@ -1361,11 +1384,14 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first do { value = p_atomic_read(&src64->value); - } while (value == TIMESTAMP_NOT_READY && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (value == TIMESTAMP_NOT_READY && (flags & VK_QUERY_RESULT_WAIT_BIT) && + !(timed_out = (atimeout < os_time_get_nano()))); available = value != TIMESTAMP_NOT_READY; - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; if (flags & VK_QUERY_RESULT_64_BIT) { @@ -1395,7 +1421,8 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first do { start = p_atomic_read(&src64[2 * i].value); end = p_atomic_read(&src64[2 * i + 1].value); - } while ((!(start & (1ull << 63)) || !(end & (1ull << 63))) && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while ((!(start & (1ull << 63)) || !(end & (1ull << 63))) && (flags & VK_QUERY_RESULT_WAIT_BIT) && + !(timed_out = (atimeout < os_time_get_nano()))); if (!(start & (1ull << 63)) || !(end & (1ull << 63))) available = 0; @@ -1404,7 +1431,9 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first } } - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; if (flags & VK_QUERY_RESULT_64_BIT) { @@ -1435,9 +1464,11 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first if (!(p_atomic_read(avail_ptr_start) & 0x80000000) || !(p_atomic_read(avail_ptr_stop) & 0x80000000)) available = 0; } - } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT) && !(timed_out = (atimeout < os_time_get_nano()))); - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; const uint64_t *start = (uint64_t *)src; @@ -1485,9 +1516,11 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first if (!(p_atomic_read(&src64[j].value) & 0x8000000000000000UL)) available = 0; } - } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT) && !(timed_out = (atimeout < os_time_get_nano()))); - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; num_primitives_written = p_atomic_read_relaxed(&src64[3].value) - p_atomic_read_relaxed(&src64[1].value); @@ -1531,9 +1564,11 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first !(p_atomic_read(&src64[5].value) & 0x8000000000000000UL))) { available = 0; } - } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT) && !(timed_out = (atimeout < os_time_get_nano()))); - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; primitive_storage_needed = p_atomic_read_relaxed(&src64[2].value) - p_atomic_read_relaxed(&src64[0].value); @@ -1563,7 +1598,7 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first for (unsigned i = 0; i < pc_pool->num_passes; ++i) if (!p_atomic_read(&src64[pool->stride / 8 - i - 1].value)) avail = false; - } while (!avail && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (!avail && (flags & VK_QUERY_RESULT_WAIT_BIT) && !(timed_out = (atimeout < os_time_get_nano()))); available = avail; @@ -1581,9 +1616,11 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first !(p_atomic_read(&src64[1].value) & 0x8000000000000000UL)) { available = 0; } - } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT)); + } while (!available && (flags & VK_QUERY_RESULT_WAIT_BIT) && !(timed_out = (atimeout < os_time_get_nano()))); - if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) + if (timed_out) + result = VK_ERROR_DEVICE_LOST; + else if (!available && !(flags & VK_QUERY_RESULT_PARTIAL_BIT)) result = VK_NOT_READY; ms_prim_gen = p_atomic_read_relaxed(&src64[1].value) - p_atomic_read_relaxed(&src64[0].value); @@ -1612,6 +1649,9 @@ radv_GetQueryPoolResults(VkDevice _device, VkQueryPool queryPool, uint32_t first } } + if (result == VK_ERROR_DEVICE_LOST) + vk_device_set_lost(&device->vk, "GetQueryPoolResults timed out"); + return result; }