From ea4d2fd6ea17c3ff64ff5bfa644ed3ee4948ac9c Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 3 Nov 2026 07:28:22 -0800 Subject: [PATCH 1/3] ggml-metal: spread big graphs over more command buffers (GPU watchdog) (cherry picked from commit 04fa42e44e3a0998a4dced5937a2316c8aea6c95) --- .../0015-ggml-metal-split-long-graphs.patch | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch diff --git a/scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch b/scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch new file mode 100644 index 0000000000..76adc3c09a --- /dev/null +++ b/scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch @@ -0,0 +1,52 @@ +diff --git a/src/ggml-metal/ggml-metal-context.m b/src/ggml-metal/ggml-metal-context.m +index e9064666..b4bac890 100644 +--- a/src/ggml-metal/ggml-metal-context.m ++++ b/src/ggml-metal/ggml-metal-context.m +@@ -53,6 +53,7 @@ struct ggml_metal { + + // command buffer state + int n_cb; // number of extra threads used to submit the command buffers ++ int n_cb_user; // n_cb as requested by ggml_metal_set_n_cb; graph_compute may raise n_cb for big graphs + int n_nodes_0; // number of nodes submitted by the main thread + int n_nodes_1; // remaining number of nodes submitted by the n_cb threads + int n_nodes_per_cb; +@@ -156,6 +157,7 @@ ggml_metal_t ggml_metal_init(ggml_metal_device_t dev) { + if (ggml_metal_fusion_info_stats(res->finfo)) { + ggml_metal_fusion_info_labels_init(res->finfo); + res->n_cb = 0; ++ res->n_cb_user = 0; + } + + GGML_LOG_INFO("%s: use fusion = %s\n", __func__, ggml_metal_fusion_info_enabled(res->finfo) ? "true" : "false"); +@@ -484,6 +486,22 @@ enum ggml_status ggml_metal_graph_compute(ggml_metal_t ctx, struct ggml_cgraph * + // number of nodes encoded by the main thread (empirically determined) + const int n_main = MAX(64, 0.1*gf->n_nodes); + ++ // a command buffer that runs for too long is killed by the macOS GPU watchdog (status 5, ++ // kIOGPUCommandBufferCallbackErrorTimeout): one Z-Image 512 DiT step in one buffer does that on a slow GPU. ++ // Spread big graphs over more command buffers (GGML_METAL_NODES_PER_CB, default 256; 0 = off). ++ { ++ static int nodes_per_cb = -1; ++ if (nodes_per_cb < 0) { ++ const char * v = getenv("GGML_METAL_NODES_PER_CB"); ++ nodes_per_cb = v ? MAX(0, atoi(v)) : 256; ++ } ++ int n_cb_eff = ctx->n_cb_user; ++ if (nodes_per_cb > 0 && n_cb_eff > 0) { ++ n_cb_eff = MAX(n_cb_eff, MIN(GGML_METAL_MAX_COMMAND_BUFFERS, (gf->n_nodes - n_main + nodes_per_cb - 1)/nodes_per_cb)); ++ } ++ ctx->n_cb = n_cb_eff; ++ } ++ + // number of threads in addition to the main thread + const int n_cb = ctx->n_cb; + +@@ -712,6 +730,8 @@ void ggml_metal_set_n_cb(ggml_metal_t ctx, int n_cb) { + n_cb = 0; + } + ++ ctx->n_cb_user = MIN(n_cb, GGML_METAL_MAX_COMMAND_BUFFERS); ++ + if (ctx->n_cb != n_cb) { + ctx->n_cb = MIN(n_cb, GGML_METAL_MAX_COMMAND_BUFFERS); + From b380462e5ee43379f1469b45e9c72e35080b0554 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Tue, 3 Nov 2026 12:44:26 -0800 Subject: [PATCH 2/3] Renumber the patch to 0018 (0014-0017 are taken by open PRs) --- ...-long-graphs.patch => 0018-ggml-metal-split-long-graphs.patch} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/unsloth/ggml-patches/{0015-ggml-metal-split-long-graphs.patch => 0018-ggml-metal-split-long-graphs.patch} (100%) diff --git a/scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch b/scripts/unsloth/ggml-patches/0018-ggml-metal-split-long-graphs.patch similarity index 100% rename from scripts/unsloth/ggml-patches/0015-ggml-metal-split-long-graphs.patch rename to scripts/unsloth/ggml-patches/0018-ggml-metal-split-long-graphs.patch From d58d6518fa6c5a77d1a8b7c9c1475ee1b196b457 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sat, 7 Nov 2026 00:41:39 -0800 Subject: [PATCH 3/3] Renumber the patch to 0021 (0018 is taken by the CPU iqk GEMM patch in #48) --- ...-long-graphs.patch => 0021-ggml-metal-split-long-graphs.patch} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/unsloth/ggml-patches/{0018-ggml-metal-split-long-graphs.patch => 0021-ggml-metal-split-long-graphs.patch} (100%) diff --git a/scripts/unsloth/ggml-patches/0018-ggml-metal-split-long-graphs.patch b/scripts/unsloth/ggml-patches/0021-ggml-metal-split-long-graphs.patch similarity index 100% rename from scripts/unsloth/ggml-patches/0018-ggml-metal-split-long-graphs.patch rename to scripts/unsloth/ggml-patches/0021-ggml-metal-split-long-graphs.patch