You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Eval bug: Performance degradation since (PR #29622) with unsloth/Qwen3.8-Flash-Next-GGUF:UD-IQ3_XXS and dual Intel B70 #30033
Using an aggressive quantization + MTP on an RTX 5070 Ti, I have achieved ~70 t/s decode and ~1100 prompt processing on a month old build. I have updated today to the newest release, and with the above settings I am achieving ~5 t/s decode speed and 100-200 t/s pp.
Oddly enough, not using MTP makes it go back to 50 t/s decode.
I assume this is an issue either with the MTP implementation itself, or a CUDA issue. I've used CUDA 13.1 before, but I have also updated to CUDA 13.4 today - though I am not knowledgable about this topic, so I'm probably very wrong about this.
Conclusion: two compounding regressions, both visible in logs
PR #29622 (0bb496dbd, "llama: support both embd + raw tokens in batch").
The log delta matches it exactly: +3 input tensors are the new mixed_tokens / mixed_slots / mixed_embd (f32 [5120 x n_tokens]) inputs, and +98 nodes are the dup/set_rows/forward_select ops added per layer for mixed-batch-capable archs (qwen35 is in the default supported list). The splits also grew 53 -> 66, i.e. more host-side graph segments per step. MTP acceptance profile is unchanged, so this is pure per-step latency, not worse speculation the regression hits the MTP/nextn path specifically.
--fit demoted one layer to CPU as a knock-on effect.
The bigger reserved graph pushed the 63-layer footprint from 22028 MiB to 22182 MiB, past the 22070 MiB target, so fit settled on 62/66. One full transformer layer (~400M params) plus its KV now runs a serialized CPU pass inside every decode step - that alone can cost most of a 30 -> 20 t/s gap on this model.
Hi, this confirms the previous findings, but since I already went through the trouble of running git bisect I figured I'd add another datapoint. It's the same conclusion as the former posts.
I'm using RPC + pipeline parallelism (12 GB 5070ti laptop running llama-server, 10 GB 3080 over RPC, model layer-split across both, Qwen3.8-27B Q4_K_M). The PP probe graph reserves 761.59 MiB on the RPC side on the parent commit and 806.22 MiB on this one; the 44.63 MiB delta is what the card doesn't have left.
Details
build_inp_embd adds a third select branch (mixed_tokens, mixed_slots, mixed_embd 5120x256 f32 = 5.24 MiB) to every ubatch when the arch supports mixed batches:
My understanding is that this is an architecture property, not a batch property, and mixed batches aren't emitted anywhere yet (mtmd puts embd rows in separate batches, TODO in the PR), so the branch isn't used yet in every workload. The select still puts it into the compute graph, and with pipeline parallelism the scheduler replicates every graph input per split in ggml_backend_sched_graph_copy - that input copied ~9 times is the 44.63 MiB.
This restores the parent's graph for every batch that can occur: probe back to 761.59 MiB. I think this is what the first version of the PR did; the unconditional check only buys "no realloc when the batch kind switches", which can't happen until mtmd actually emits mixed batches which is the pending "TODO: handle this in mtmd" in the PR, but an unconditional check would matter once mtmd actually emits mixed batches hence why I'm not so sure about the quoted fix. It would work today, but would need a strategy later.
I'm wondering if this is the right fix. I apologize in advance if I'm misunderstanding something; I'm not familiar with how this works (and the below reasoning is partially assisted by AI so it might be wrong). However, if I understand correctly, with this fix, if embd (il=-1) is present, it forces its backend to layer 0 via ggml_backend_sched_set_tensor_backend, preventing the small embedding ops (pad, scale) from being placed in the CPU split. This appears to fix the performance issue, and the PR's benchmarks support that. However:
The third select branch and its three inputs (mixed_tokens/mixed_slots/mixed_embd) are still present in every ubatch graph. PP input duplication (ggml_backend_sched_graph_copy) is unchanged, so the RPC0 probe (in my earlier example) still needs 806.22 MiB, and the memory issues there aren't fixed (I think?))
Only the embd node is pinned; the actual CPU ops (pad/scale/dup) are anonymous intermediates and may still be placed on CPU unless the scheduler groups them with embd. Also, what embd refers to depends on topology: with scale_tok != 1.0f, it's the final mul/scale rather than the select
If model.dev_layer(0) is CPU (low ngl), the embedding is pinned to CPU. This also runs for all models, including ones whose backend already matches
I'm still getting the same issue on #30160 as on 0bb496d:
E ggml_gallocr_reserve_n_impl: failed to allocate RPC0[192.168.50.1:50052] buffer of size 845783552
E graph_reserve: failed to allocate compute buffers
W sched_reserve: compute buffer allocation failed, retrying without pipeline parallelism
Activity
Reallondoner commentedon Oct 6, 2026
I have the same issue. Unfortunately I don't have a fix, I just want to join in.
llama-server.exe -m F:/models/Qwen3.8-27B-Q3_K_S/Qwen3.8-27B-Q3_K_S.gguf --mmproj F:/models/Qwen3.8-27B-Q3_K_S/mmproj-F16.gguf --image-min-tokens 1024 --cache-type-k q8_0 --cache-type-v q8_0 -ngl 99 -c 65000 -fa on --batch-size 1024 --spec-type draft-mtp --spec-draft-n-max 2 -np 1 --reasoning-preserve --frequency-penalty 0.1 --reasoning-budget 8000 --reasoning-effort medium --host 0.0.0.0 --port 8080Using an aggressive quantization + MTP on an RTX 5070 Ti, I have achieved ~70 t/s decode and ~1100 prompt processing on a month old build. I have updated today to the newest release, and with the above settings I am achieving ~5 t/s decode speed and 100-200 t/s pp.
Oddly enough, not using MTP makes it go back to 50 t/s decode.
I assume this is an issue either with the MTP implementation itself, or a CUDA issue. I've used CUDA 13.1 before, but I have also updated to CUDA 13.4 today - though I am not knowledgable about this topic, so I'm probably very wrong about this.
deadprogram commentedon Oct 8, 2026
I ran into this myself, and did a lot more research. Please see my comment here #29622 (comment)
ali0une commentedon Oct 8, 2026
Hi there.
Same issue on my 3090 with Qwen3.8-27B-NGRAM-MTP-Q4_K_M decode tg t/s went from ~30 to ~19
Evidence (measured from the logs)
9f84af420db446c163(has #29622)--fitdropped one)Conclusion: two compounding regressions, both visible in logs
PR #29622 (
0bb496dbd, "llama: support both embd + raw tokens in batch").The log delta matches it exactly: +3 input tensors are the new
mixed_tokens/mixed_slots/mixed_embd(f32 [5120 x n_tokens]) inputs, and +98 nodes are thedup/set_rows/forward_selectops added per layer for mixed-batch-capable archs (qwen35 is in the default supported list). The splits also grew 53 -> 66, i.e. more host-side graph segments per step. MTP acceptance profile is unchanged, so this is pure per-step latency, not worse speculation the regression hits the MTP/nextn path specifically.--fitdemoted one layer to CPU as a knock-on effect.The bigger reserved graph pushed the 63-layer footprint from 22028 MiB to 22182 MiB, past the 22070 MiB target, so fit settled on 62/66. One full transformer layer (~400M params) plus its KV now runs a serialized CPU pass inside every decode step - that alone can cost most of a 30 -> 20 t/s gap on this model.
llama.cpp-router-0bb496d.log
llama.cpp-router-9f84af4.log
torsrex commentedon Oct 8, 2026
Hi, this confirms the previous findings, but since I already went through the trouble of running git bisect I figured I'd add another datapoint. It's the same conclusion as the former posts.
I'm using RPC + pipeline parallelism (12 GB 5070ti laptop running llama-server, 10 GB 3080 over RPC, model layer-split across both, Qwen3.8-27B Q4_K_M). The PP probe graph reserves 761.59 MiB on the RPC side on the parent commit and 806.22 MiB on this one; the 44.63 MiB delta is what the card doesn't have left.
Details
build_inp_embd adds a third select branch (mixed_tokens, mixed_slots, mixed_embd 5120x256 f32 = 5.24 MiB) to every ubatch when the arch supports mixed batches:
My understanding is that this is an architecture property, not a batch property, and mixed batches aren't emitted anywhere yet (mtmd puts embd rows in separate batches, TODO in the PR), so the branch isn't used yet in every workload. The select still puts it into the compute graph, and with pipeline parallelism the scheduler replicates every graph input per split in ggml_backend_sched_graph_copy - that input copied ~9 times is the 44.63 MiB.
A possible fix is to gate it on the batch instead of the arch:
This restores the parent's graph for every batch that can occur: probe back to 761.59 MiB. I think this is what the first version of the PR did; the unconditional check only buys "no realloc when the batch kind switches", which can't happen until mtmd actually emits mixed batches which is the pending "TODO: handle this in mtmd" in the PR, but an unconditional check would matter once mtmd actually emits mixed batches hence why I'm not so sure about the quoted fix. It would work today, but would need a strategy later.
deadprogram commentedon Oct 8, 2026
I have proposed this fix https://github.com/ggml-org/llama.cpp/pull/30151 as a better take from my first one.
torsrex commentedon Oct 8, 2026
I'm wondering if this is the right fix. I apologize in advance if I'm misunderstanding something; I'm not familiar with how this works (and the below reasoning is partially assisted by AI so it might be wrong). However, if I understand correctly, with this fix, if
embd (il=-1)is present, it forces its backend to layer 0 viaggml_backend_sched_set_tensor_backend, preventing the small embedding ops (pad,scale) from being placed in the CPU split. This appears to fix the performance issue, and the PR's benchmarks support that. However:selectbranch and its three inputs (mixed_tokens/mixed_slots/mixed_embd) are still present in every ubatch graph. PP input duplication (ggml_backend_sched_graph_copy) is unchanged, so the RPC0 probe (in my earlier example) still needs 806.22 MiB, and the memory issues there aren't fixed (I think?))embdnode is pinned; the actual CPU ops (pad/scale/dup) are anonymous intermediates and may still be placed on CPU unless the scheduler groups them withembd. Also, whatembdrefers to depends on topology: withscale_tok != 1.0f, it's the final mul/scale rather than theselectmodel.dev_layer(0)is CPU (lowngl), the embedding is pinned to CPU. This also runs for all models, including ones whose backend already matchesggerganov commentedon Oct 8, 2026
Thanks for spotting this issue. Please try #30160 and report your findings.
deadprogram commentedon Oct 8, 2026
Checking my local benchmarks now... more shortly.
torsrex commentedon Oct 8, 2026
I'm still getting the same issue on #30160 as on 0bb496d:
Here are the verbose log outputs:
log-2ca15f5-good.txt
log-0bb496d-bad.txt
log-4e67ebb-bad.txt
moriz1 commentedon Oct 8, 2026
tried #30160 with the same file and prompt as before.
PP: 582.23 t/s
TG: 32.75 t/s
no doubt it incorporates a bunch of other fixes, which explains why it's even faster than the commit before #29622 .