mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-17 20:31:47 +02:00
vulkan : add command-buffer debug labels for GPU profilers (#28101)
* vulkan : add command-buffer debug labels for GPU profilers Co-authored-by: gabby-zy <z2262718160@gmail.com> Assisted-by: Claude Code * vulkan : close the queue debug label with the label struct --------- Co-authored-by: gabby-zy <z2262718160@gmail.com>
This commit is contained in:
co-authored by
gabby-zy
parent
4ea6d1bb6d
commit
72797e8919
@@ -844,6 +844,8 @@ struct vk_device_struct {
|
|||||||
std::mutex compile_mutex;
|
std::mutex compile_mutex;
|
||||||
std::condition_variable compile_cv;
|
std::condition_variable compile_cv;
|
||||||
|
|
||||||
|
uint32_t debug_cmdbuf_idx {};
|
||||||
|
|
||||||
vk::PhysicalDevice physical_device;
|
vk::PhysicalDevice physical_device;
|
||||||
vk::PhysicalDeviceProperties properties;
|
vk::PhysicalDeviceProperties properties;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -2209,6 +2211,8 @@ struct vk_context_struct {
|
|||||||
std::vector<vk_staging_memcpy> out_memcpys;
|
std::vector<vk_staging_memcpy> out_memcpys;
|
||||||
std::vector<vk_staging_memset> memsets;
|
std::vector<vk_staging_memset> memsets;
|
||||||
|
|
||||||
|
std::vector<std::string> debug_labels;
|
||||||
|
|
||||||
vk_command_pool * p {};
|
vk_command_pool * p {};
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<vk_context_struct> vk_context;
|
typedef std::shared_ptr<vk_context_struct> vk_context;
|
||||||
@@ -8332,6 +8336,95 @@ template <typename T, uint32_t N> const T *push_constant_data(const std::array<T
|
|||||||
return t.data();
|
return t.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ggml_vk_cmd_label_begin(vk::CommandBuffer buf, const char * name) {
|
||||||
|
vk::DebugUtilsLabelEXT label = {};
|
||||||
|
label.pLabelName = name;
|
||||||
|
label.color = std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
vk_instance.pfn_vkCmdBeginDebugUtilsLabelEXT(buf, reinterpret_cast<VkDebugUtilsLabelEXT *>(&label));
|
||||||
|
}
|
||||||
|
|
||||||
|
// no-op unless GGML_VK_DEBUG_MARKERS is set
|
||||||
|
struct ggml_vk_debug_label {
|
||||||
|
// at most one of these is set, depending on the scope the label was opened in
|
||||||
|
vk_context_struct * subctx {};
|
||||||
|
vk_queue_handle * qhandle {};
|
||||||
|
|
||||||
|
// one region per dispatch, e.g. "matmul_q4_k_f32_f16acc_aligned_m (192,8,1)".
|
||||||
|
// RGP cannot recover the pipeline name on its own, it only has the hash
|
||||||
|
ggml_vk_debug_label(vk_context & ctx, const std::string & pipeline_name, uint32_t wg0, uint32_t wg1, uint32_t wg2) {
|
||||||
|
if (!vk_instance.debug_utils_support || ctx->s == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
begin(ctx, pipeline_name + " (" + std::to_string(wg0) + "," + std::to_string(wg1) + "," + std::to_string(wg2) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// one region per graph node
|
||||||
|
// fused nodes are joined with '+', e.g. "RMS_NORM+MUL+ROPE Qcur-19"
|
||||||
|
ggml_vk_debug_label(vk_context & ctx, const ggml_cgraph * cgraph, int node_idx, int n_fused) {
|
||||||
|
if (!vk_instance.debug_utils_support || ctx->s == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string name = ggml_op_name(cgraph->nodes[node_idx]->op);
|
||||||
|
for (int i = 1; i <= n_fused; i++) {
|
||||||
|
name += "+";
|
||||||
|
name += ggml_op_name(cgraph->nodes[node_idx + i]->op);
|
||||||
|
}
|
||||||
|
name += " ";
|
||||||
|
name += cgraph->nodes[node_idx]->name;
|
||||||
|
begin(ctx, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// one region per graph evaluation, opened on the queue instead of a command buffer
|
||||||
|
// so it spans every submit the evaluation makes
|
||||||
|
ggml_vk_debug_label(vk_queue_handle * handle, const char * name) {
|
||||||
|
if (!vk_instance.debug_utils_support || handle == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vk::DebugUtilsLabelEXT label = {};
|
||||||
|
label.pLabelName = name;
|
||||||
|
label.color = std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
|
||||||
|
qhandle = handle;
|
||||||
|
std::lock_guard<vk_queue_handle> guard(*qhandle);
|
||||||
|
vk_instance.pfn_vkQueueBeginDebugUtilsLabelEXT(qhandle->queue, reinterpret_cast<VkDebugUtilsLabelEXT *>(&label));
|
||||||
|
}
|
||||||
|
|
||||||
|
// call before the command buffer can end, the destructor covers the rest
|
||||||
|
void close() {
|
||||||
|
if (subctx != nullptr) {
|
||||||
|
// close on the current command buffer, which may differ from the one begin used
|
||||||
|
if (subctx->s != nullptr) {
|
||||||
|
vk_instance.pfn_vkCmdEndDebugUtilsLabelEXT(subctx->s->buffer->buf);
|
||||||
|
}
|
||||||
|
subctx->debug_labels.pop_back();
|
||||||
|
subctx = nullptr;
|
||||||
|
}
|
||||||
|
if (qhandle != nullptr) {
|
||||||
|
std::lock_guard<vk_queue_handle> guard(*qhandle);
|
||||||
|
vk_instance.pfn_vkQueueEndDebugUtilsLabelEXT(qhandle->queue);
|
||||||
|
qhandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ggml_vk_debug_label() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ggml_vk_debug_label(const ggml_vk_debug_label &) = delete;
|
||||||
|
ggml_vk_debug_label & operator=(const ggml_vk_debug_label &) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// the constructors check this too, so the name is not built when markers are off
|
||||||
|
void begin(vk_context & ctx, const std::string & name) {
|
||||||
|
if (!vk_instance.debug_utils_support || ctx->s == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
subctx = ctx.get();
|
||||||
|
subctx->debug_labels.push_back(name);
|
||||||
|
ggml_vk_cmd_label_begin(subctx->s->buffer->buf, subctx->debug_labels.back().c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void ggml_vk_dispatch_pipeline(ggml_backend_vk_context* ctx, vk_context& subctx, vk_pipeline& pipeline, std::initializer_list<vk::DescriptorBufferInfo> const& descriptor_buffer_infos, const T &push_constants, std::array<uint32_t, 3> elements) {
|
static void ggml_vk_dispatch_pipeline(ggml_backend_vk_context* ctx, vk_context& subctx, vk_pipeline& pipeline, std::initializer_list<vk::DescriptorBufferInfo> const& descriptor_buffer_infos, const T &push_constants, std::array<uint32_t, 3> elements) {
|
||||||
const uint32_t wg0 = CEIL_DIV(elements[0], pipeline->wg_denoms[0]);
|
const uint32_t wg0 = CEIL_DIV(elements[0], pipeline->wg_denoms[0]);
|
||||||
@@ -8361,7 +8454,10 @@ static void ggml_vk_dispatch_pipeline(ggml_backend_vk_context* ctx, vk_context&
|
|||||||
0,
|
0,
|
||||||
{ descriptor_set },
|
{ descriptor_set },
|
||||||
{});
|
{});
|
||||||
subctx->s->buffer->buf.dispatch(wg0, wg1, wg2);
|
{
|
||||||
|
ggml_vk_debug_label dbg(subctx, pipeline->name, wg0, wg1, wg2);
|
||||||
|
subctx->s->buffer->buf.dispatch(wg0, wg1, wg2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ggml_vk_ctx_end(vk_context& ctx) {
|
static void ggml_vk_ctx_end(vk_context& ctx) {
|
||||||
@@ -8370,6 +8466,15 @@ static void ggml_vk_ctx_end(vk_context& ctx) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close open labels so this buffer is balanced; reopened in ggml_vk_ctx_begin
|
||||||
|
if (vk_instance.debug_utils_support) {
|
||||||
|
for (size_t i = 0; i < ctx->debug_labels.size(); i++) {
|
||||||
|
vk_instance.pfn_vkCmdEndDebugUtilsLabelEXT(ctx->s->buffer->buf);
|
||||||
|
}
|
||||||
|
// the enclosing per-command-buffer region
|
||||||
|
vk_instance.pfn_vkCmdEndDebugUtilsLabelEXT(ctx->s->buffer->buf);
|
||||||
|
}
|
||||||
|
|
||||||
ctx->s->buffer->buf.end();
|
ctx->s->buffer->buf.end();
|
||||||
ctx->s = nullptr;
|
ctx->s = nullptr;
|
||||||
}
|
}
|
||||||
@@ -8382,6 +8487,17 @@ static void ggml_vk_ctx_begin(vk_device& device, vk_context& subctx) {
|
|||||||
|
|
||||||
subctx->seqs.push_back({ ggml_vk_begin_submission(device, *subctx->p) });
|
subctx->seqs.push_back({ ggml_vk_begin_submission(device, *subctx->p) });
|
||||||
subctx->s = subctx->seqs[subctx->seqs.size() - 1].data();
|
subctx->s = subctx->seqs[subctx->seqs.size() - 1].data();
|
||||||
|
|
||||||
|
if (vk_instance.debug_utils_support) {
|
||||||
|
// outermost region, one per command buffer, so the gaps between submits stand out
|
||||||
|
const std::string name = "submit " + std::to_string(device->debug_cmdbuf_idx++);
|
||||||
|
ggml_vk_cmd_label_begin(subctx->s->buffer->buf, name.c_str());
|
||||||
|
|
||||||
|
// reopen labels left open when the previous command buffer was submitted
|
||||||
|
for (const std::string & label : subctx->debug_labels) {
|
||||||
|
ggml_vk_cmd_label_begin(subctx->s->buffer->buf, label.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static vk_context ggml_vk_get_compute_ctx(ggml_backend_vk_context * ctx) {
|
static vk_context ggml_vk_get_compute_ctx(ggml_backend_vk_context * ctx) {
|
||||||
@@ -15971,6 +16087,9 @@ static bool ggml_vk_build_graph(ggml_backend_vk_context * ctx, ggml_cgraph * cgr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closed explicitly below, and by the destructor on the early returns
|
||||||
|
ggml_vk_debug_label dbg(compute_ctx, cgraph, node_idx, ctx->num_additional_fused_ops);
|
||||||
|
|
||||||
switch (node->op) {
|
switch (node->op) {
|
||||||
case GGML_OP_REPEAT:
|
case GGML_OP_REPEAT:
|
||||||
ggml_vk_repeat(ctx, compute_ctx, src0, node);
|
ggml_vk_repeat(ctx, compute_ctx, src0, node);
|
||||||
@@ -16375,6 +16494,9 @@ static bool ggml_vk_build_graph(ggml_backend_vk_context * ctx, ggml_cgraph * cgr
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the submit path below can end the command buffer, so close the region first
|
||||||
|
dbg.close();
|
||||||
|
|
||||||
ctx->tensor_ctxs[node_idx] = compute_ctx;
|
ctx->tensor_ctxs[node_idx] = compute_ctx;
|
||||||
|
|
||||||
#if defined(GGML_VULKAN_CHECK_RESULTS)
|
#if defined(GGML_VULKAN_CHECK_RESULTS)
|
||||||
@@ -17841,14 +17963,13 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
|||||||
ctx->device->diag_prev_end = -1;
|
ctx->device->diag_prev_end = -1;
|
||||||
|
|
||||||
if (vk_instance.debug_utils_support) {
|
if (vk_instance.debug_utils_support) {
|
||||||
vk::DebugUtilsLabelEXT dul = {};
|
ctx->device->debug_cmdbuf_idx = 0;
|
||||||
dul.pLabelName = "ggml_backend_vk_graph_compute";
|
|
||||||
dul.color = std::array<float,4>{1.0f, 1.0f, 1.0f, 1.0f};
|
|
||||||
|
|
||||||
std::lock_guard<vk_queue_handle> guard(*ctx->device->compute_queue->handle);
|
|
||||||
vk_instance.pfn_vkQueueBeginDebugUtilsLabelEXT(ctx->device->compute_queue->handle->queue, reinterpret_cast<VkDebugUtilsLabelEXT*>(&dul));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queue scope, so it encloses every submit this evaluation makes.
|
||||||
|
// closed when the function returns
|
||||||
|
ggml_vk_debug_label queue_dbg(ctx->device->compute_queue->handle.get(), "ggml_backend_vk_graph_compute");
|
||||||
|
|
||||||
ctx->prealloc_size_add_rms_partials_offset = 0;
|
ctx->prealloc_size_add_rms_partials_offset = 0;
|
||||||
ctx->do_add_rms_partials = false;
|
ctx->do_add_rms_partials = false;
|
||||||
ctx->do_add_rms_partials_offset_calculation = false;
|
ctx->do_add_rms_partials_offset_calculation = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user