llama: disable fused up-gate when an offload backend lacks GGML_OP_FUSED_UP_GATE (fixes silent 3.5x Metal slowdown)#2133
Open
hchengit wants to merge 1 commit into
Open
Conversation
GGML_OP_FUSED_UP_GATE has a CUDA implementation but no Metal one. With full offload on Apple Silicon the scheduler silently assigns every fused up-gate node to the CPU backend, forcing a GPU<->CPU round trip on every FFN layer (24x per token on Qwen 2.5-0.5B) with no error or warning. Measured cost on M2: 36 tok/s vs 125 tok/s decode (3.5x). Probe the offload backends at context creation with a dummy fused up-gate node; if any backend does not support the op, disable cparams.fused_up_gate with a warning so the graph builds the decomposed MUL_MAT + FUSED_MUL_UNARY form and stays on GPU. Backend-agnostic: any backend lacking the kernel gets the same fallback, and the probe stops triggering once the op gains a native kernel.
Contributor
Author
|
We verified it on M2. We built this branch with Metal (Apple M2, macOS) and ran Qwen 2.5-0.5B-Instruct Q4_K_M with full offload (
Two pre-existing Metal/ARM build issues we hit while compiling this branch on Xcode clang 21, both unrelated to this PR:
|
Owner
|
The Metal back-end has not been maintained for a while. There are several other new ops that are missing in addition to the fused up/gate op. Are you interested in bringing the Metal back-end up to speed and helping maintain it? The way out of the missing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GGML_OP_FUSED_UP_GATEis implemented in the CUDA backend (ggml_cuda_up_gate_unary) but not in the Metal backend. With-ngl 99on Apple Silicon, the backend scheduler silently assigns every fused up-gate node to the CPU backend, forcing a GPU→CPU→GPU synchronization stall on every FFN layer — 24 times per token on Qwen 2.5-0.5B.There is no error and no warning; inference is just silently slower. Measured on an M2 (Qwen 2.5-0.5B, Q5_0, full offload):
fused_up_gate = true)--no-fused-up-gateThis affects all standard transformer models (Qwen 2.5, Llama, DeepSeek, ...) on all Apple Silicon Macs (M1–M4). Hybrid DeltaNet models are unaffected (their FFN path doesn't emit this op).
Fix
At context creation, after the backends are initialized, build a dummy
GGML_OP_FUSED_UP_GATEnode and probe each non-CPU backend withggml_backend_supports_op(). If any offload backend lacks the op, disablecparams.fused_up_gateand log a warning. The graph then builds the decomposed form (MUL_MAT+FUSED_MUL_UNARY), which Metal handles natively, and the whole graph stays on GPU.This deliberately does not special-case Metal: any backend without the kernel (Vulkan, SYCL, ...) gets the same fallback, and once someone adds a Metal kernel for the op the probe simply stops triggering.
--no-fused-up-gatestill works as an explicit override; the probe only ever turns the option off, never on.Testing
fused_up_gate = 1in the context log and normal generation).fused_up_gate = falseunder Metal full offload) is the same mitigation we have been running manually via an eval callback on M2 since April — that is where the 36→125 tok/s numbers come from.I don't have Apple hardware in CI reach for this branch, so the probe path on Metal is verified by inspection.Update: we verified it on M2 (details in comment below): this branch built withGGML_METAL=ON, Qwen 2.5-0.5B Q4_K_M at-ngl 99— the probe warning fires at context creation and default decode runs at 112.5 t/s, matching the explicit--no-fused-up-gaterun (115.3 t/s, identical output) instead of the previous ~36 t/s CPU-fallback behavior.