Repository navigation
Conversation
|
can you post some perf results on the PR? I can try to reproduce them and test |
e12a444 to
95c7ce5
Compare
|
@am17an Rebased and did multiple benches: Test types:
So with Details
Notes on rows 13-17 (why the MoE cache slows down generation here):
Tests on the branch head (
|
|
Cache rate needs to be above 70-80% for the speed-up from what I saw. But otherwise the PP results look quite good to me. Can you clean up the PR and make it ready for review? |
|
Also measure some real workload other than llama-bench, as random tokens wouldn't have lower hit rates than something in distribution. |
Bench results above except 10,11,12 are from server mode, processing RFC 7540 prompt of 52421 tokens (just copypasting part from head of rfc page)
Will do In #29964 there was a discussion that in some configurations this PR can lower performance, my plan was to introduce new option for |
95c7ce5 to
f81e182
Compare
|
Removed first commit as all required changes already in master via #28713 did a clean up, fixed long comments, updated description, marking as ready for review |
llama args
|
f81e182 to
273cd26
Compare
| overflow_bufts.push_back(ggml_backend_cpu_buffer_type()); | ||
| } | ||
|
|
||
| // with pipeline parallelism, each device uploads the MoE weights in system memory of its own layers (keep the conditions in sync with llama_context) |
There was a problem hiding this comment.
Testing this with Qwen 3.8 Flash Next with or without MTP enabled, unfortunately, the prefill speed is halved in a dual 3090/3060 GPU setup. Previously, it was ~1200 without MTP and ~600t/s with MTP (#27428) but with this PR it goes down to ~300t/s using the exact same flags regardless if MTP is enabled or not.
All flags are llama-server defaults, no behaviour override.
Looking at the VRAM distribution, I could see that the VRAM is no longer fully utilized even with --fit-target set to something small like 100 MB. It leaves out ~8GB on my GPU for some reason.
There was a problem hiding this comment.
How do you get 1200 on 3090? Can you share the secret (config)?
There was a problem hiding this comment.
Here it is: ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-Coder-GGUF, the pruned version of Flash Next, which fully fits my VRAM.
There was a problem hiding this comment.
Ah... got it, it is fully resident. Thank you for the link
There was a problem hiding this comment.
@aminya not sure how to debug this, can you show what llama-fit-params generates for your setup?
273cd26 to
6325cf4
Compare
…ml-org#29963 rewrite re-tested and rejected
Assisted-by: Claude
6325cf4 to
544a400
Compare
|
@am17an @ggerganov PTAL |


Overview
Support pipeline parallelism with MoE experts in host RAM
Additional information
When part of the MoE weights is in host RAM (
-ot,--cpu-moe,--n-cpu-moe, orfitwhen the model does not fit in VRAM), llama.cpp turns pipeline parallelism off (!has_tensor_overrides()in llama-context.cpp). All the experts are then uploaded through the first device that can (GPU0 on CUDA) and the GPUs run strictly one after another.This PR keeps pipeline parallelism working with the weights in host RAM. Each GPU uploads the experts of its own layers, consecutive ubatches overlap across devices. Long prompt processing is x1.5-2 faster on my 3x RTX PRO 4000, short prompts and generation stay about the same.
Benchmarks
3x RTX PRO 4000 Blackwell (PCIe 5 x16, P2P), EPYC 9274F, 384 GB DDR5, CUDA 13.3. Common settings
-fa on -b 4096 -ub 4096 -lm none,CUDA_SCALE_LAUNCH_QUEUES=4x. PP is for the 1st / 2nd request of a about 50k-token RFC 7540.-ncmoe 999, serverCommits:
ggml : upload user inputs once per device before the splits. In pipeline mode every graph input (KQ mask and friends) was copied
n_copiestimes per device and the copies were held for the whole graph. Now one copy per device, uploaded async on the stream of the split that uses it. Alone it does not change the speed, but it cuts the compute buffers from 9133 to 2988 MiB per GPU (Qwen3.5-35B in VRAM, c=262144, and the saving grows with the context).llama : keep graph topology constant with pipeline parallelism. With host weights the executed graph is not always the worst-case one, and then every ubatch of a prompt reallocated the compute buffers, which synchronizes all devices. So after a smaller graph the worst-case graph is reserved again. This is what makes the host-weights case fast at all: without this commit the branch gives 983/991 instead of 1809/2095 on the Qwen3.8 server bench.
ggml : pipeline parallelism with weights in host memory. The main part. One copy of a host weight per device instead of 4 held for the whole graph, the allocator reuses it between splits, each split backend writes it in stream order. Ops with host weights run on the device of their own layer through the graph callback, not all on GPU0. The pipeline is now enabled with overrides, but only when the host weights are spread over the devices - on the master
fitlayout (all host weights on the last GPU) it stays off and runs at master speed. Reading the MoE ids waits for the split backend and would stall the graphs in flight, so on large batches the whole expert tensor is uploaded instead (>= 16 ids per expert with a graph in flight, else a full batch with >= 64). Also fixesggml_backend_sched_reserve_sizeto reset aftersplit_graphso that thefitprobes see the backend assignments made by the callback.common : balanced layer slices for fit with pipeline parallelism. Master fit stacks all host weights on the last device (Qwen3.8 gets
-ts 7,4,38), which is exactly the one-GPU upload this whole thing is about. When the pipeline conditions hold, fit now gives every GPU an equal slice of layers and converts them to full layers per device as they fit (-ts 16,16,17).the CUDA top-k radix select from the earlier version of the branch is dropped, #28713 landed and already covers that path in master.
Corresponding discussion thread: #29964
Requirements
AI usage disclosure: YES, paired with opus\fable