Compare commits

...

4 Commits

Author SHA1 Message Date
Ruben Ortlam 5ea81d6c28 clean up circular dependency 2026-08-02 11:04:44 +02:00
Ruben Ortlam 058e3e39f5 use logging macros, throw instead of aborting 2026-07-31 15:23:19 +02:00
Ruben Ortlam 18bcd1f9ba fix submission threshold applied too late 2026-07-31 15:23:19 +02:00
Ruben Ortlam b5f9f146f7 vulkan: add debug tooling to get more information about a DeviceLost error 2026-07-31 15:23:19 +02:00
+232 -33
View File
@@ -186,13 +186,22 @@ static bool is_pow2(uint32_t x) { return x > 1 && (x & (x-1)) == 0; }
#define VK_DEVICE_DESCRIPTOR_POOL_SIZE 256
#define VK_CHECK(err, msg) \
#define VK_CHECK(err, msg, dev) \
do { \
vk::Result err_ = (err); \
vk::Result err_; \
try { \
err_ = (err); \
} catch (vk::DeviceLostError &) { \
ggml_vk_print_device_lost_info(dev); \
GGML_LOG_ERROR("ggml_vulkan: %s at %s:%d\n", \
#err, __FILE__, __LINE__); \
throw; \
} \
if (err_ != vk::Result::eSuccess) { \
fprintf(stderr, "ggml_vulkan: %s error %s at %s:%d\n", \
GGML_LOG_ERROR("ggml_vulkan: %s error %s at %s:%d\n", \
#err, to_string(err_).c_str(), __FILE__, __LINE__); \
exit(1); \
throw vk::SystemError(vk::make_error_code(err_), \
"ggml_vulkan: " msg); \
} \
} while (0)
@@ -302,9 +311,13 @@ struct vk_command_pool {
}
};
static void ggml_vk_print_device_fault_info(const vk_device& device);
static void ggml_vk_print_device_lost_info(const vk_device& device);
// Prevent simultaneous submissions to the same queue.
struct vk_queue_handle {
vk::Queue queue;
vk_device_ref device;
virtual void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) = 0;
virtual void lock() {} // no-op by default (internally synchronized case)
virtual void unlock() {}
@@ -315,7 +328,14 @@ struct vk_queue_handle_synchronized : vk_queue_handle {
std::mutex mutex;
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
std::lock_guard<std::mutex> guard(mutex);
queue.submit(submits, fence);
try {
queue.submit(submits, fence);
} catch (vk::DeviceLostError &) {
if (auto dev = device.lock()) {
ggml_vk_print_device_lost_info(dev);
}
throw;
}
}
void lock() override { mutex.lock(); }
void unlock() override { mutex.unlock(); }
@@ -324,7 +344,14 @@ struct vk_queue_handle_synchronized : vk_queue_handle {
struct vk_queue_handle_unsynchronized : vk_queue_handle {
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
// Driver guarantees internal synchronization via VK_KHR_internally_synchronized_queues
queue.submit(submits, fence);
try {
queue.submit(submits, fence);
} catch (vk::DeviceLostError &) {
if (auto dev = device.lock()) {
ggml_vk_print_device_lost_info(dev);
}
throw;
}
}
// lock()/unlock() inherited no-ops
};
@@ -811,6 +838,15 @@ struct vk_device_struct {
bool pipeline_executable_properties_support {};
bool device_fault {};
PFN_vkGetDeviceFaultInfoEXT pfn_vkGetDeviceFaultInfoEXT {};
bool serialize_submissions {};
const ggml_cgraph * diag_cgraph {};
int diag_prev_start = -1;
int diag_prev_end = -1;
size_t idx;
bool mul_mat_l[GGML_TYPE_COUNT];
@@ -1092,6 +1128,57 @@ void vk_command_pool::destroy(vk::Device& device) {
cmd_buffers.clear();
}
static void ggml_vk_print_device_fault_info(const vk_device& device) {
if (!device->device_fault || !device->pfn_vkGetDeviceFaultInfoEXT) {
return;
}
VkDeviceFaultCountsEXT fault_counts {};
fault_counts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
VkResult res = device->pfn_vkGetDeviceFaultInfoEXT(device->device, &fault_counts, nullptr);
if (res != VK_SUCCESS) {
GGML_LOG_ERROR("ggml_vulkan: vkGetDeviceFaultInfoEXT (counts) failed: %d\n", res);
return;
}
std::vector<VkDeviceFaultAddressInfoEXT> address_infos(fault_counts.addressInfoCount);
std::vector<VkDeviceFaultVendorInfoEXT> vendor_infos(fault_counts.vendorInfoCount);
VkDeviceFaultInfoEXT fault_info {};
fault_info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
fault_info.pAddressInfos = address_infos.data();
fault_info.pVendorInfos = vendor_infos.data();
res = device->pfn_vkGetDeviceFaultInfoEXT(device->device, &fault_counts, &fault_info);
if (res != VK_SUCCESS) {
GGML_LOG_ERROR("ggml_vulkan: vkGetDeviceFaultInfoEXT (info) failed: %d\n", res);
return;
}
if (fault_counts.addressInfoCount == 0 && fault_counts.vendorInfoCount == 0 && fault_info.description[0] == '\0') {
return;
}
if (fault_info.description[0] != '\0') {
GGML_LOG_ERROR("ggml_vulkan: device fault on %s: %s\n", device->name.c_str(), fault_info.description);
}
for (uint32_t i = 0; i < fault_counts.addressInfoCount; i++) {
const auto& info = address_infos[i];
GGML_LOG_CONT(" address fault %u: type=%d address=0x%llx precision=0x%llx\n",
i, (int)info.addressType,
(unsigned long long)info.reportedAddress,
(unsigned long long)info.addressPrecision);
}
for (uint32_t i = 0; i < fault_counts.vendorInfoCount; i++) {
const auto& info = vendor_infos[i];
GGML_LOG_CONT(" vendor fault %u: %s (code=0x%llx data=0x%llx)\n",
i, info.description,
(unsigned long long)info.vendorFaultCode,
(unsigned long long)info.vendorFaultData);
}
}
struct vk_buffer_struct {
vk::Buffer buffer = VK_NULL_HANDLE;
vk::DeviceMemory device_memory = VK_NULL_HANDLE;
@@ -2014,6 +2101,36 @@ static uint64_t ggml_vk_get_node_flops(const ggml_tensor * node) {
return 0;
}
static void ggml_vk_print_node_list(const ggml_cgraph * cgraph, int start, int end) {
uint64_t total_flops = 0;
int n_ops = 0;
for (int j = start; j <= end && j < cgraph->n_nodes; j++) {
uint64_t flops = ggml_vk_get_node_flops(cgraph->nodes[j]);
total_flops += flops;
n_ops++;
if (flops > 0) {
GGML_LOG_CONT(" node %d: %s (%s) [%.2f GFLOP]\n",
j, cgraph->nodes[j]->name, ggml_op_name(cgraph->nodes[j]->op),
flops / 1e9);
} else {
GGML_LOG_CONT(" node %d: %s (%s)\n",
j, cgraph->nodes[j]->name, ggml_op_name(cgraph->nodes[j]->op));
}
}
GGML_LOG_CONT(" total: %d ops, %.2f GFLOP\n", n_ops, total_flops / 1e9);
}
static void ggml_vk_print_device_lost_info(const vk_device& device) {
ggml_vk_print_device_fault_info(device);
if (device->serialize_submissions && device->diag_cgraph != nullptr && device->diag_prev_start >= 0) {
GGML_LOG_ERROR("ggml_vulkan: device lost on %s, likely caused by previous submission (nodes %d to %d):\n",
device->name.c_str(), device->diag_prev_start, device->diag_prev_end);
ggml_vk_print_node_list(device->diag_cgraph, device->diag_prev_start, device->diag_prev_end);
} else {
GGML_LOG_ERROR("ggml_vulkan: device lost on %s\n", device->name.c_str());
}
}
class vk_perf_logger {
public:
void print_timings(bool force = false) {
@@ -2426,17 +2543,27 @@ static void ggml_vk_wait_for_fence(ggml_backend_vk_context * ctx) {
// Use waitForFences while most of the graph executes. Hopefully the CPU can sleep
// during this wait.
if (ctx->almost_ready_fence_pending) {
VK_CHECK(ctx->device->device.waitForFences({ ctx->almost_ready_fence }, true, UINT64_MAX), "almost_ready_fence");
VK_CHECK(ctx->device->device.waitForFences({ ctx->almost_ready_fence }, true, UINT64_MAX), "almost_ready_fence", ctx->device);
ctx->device->device.resetFences({ ctx->almost_ready_fence });
ctx->almost_ready_fence_pending = false;
}
// Spin (w/pause) waiting for the graph to finish executing.
vk::Result result;
while ((result = ctx->device->device.getFenceStatus(ctx->fence)) != vk::Result::eSuccess) {
for (;;) {
try {
result = ctx->device->device.getFenceStatus(ctx->fence);
} catch (vk::DeviceLostError &) {
ggml_vk_print_device_lost_info(ctx->device);
GGML_LOG_ERROR("ggml_vulkan: getFenceStatus at %s:%d\n", __FILE__, __LINE__);
throw;
}
if (result == vk::Result::eSuccess) {
break;
}
if (result != vk::Result::eNotReady) {
fprintf(stderr, "ggml_vulkan: error %s at %s:%d\n", to_string(result).c_str(), __FILE__, __LINE__);
exit(1);
GGML_LOG_ERROR("ggml_vulkan: error %s at %s:%d\n", to_string(result).c_str(), __FILE__, __LINE__);
throw vk::SystemError(vk::make_error_code(result), "ggml_vulkan: getFenceStatus");
}
for (uint32_t i = 0; i < 100; ++i) {
YIELD();
@@ -3127,6 +3254,7 @@ static std::unique_ptr<vk_queue> ggml_vk_create_queue(vk_device& device, uint32_
}
h->queue = device->device.getQueue2(queue_info2);
h->device = device;
q->handle = h;
q->cmd_pool.init(device, q.get());
@@ -6067,6 +6195,8 @@ static vk_device ggml_vk_get_device(size_t idx) {
#endif
} else if (strcmp(VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME, properties.extensionName) == 0) {
internally_sync_support = true;
} else if (strcmp("VK_EXT_device_fault", properties.extensionName) == 0) {
device->device_fault = true;
}
}
@@ -6421,8 +6551,18 @@ static vk_device ggml_vk_get_device(size_t idx) {
}
#endif
VkPhysicalDeviceFaultFeaturesEXT fault_features {};
fault_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
if (device->device_fault) {
last_struct->pNext = (VkBaseOutStructure *)&fault_features;
last_struct = (VkBaseOutStructure *)&fault_features;
device_extensions.push_back("VK_EXT_device_fault");
}
vkGetPhysicalDeviceFeatures2(device->physical_device, &device_features2);
device->device_fault = device->device_fault && fault_features.deviceFault;
device->has_internally_synchronized_queues = internally_synchronized_queues_features.internallySynchronizedQueues;
// Build queue create infos only after querying whether internally synchronized queues are enabled.
@@ -6721,6 +6861,11 @@ static vk_device ggml_vk_get_device(size_t idx) {
device_create_info.setPNext(&device_features2);
device->device = device->physical_device.createDevice(device_create_info);
if (device->device_fault) {
device->pfn_vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT)
vkGetDeviceProcAddr(device->device, "vkGetDeviceFaultInfoEXT");
}
// Queues
device->compute_queue = ggml_vk_create_queue(device, compute_queue_family_index, 0, { vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer }, false);
@@ -6843,6 +6988,8 @@ static vk_device ggml_vk_get_device(size_t idx) {
device->idx = idx;
device->serialize_submissions = getenv("GGML_VK_SERIALIZE_SUBMISSIONS") != nullptr;
device->disable_fusion = getenv("GGML_VK_DISABLE_FUSION") != nullptr;
device->add_rms_fusion = !device->disable_fusion &&
@@ -8269,7 +8416,7 @@ static void ggml_vk_buffer_write_2d(vk_buffer& dst, size_t offset, const void *
}
ggml_vk_submit(subctx, dst->device->fence);
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_buffer_write_2d waitForFences");
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_buffer_write_2d waitForFences", dst->device);
dst->device->device.resetFences({ dst->device->fence });
ggml_vk_queue_command_pools_cleanup(dst->device);
}
@@ -8381,7 +8528,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
ggml_vk_ctx_end(subctx);
ggml_vk_submit(subctx, src->device->fence);
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX),
"vk_buffer_read_2d uma waitForFences");
"vk_buffer_read_2d uma waitForFences", src->device);
src->device->device.resetFences({ src->device->fence });
ggml_vk_queue_command_pools_cleanup(src->device);
@@ -8402,7 +8549,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
ggml_vk_ctx_end(subctx);
ggml_vk_submit(subctx, src->device->fence);
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_read_2d waitForFences");
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_read_2d waitForFences", src->device);
src->device->device.resetFences({ src->device->fence });
ggml_vk_queue_command_pools_cleanup(src->device);
@@ -8437,7 +8584,7 @@ static void ggml_vk_buffer_copy(vk_buffer& dst, size_t dst_offset, vk_buffer& sr
ggml_vk_buffer_copy_async(subctx, dst, dst_offset, src, src_offset, size);
ggml_vk_ctx_end(subctx);
ggml_vk_submit(subctx, src->device->fence);
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_copy waitForFences");
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_copy waitForFences", src->device);
src->device->device.resetFences({ src->device->fence });
ggml_vk_queue_command_pools_cleanup(src->device);
} else {
@@ -8481,7 +8628,7 @@ static void ggml_vk_buffer_memset(vk_buffer& dst, size_t offset, uint32_t c, siz
ggml_vk_ctx_end(subctx);
ggml_vk_submit(subctx, dst->device->fence);
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_memset waitForFences");
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_memset waitForFences", dst->device);
dst->device->device.resetFences({ dst->device->fence });
ggml_vk_queue_command_pools_cleanup(dst->device);
}
@@ -14129,7 +14276,7 @@ static void ggml_vk_test_matmul(ggml_backend_vk_context * ctx, size_t m, size_t
auto begin = std::chrono::high_resolution_clock::now();
ggml_vk_submit(subctx, ctx->fence);
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_matmul waitForFences");
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_matmul waitForFences", ctx->device);
ctx->device->device.resetFences({ ctx->fence });
ggml_vk_queue_command_pools_cleanup(ctx->device);
@@ -14331,7 +14478,7 @@ static void ggml_vk_test_dequant(ggml_backend_vk_context * ctx, size_t ne, ggml_
auto begin = std::chrono::high_resolution_clock::now();
ggml_vk_submit(subctx, ctx->fence);
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences");
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences", ctx->device);
ctx->device->device.resetFences({ ctx->fence });
ggml_vk_queue_command_pools_cleanup(ctx->device);
@@ -14617,7 +14764,7 @@ static void ggml_vk_test_dequant_matmul(ggml_backend_vk_context * ctx, size_t m,
auto begin = std::chrono::high_resolution_clock::now();
ggml_vk_submit(subctx, ctx->fence);
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences");
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences", ctx->device);
ctx->device->device.resetFences({ ctx->fence });
ggml_vk_queue_command_pools_cleanup(ctx->device);
@@ -15407,7 +15554,9 @@ static void ggml_vk_compute_forward(ggml_backend_vk_context * ctx, ggml_cgraph *
memset(mset.dst, mset.val, mset.n);
}
if (almost_ready && !ctx->almost_ready_fence_pending) {
if (ctx->device->serialize_submissions) {
ggml_vk_submit(subctx, ctx->fence);
} else if (almost_ready && !ctx->almost_ready_fence_pending) {
ggml_vk_submit(subctx, ctx->almost_ready_fence);
ctx->almost_ready_fence_pending = true;
} else {
@@ -16018,12 +16167,20 @@ static void ggml_vk_synchronize(ggml_backend_vk_context * ctx) {
memcpy(cpy.dst, cpy.src, cpy.n);
}
ggml_vk_submit(compute_ctx, {});
if (ctx->device->serialize_submissions) {
ggml_vk_submit(compute_ctx, ctx->fence);
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "synchronize waitForFences", ctx->device);
ctx->device->device.resetFences({ ctx->fence });
} else {
ggml_vk_submit(compute_ctx, {});
}
ctx->submit_pending = true;
}
if (ctx->submit_pending) {
if (ctx->device->async_use_transfer_queue && ctx->transfer_semaphore_last_submitted < ctx->transfer_semaphore.value) {
if (ctx->device->serialize_submissions) {
ctx->submit_pending = false;
} else if (ctx->device->async_use_transfer_queue && ctx->transfer_semaphore_last_submitted < ctx->transfer_semaphore.value) {
vk::TimelineSemaphoreSubmitInfo tl_info{
1, &ctx->transfer_semaphore.value,
0, nullptr,
@@ -16040,7 +16197,9 @@ static void ggml_vk_synchronize(ggml_backend_vk_context * ctx) {
} else {
ctx->device->compute_queue->handle->submit({}, ctx->fence);
}
ggml_vk_wait_for_fence(ctx);
if (!ctx->device->serialize_submissions) {
ggml_vk_wait_for_fence(ctx);
}
ctx->submit_pending = false;
if (cmd_buf) {
cmd_buf->in_use = false;
@@ -16596,6 +16755,10 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
VK_LOG_DEBUG("ggml_backend_vk_graph_compute(" << cgraph->n_nodes << " nodes)");
ggml_backend_vk_context * ctx = (ggml_backend_vk_context *)backend->context;
ctx->device->diag_cgraph = nullptr;
ctx->device->diag_prev_start = -1;
ctx->device->diag_prev_end = -1;
if (vk_instance.debug_utils_support) {
vk::DebugUtilsLabelEXT dul = {};
dul.pLabelName = "ggml_backend_vk_graph_compute";
@@ -16687,6 +16850,36 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
}
uint64_t flops_per_submit = std::min(flops_cap, ctx->last_total_flops / 40u);
auto const submit_after = [&](int start, int end) {
if (ctx->device->serialize_submissions) {
try {
auto res = ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX);
if (res != vk::Result::eSuccess) {
GGML_LOG_ERROR("ggml_vulkan: waitForFences error during serialized submission\n");
throw vk::SystemError(vk::make_error_code(res), "ggml_vulkan: waitForFences during serialized submission");
}
} catch (vk::DeviceLostError &) {
ggml_vk_print_device_fault_info(ctx->device);
GGML_LOG_ERROR("ggml_vulkan: device lost on %s waiting for submission (nodes %d to %d):\n",
ctx->device->name.c_str(), start, end);
ggml_vk_print_node_list(cgraph, start, end);
throw;
}
ctx->device->device.resetFences({ ctx->fence });
ctx->submit_pending = false;
ctx->device->diag_cgraph = cgraph;
ctx->device->diag_prev_start = start;
ctx->device->diag_prev_end = end;
}
first_node_in_batch = true;
submitted_nodes = 0;
batch_flops = 0;
if (submit_count < 3) {
flops_per_submit *= 2;
}
submit_count++;
};
for (int i = 0; i < cgraph->n_nodes; i++) {
if (first_node_in_batch) {
submit_node_idx = i;
@@ -16694,8 +16887,20 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
{
auto node_flops = ggml_vk_get_node_flops(cgraph->nodes[i]);
batch_flops += node_flops;
total_flops += node_flops;
// Flush the current batch before recording a node that would push it over the flop threshold
if (flops_per_submit != 0 && submitted_nodes > 0 && batch_flops + node_flops >= flops_per_submit) {
vk_context flush_ctx = ggml_vk_get_compute_ctx(ctx);
ggml_vk_ctx_end(flush_ctx);
flush_ctx->exit_tensor_idx = -1;
ctx->compute_ctx.reset();
ggml_vk_compute_forward(ctx, cgraph, cgraph->nodes[submit_node_idx], submit_node_idx, false);
submit_after(submit_node_idx, i - 1);
submit_node_idx = i;
}
batch_flops += node_flops;
}
// op_srcs_fused_elementwise indicates whether an op's srcs all contribute to
@@ -16940,13 +17145,7 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
}
if (submit && enqueued) {
first_node_in_batch = true;
submitted_nodes = 0;
batch_flops = 0;
if (submit_count < 3) {
flops_per_submit *= 2;
}
submit_count++;
submit_after(submit_node_idx, i + (int)ctx->num_additional_fused_ops);
}
i += ctx->num_additional_fused_ops;
ctx->num_additional_fused_ops = 0;
@@ -16962,13 +17161,13 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
ggml_vk_ctx_end(compute_ctx);
ggml_vk_submit(compute_ctx, ctx->device->fence);
VK_CHECK(ctx->device->device.waitForFences({ ctx->device->fence }, true, UINT64_MAX), "GGML_VULKAN_PERF waitForFences");
VK_CHECK(ctx->device->device.waitForFences({ ctx->device->fence }, true, UINT64_MAX), "GGML_VULKAN_PERF waitForFences", ctx->device);
ctx->device->device.resetFences({ ctx->device->fence });
ctx->compute_ctx.reset();
// Get the results and pass them to the logger
std::vector<uint64_t> timestamps(cgraph->n_nodes + 1);
VK_CHECK(ctx->device->device.getQueryPoolResults(ctx->query_pool, 0, ctx->query_idx, (cgraph->n_nodes + 1)*sizeof(uint64_t), timestamps.data(), sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait), "get timestamp results");
VK_CHECK(ctx->device->device.getQueryPoolResults(ctx->query_pool, 0, ctx->query_idx, (cgraph->n_nodes + 1)*sizeof(uint64_t), timestamps.data(), sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait), "get timestamp results", ctx->device);
if (!vk_perf_logger_concurrent) {
// Log each op separately
for (int i = 1; i < ctx->query_idx; i++) {
@@ -18186,7 +18385,7 @@ static void ggml_backend_vk_device_event_synchronize(ggml_backend_dev_t dev, ggm
vk::Semaphore sem = vkev->tl_semaphore.s;
uint64_t val = vkev->tl_semaphore.value;
vk::SemaphoreWaitInfo swi{vk::SemaphoreWaitFlags{}, sem, val};
VK_CHECK(device->device.waitSemaphores(swi, UINT64_MAX), "event_synchronize");
VK_CHECK(device->device.waitSemaphores(swi, UINT64_MAX), "event_synchronize", device);
// Reset and move submitted events
for (auto& event : vkev->events_submitted) {