Skip to content

Commit 19debfa

Browse files
committed
Arm backend: Replace VkQueueWaitIdle with fences
Use fences to wait for the submitted VGF command buffer instead of calling vkQueueWaitIdle(). This avoids stalling the whole queue and only waits for the work submitted by the backend. Create the execution fence once during VGF setup and reuse it across execute_vgf() calls by resetting it before each submission. Keep the one-shot fence helper for temporary setup submissions. Signed-off-by: Elena Zhelezina <elena.zhelezina@arm.com> Change-Id: I628680dd530738284aa5be3e356c242d2a40ca6b
1 parent 2b9e9bf commit 19debfa

2 files changed

Lines changed: 92 additions & 19 deletions

File tree

backends/arm/runtime/VGFSetup.cpp

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,38 @@ static bool is_tensor_like_descriptor_type(VkDescriptorType descriptor_type) {
486486
descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
487487
}
488488

489+
static VkResult submit_and_wait_with_fence(
490+
VkDevice device,
491+
VkQueue queue,
492+
const VkSubmitInfo* submit_info) {
493+
VkFence fence = VK_NULL_HANDLE;
494+
495+
const VkFenceCreateInfo fence_info = {
496+
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
497+
.pNext = nullptr,
498+
.flags = 0,
499+
};
500+
501+
VkResult result = vkCreateFence(device, &fence_info, nullptr, &fence);
502+
if (result != VK_SUCCESS) {
503+
ET_LOG(Error, "Failed to create Vulkan fence, error %d", result);
504+
return result;
505+
}
506+
507+
result = vkQueueSubmit(queue, 1, submit_info, fence);
508+
if (result != VK_SUCCESS) {
509+
ET_LOG(Error, "Vulkan queue submit failed, error %d", result);
510+
vkDestroyFence(device, fence, nullptr);
511+
return result;
512+
}
513+
514+
result = vkWaitForFences(
515+
device, 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
516+
517+
vkDestroyFence(device, fence, nullptr);
518+
return result;
519+
}
520+
489521
static void record_image_layout_transition(
490522
VkCommandBuffer command_buffer,
491523
VkImage image,
@@ -1278,10 +1310,11 @@ VkResult transition_image_layout(
12781310
.signalSemaphoreCount = 0,
12791311
.pSignalSemaphores = nullptr,
12801312
};
1281-
result = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
1282-
if (result == VK_SUCCESS) {
1283-
result = vkQueueWaitIdle(queue);
1284-
}
1313+
1314+
// creates a temporary one-time command buffer, submits it once, waits, and
1315+
// frees it immediately.
1316+
result = submit_and_wait_with_fence(device, queue, &submit_info);
1317+
12851318
vkFreeCommandBuffers(device, command_pool, 1, &command_buffer);
12861319
return result;
12871320
}
@@ -3078,19 +3111,33 @@ bool VgfRepr::process_vgf(
30783111
{
30793112
VGF_PROFILE_SCOPE(event_tracer, "VGF_INIT_ALLOCATE_COMMAND_BUFFER");
30803113

3081-
// Allocate command buffer
30823114
VkCommandBufferAllocateInfo buffer_allocate_info{
30833115
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
30843116
.pNext = nullptr,
30853117
.commandPool = vk_command_pool,
30863118
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
30873119
.commandBufferCount = 1};
3120+
30883121
result = vkAllocateCommandBuffers(
30893122
vk_device, &buffer_allocate_info, &vk_execute_cmd);
30903123
if (result != VK_SUCCESS) {
30913124
ET_LOG(Error, "Failed to allocate command buffers");
30923125
return false;
30933126
}
3127+
3128+
const VkFenceCreateInfo fence_info{
3129+
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
3130+
.pNext = nullptr,
3131+
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
3132+
};
3133+
3134+
result = vkCreateFence(vk_device, &fence_info, nullptr, &vk_execute_fence);
3135+
if (result != VK_SUCCESS) {
3136+
ET_LOG(Error, "Failed to create VGF execute fence, error %d", result);
3137+
vkFreeCommandBuffers(vk_device, vk_command_pool, 1, &vk_execute_cmd);
3138+
vk_execute_cmd = VK_NULL_HANDLE;
3139+
return false;
3140+
}
30943141
}
30953142

30963143
{
@@ -3392,31 +3439,51 @@ bool VgfRepr::process_vgf(
33923439
bool VgfRepr::execute_vgf(executorch::runtime::EventTracer* event_tracer) {
33933440
ET_LOG(Info, "Executing vgf");
33943441

3395-
VkSubmitInfo submit{VK_STRUCTURE_TYPE_SUBMIT_INFO};
3396-
submit.commandBufferCount = 1;
3397-
submit.pCommandBuffers = &vk_execute_cmd;
3442+
VkSubmitInfo submit{
3443+
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3444+
.pNext = nullptr,
3445+
.waitSemaphoreCount = 0,
3446+
.pWaitSemaphores = nullptr,
3447+
.pWaitDstStageMask = nullptr,
3448+
.commandBufferCount = 1,
3449+
.pCommandBuffers = &vk_execute_cmd,
3450+
.signalSemaphoreCount = 0,
3451+
.pSignalSemaphores = nullptr,
3452+
};
33983453

33993454
VkResult result;
34003455

34013456
{
3402-
VGF_PROFILE_SCOPE(event_tracer, "VGF_QUEUE_SUBMIT");
3457+
VGF_PROFILE_SCOPE(event_tracer, "VGF_QUEUE_SUBMIT_AND_WAIT_FENCE");
34033458

3404-
result = vkQueueSubmit(vk_queue, 1, &submit, VK_NULL_HANDLE);
3405-
}
3459+
if (vk_execute_fence == VK_NULL_HANDLE) {
3460+
ET_LOG(Error, "VGF execute fence is not initialized");
3461+
return false;
3462+
}
34063463

3407-
if (result != VK_SUCCESS) {
3408-
ET_LOG(Error, "VGF/VkCommandBuffer command submission failed");
3409-
return false;
3410-
}
3464+
result = vkResetFences(vk_device, 1, &vk_execute_fence);
3465+
if (result != VK_SUCCESS) {
3466+
ET_LOG(Error, "VGF/VkFence reset failed, error %d", result);
3467+
return false;
3468+
}
34113469

3412-
{
3413-
VGF_PROFILE_SCOPE(event_tracer, "VGF_QUEUE_WAIT_IDLE");
3470+
result = vkQueueSubmit(vk_queue, 1, &submit, vk_execute_fence);
3471+
if (result != VK_SUCCESS) {
3472+
ET_LOG(Error, "VGF/VkFence wait failed, error %d", result);
3473+
return false;
3474+
}
34143475

3415-
result = vkQueueWaitIdle(vk_queue);
3476+
result = vkWaitForFences(
3477+
vk_device,
3478+
1,
3479+
&vk_execute_fence,
3480+
VK_TRUE,
3481+
std::numeric_limits<uint64_t>::max());
34163482
}
34173483

34183484
if (result != VK_SUCCESS) {
3419-
ET_LOG(Error, "VGF/VkQueue wait idle failed");
3485+
ET_LOG(
3486+
Error, "VGF/VkCommandBuffer command submission or fence wait failed");
34203487
return false;
34213488
}
34223489

@@ -3431,6 +3498,11 @@ void VgfRepr::free_vgf() {
34313498
vk_timestamp_query_pool = VK_NULL_HANDLE;
34323499
}
34333500

3501+
if (vk_execute_fence != VK_NULL_HANDLE) {
3502+
vkDestroyFence(vk_device, vk_execute_fence, nullptr);
3503+
vk_execute_fence = VK_NULL_HANDLE;
3504+
}
3505+
34343506
vkFreeCommandBuffers(vk_device, vk_command_pool, 1, &vk_execute_cmd);
34353507
vector<VkDeviceMemory> owned_memory;
34363508
auto remember_owned_memory = [&](VkDeviceMemory memory) {

backends/arm/runtime/VGFSetup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class VgfRepr {
163163
// per-VgfRepr-instance objects allocated in process_vgf, used (can be more
164164
// than once) in execute_vgf
165165
VkCommandBuffer vk_execute_cmd = VK_NULL_HANDLE;
166+
VkFence vk_execute_fence = VK_NULL_HANDLE;
166167
// Note: the vector of tensor memory is stored in IOs above
167168

168169
bool init_timestamp_queries();

0 commit comments

Comments
 (0)