Module: Mesa Branch: main Commit: bb4c10f85e5f3cf08bd70b9368d6be6e31b37c72 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=bb4c10f85e5f3cf08bd70b9368d6be6e31b37c72
Author: Ryan Neph <[email protected]> Date: Wed Mar 22 12:12:21 2023 -0700 venus: add vn_relax_init/_fini() Use a new calling contract so we can do pre/post-work around every ring-waiting iteration. All looping uses of `vn_relax()` must now call `vn_relax_init()` and `vn_relax_fini()` before/after their loop bodies. Signed-off-by: Ryan Neph <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22036> --- src/virtio/vulkan/vn_common.c | 16 +++++++++++++++- src/virtio/vulkan/vn_common.h | 16 +++++++++++++++- src/virtio/vulkan/vn_instance.c | 10 ++++++---- src/virtio/vulkan/vn_queue.c | 30 ++++++++++++++++++++++-------- src/virtio/vulkan/vn_ring.c | 22 +++++++++++++--------- src/virtio/vulkan/vn_ring.h | 2 +- 6 files changed, 72 insertions(+), 24 deletions(-) diff --git a/src/virtio/vulkan/vn_common.c b/src/virtio/vulkan/vn_common.c index 967aadc6acb..0472e9369b7 100644 --- a/src/virtio/vulkan/vn_common.c +++ b/src/virtio/vulkan/vn_common.c @@ -123,9 +123,23 @@ vn_extension_get_spec_version(const char *name) return index >= 0 ? vn_info_extension_get(index)->spec_version : 0; } +struct vn_relax_state +vn_relax_init(struct vn_ring *ring, const char *reason) +{ + return (struct vn_relax_state){ + .ring = ring, + .iter = 0, + .reason = reason, + }; +} + void -vn_relax(const struct vn_ring *ring, uint32_t *iter, const char *reason) +vn_relax(struct vn_relax_state *state) { + struct vn_ring *ring = state->ring; + uint32_t *iter = &state->iter; + const char *reason = state->reason; + /* Yield for the first 2^busy_wait_order times and then sleep for * base_sleep_us microseconds for the same number of times. After that, * keep doubling both sleep length and count. diff --git a/src/virtio/vulkan/vn_common.h b/src/virtio/vulkan/vn_common.h index 59331b7772a..26477d22fb3 100644 --- a/src/virtio/vulkan/vn_common.h +++ b/src/virtio/vulkan/vn_common.h @@ -156,6 +156,12 @@ struct vn_env { }; extern struct vn_env vn_env; +struct vn_relax_state { + struct vn_ring *ring; + uint32_t iter; + const char *reason; +}; + void vn_env_init(void); @@ -223,8 +229,16 @@ vn_refcount_dec(struct vn_refcount *ref) uint32_t vn_extension_get_spec_version(const char *name); +struct vn_relax_state +vn_relax_init(struct vn_ring *ring, const char *reason); + void -vn_relax(const struct vn_ring *ring, uint32_t *iter, const char *reason); +vn_relax(struct vn_relax_state *state); + +static inline void +vn_relax_fini(struct vn_relax_state *state) +{ +} static_assert(sizeof(vn_object_id) >= sizeof(uintptr_t), ""); diff --git a/src/virtio/vulkan/vn_instance.c b/src/virtio/vulkan/vn_instance.c index aded646cba0..2c6a4e8c6c5 100644 --- a/src/virtio/vulkan/vn_instance.c +++ b/src/virtio/vulkan/vn_instance.c @@ -321,15 +321,17 @@ vn_instance_wait_roundtrip(struct vn_instance *instance, return; } - const struct vn_ring *ring = &instance->ring.ring; + struct vn_ring *ring = &instance->ring.ring; const volatile atomic_uint *ptr = ring->shared.extra; - uint32_t iter = 0; + struct vn_relax_state relax_state = vn_relax_init(ring, "roundtrip"); do { const uint32_t cur = atomic_load_explicit(ptr, memory_order_acquire); /* clamp to 32bit for legacy ring extra based roundtrip waiting */ - if (roundtrip_seqno_ge(cur, roundtrip_seqno)) + if (roundtrip_seqno_ge(cur, roundtrip_seqno)) { + vn_relax_fini(&relax_state); break; - vn_relax(ring, &iter, "roundtrip"); + } + vn_relax(&relax_state); } while (true); } diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c index c01c2352789..fb6f4021d04 100644 --- a/src/virtio/vulkan/vn_queue.c +++ b/src/virtio/vulkan/vn_queue.c @@ -1286,7 +1286,7 @@ static VkResult vn_update_sync_result(struct vn_device *dev, VkResult result, int64_t abs_timeout, - uint32_t *iter) + struct vn_relax_state *relax_state) { switch (result) { case VK_NOT_READY: @@ -1294,7 +1294,7 @@ vn_update_sync_result(struct vn_device *dev, os_time_get_nano() >= abs_timeout) result = VK_TIMEOUT; else - vn_relax(&dev->instance->ring.ring, iter, "client"); + vn_relax(relax_state); break; default: assert(result == VK_SUCCESS || result < 0); @@ -1317,7 +1317,6 @@ vn_WaitForFences(VkDevice device, const int64_t abs_timeout = os_time_get_absolute_timeout(timeout); VkResult result = VK_NOT_READY; - uint32_t iter = 0; if (fenceCount > 1 && waitAll) { VkFence local_fences[8]; VkFence *fences = local_fences; @@ -1330,18 +1329,26 @@ vn_WaitForFences(VkDevice device, } memcpy(fences, pFences, sizeof(*fences) * fenceCount); + struct vn_relax_state relax_state = + vn_relax_init(&dev->instance->ring.ring, "client"); while (result == VK_NOT_READY) { result = vn_remove_signaled_fences(device, fences, &fenceCount); - result = vn_update_sync_result(dev, result, abs_timeout, &iter); + result = + vn_update_sync_result(dev, result, abs_timeout, &relax_state); } + vn_relax_fini(&relax_state); if (fences != local_fences) vk_free(alloc, fences); } else { + struct vn_relax_state relax_state = + vn_relax_init(&dev->instance->ring.ring, "client"); while (result == VK_NOT_READY) { result = vn_find_first_signaled_fence(device, pFences, fenceCount); - result = vn_update_sync_result(dev, result, abs_timeout, &iter); + result = + vn_update_sync_result(dev, result, abs_timeout, &relax_state); } + vn_relax_fini(&relax_state); } return vn_result(dev->instance, result); @@ -1812,7 +1819,6 @@ vn_WaitSemaphores(VkDevice device, const int64_t abs_timeout = os_time_get_absolute_timeout(timeout); VkResult result = VK_NOT_READY; - uint32_t iter = 0; if (pWaitInfo->semaphoreCount > 1 && !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT)) { uint32_t semaphore_count = pWaitInfo->semaphoreCount; @@ -1833,21 +1839,29 @@ vn_WaitSemaphores(VkDevice device, sizeof(*semaphores) * semaphore_count); memcpy(values, pWaitInfo->pValues, sizeof(*values) * semaphore_count); + struct vn_relax_state relax_state = + vn_relax_init(&dev->instance->ring.ring, "client"); while (result == VK_NOT_READY) { result = vn_remove_signaled_semaphores(device, semaphores, values, &semaphore_count); - result = vn_update_sync_result(dev, result, abs_timeout, &iter); + result = + vn_update_sync_result(dev, result, abs_timeout, &relax_state); } + vn_relax_fini(&relax_state); if (semaphores != local_semaphores) vk_free(alloc, semaphores); } else { + struct vn_relax_state relax_state = + vn_relax_init(&dev->instance->ring.ring, "client"); while (result == VK_NOT_READY) { result = vn_find_first_signaled_semaphore( device, pWaitInfo->pSemaphores, pWaitInfo->pValues, pWaitInfo->semaphoreCount); - result = vn_update_sync_result(dev, result, abs_timeout, &iter); + result = + vn_update_sync_result(dev, result, abs_timeout, &relax_state); } + vn_relax_fini(&relax_state); } return vn_result(dev->instance, result); diff --git a/src/virtio/vulkan/vn_ring.c b/src/virtio/vulkan/vn_ring.c index a315dbbdb99..4e9ac3b3acf 100644 --- a/src/virtio/vulkan/vn_ring.c +++ b/src/virtio/vulkan/vn_ring.c @@ -89,17 +89,19 @@ vn_ring_retire_submits(struct vn_ring *ring, uint32_t seqno) } static uint32_t -vn_ring_wait_seqno(const struct vn_ring *ring, uint32_t seqno) +vn_ring_wait_seqno(struct vn_ring *ring, uint32_t seqno) { /* A renderer wait incurs several hops and the renderer might poll * repeatedly anyway. Let's just poll here. */ - uint32_t iter = 0; + struct vn_relax_state relax_state = vn_relax_init(ring, "ring seqno"); do { const uint32_t head = vn_ring_load_head(ring); - if (vn_ring_ge_seqno(ring, head, seqno)) + if (vn_ring_ge_seqno(ring, head, seqno)) { + vn_relax_fini(&relax_state); return head; - vn_relax(ring, &iter, "ring seqno"); + } + vn_relax(&relax_state); } while (true); } @@ -118,7 +120,7 @@ vn_ring_has_space(const struct vn_ring *ring, } static uint32_t -vn_ring_wait_space(const struct vn_ring *ring, uint32_t size) +vn_ring_wait_space(struct vn_ring *ring, uint32_t size) { assert(size <= ring->buffer_size); @@ -130,11 +132,13 @@ vn_ring_wait_space(const struct vn_ring *ring, uint32_t size) VN_TRACE_FUNC(); /* see the reasoning in vn_ring_wait_seqno */ - uint32_t iter = 0; + struct vn_relax_state relax_state = vn_relax_init(ring, "ring space"); do { - vn_relax(ring, &iter, "ring space"); - if (vn_ring_has_space(ring, size, &head)) + vn_relax(&relax_state); + if (vn_ring_has_space(ring, size, &head)) { + vn_relax_fini(&relax_state); return head; + } } while (true); } } @@ -263,7 +267,7 @@ vn_ring_submit(struct vn_ring *ring, * This is thread-safe. */ void -vn_ring_wait(const struct vn_ring *ring, uint32_t seqno) +vn_ring_wait(struct vn_ring *ring, uint32_t seqno) { vn_ring_wait_seqno(ring, seqno); } diff --git a/src/virtio/vulkan/vn_ring.h b/src/virtio/vulkan/vn_ring.h index 970cce73c04..892c3616b14 100644 --- a/src/virtio/vulkan/vn_ring.h +++ b/src/virtio/vulkan/vn_ring.h @@ -96,7 +96,7 @@ vn_ring_submit(struct vn_ring *ring, uint32_t *seqno); void -vn_ring_wait(const struct vn_ring *ring, uint32_t seqno); +vn_ring_wait(struct vn_ring *ring, uint32_t seqno); bool vn_ring_fatal(const struct vn_ring *ring);
