From 84e76d8a23162eca70490da131945ebec1f09bf4 Mon Sep 17 00:00:00 2001 From: Georgi Gerganov Date: Thu, 24 Sep 2026 22:44:53 +0300 Subject: [PATCH] metal : fix graph capture and handle empty graphs (#29390) - return early when the graph has no nodes - drop the redundant reset of capture_compute: the decrement at the top of the function already transitions the counter from 0 to -1, so a capture happens exactly once - hint at METAL_CAPTURE_ENABLED=1 in the capture error message - pass capture_compute == 0 (not the raw counter) as use_capture to ggml_metal_op_init, so GPU debug-group markers are only emitted on the captured compute Assisted-by: pi:llama.cpp/Qwen3.8-27B --- ggml/src/ggml-metal/ggml-metal-context.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ggml/src/ggml-metal/ggml-metal-context.m b/ggml/src/ggml-metal/ggml-metal-context.m index 442ed2a074..e9064666f6 100644 --- a/ggml/src/ggml-metal/ggml-metal-context.m +++ b/ggml/src/ggml-metal/ggml-metal-context.m @@ -477,6 +477,10 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph * return GGML_STATUS_FAILED; } + if (gf->n_nodes == 0) { + return GGML_STATUS_SUCCESS; + } + // number of nodes encoded by the main thread (empirically determined) const int n_main = MAX(64, 0.1*gf->n_nodes); @@ -514,8 +518,6 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph * const bool use_capture = ctx->capture_compute == 0; if (use_capture) { - ctx->capture_compute = -1; - // make sure all previous computations have finished before starting the capture if (ctx->cmd_buf_last) { [ctx->cmd_buf_last waitUntilCompleted]; @@ -538,7 +540,7 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph * NSError * error = nil; if (![[MTLCaptureManager sharedCaptureManager] startCaptureWithDescriptor:descriptor error:&error]) { - GGML_LOG_ERROR("%s: error: unable to start capture '%s'\n", __func__, [[error localizedDescription] UTF8String]); + GGML_LOG_ERROR("%s: error: unable to start capture '%s' (did you set METAL_CAPTURE_ENABLED=1 ?)\n", __func__, [[error localizedDescription] UTF8String]); } else { [ctx->capture_scope beginScope]; ctx->capture_started = true; @@ -749,7 +751,7 @@ void ggml_metal_set_n_cb(ggml_metal_t ctx, int n_cb) { idx_start, idx_end, ctx->use_concurrency, - ctx->capture_compute, + ctx->capture_compute == 0, ctx->debug_graph); for (int idx = 0; idx < ggml_metal_op_n_nodes(ctx_op); ++idx) {