Repository navigation
llama : overlap the AllReduce of split mode tensor with the compute of the next ubatch - #17
Merged
Merged
Conversation
…f the next ubatch With --split-overlap (llama_context_params.split_overlap), consecutive ubatches of at least 64 tokens alternate between two schedulers. Each has its own meta backend, so its own streams, AllReduce context and compute buffers. A subgraph of one lane waits on each device for the same subgraph of the previous ubatch of the other lane (ggml_backend_meta_share_lanes): it reads the KV cache and the recurrent state that one wrote, while the AllReduce after that subgraph overlaps with this lane's compute. A previous graph of another structure is waited for as a whole. Smaller ubatches and draft contexts stay on lane 0. The lanes share the weight and KV buffers, whose views are mapped in a rotating pair of containers that a rebuild clears; a lane that becomes active builds and allocates its graph again instead of reusing it. Each lane reserves the compute buffers of a full ubatch, so half the --ubatch-size takes the same memory; 256 per lane was the fastest on the measured GPUs. The memory breakdown counts both lanes. llama-bench takes -so, test-llama-archs runs the tensor split with the overlap, docs in docs/multi-gpu.md. Qwen3.8-27B UD-Q4_K_S, RTX 4070 + 3060, -ts 0.625/0.375 -as 1/3, q5_1, with the copy-engine AllReduce: pp2048 817 -> 1138 t/s (-ub 512 -> -ub 256 -so 1), at 16k context 731 -> 984; llama-server with 262144 tokens in 2 slots and MTP: 10k prompt 733 -> 947 t/s, 95k 570 -> 734. Outputs identical with and without the overlap, decode unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- a subgraph waits for the subgraphs of the other lane that last touched the same state tensors (KV cache, recurrent state: tensors of buffers that are neither weights nor compute buffers, by the root of their views), whatever their index: Gemma4 layers that share another layer's KV and the LFM2 short-conv state, read a subgraph before it is written, raced with waits for the same subgraph index. The other lane's history is used, not only its last graph, and subgraphs without state (FFN) no longer wait. - the lane of the next large ubatch carries over to the next decode, so one large ubatch per call alternates too - ggml_backend_meta_share_lanes returns false without events; lanes also need all layers, the KV cache and the experts on the devices - docs: how the lanes wait, measured numbers Gemma4 (30 layers, 25 sharing KV, swa_full = false, ub 512, 3000 tokens) and LFM2 (n_embd 4096, ub 2048, 6144 tokens) from the review: logits of Meta and Meta -so are now bitwise identical. test-llama-archs: Meta -so 308 OK as Meta. Qwen3.8-27B -ub 256 -so 1: pp2048 1138 -> 1180 t/s, at 16k 984 -> 1047. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lama/split-overlap
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.
Stacked on #16 (copy-engine AllReduce). This PR is the last commit; once #16 is merged, the base changes to
main.With
--split-overlap, the AllReduce of one ubatch under-sm tensorruns while the next ubatch computes. Prompt processing gets 29–39% faster, the output is identical, and decode is unchanged.Why
Every layer under
-sm tensorends with an AllReduce, and the GPUs wait for it. On an RTX 3060 at PCIe 3.0 x4, that was 42% of the 3060's prompt-processing time, never overlapped with compute.How
Consecutive ubatches of at least 64 tokens alternate between two schedulers ("lanes"). Each lane has its own meta backend, and so its own streams, AllReduce context and compute buffers.
ggml_backend_meta_share_lanes()links the two meta backends. When the graph is rebuilt, each subgraph gets the list of state tensors it reads or writes: KV cache and recurrent state, i.e. tensors in buffers that are neither weights nor compute buffers, identified by the root of their views. On each device, a subgraph then waits by event for the subgraphs of the other lane that last touched one of those tensors, from any of its graphs and at any index. The AllReduce after a subgraph is not waited for, so it overlaps with the other lane's compute. Subgraphs without state (FFN) do not wait at all.test-llama-archsfailed its mixed-batch check (NMSE 1e-2) and gpt2 hit an illegal memory access. With it, every check matches plainMetaexactly. It costs one graph build per prompt ubatch, a few ms against ~250 ms of compute.--ubatch-sizetakes the same memory as before. The memory breakdown counts both lanes. Each lane captures its own CUDA graphs, about 50 MiB more at run time.llama_context_params.split_overlap,--split-overlap/LLAMA_ARG_SPLIT_OVERLAP,llama-bench -so, aMeta -soconfig in test-llama-archs, and recipe 8 indocs/multi-gpu.md.Results
Qwen3.8-27B UD-Q4_K_S, RTX 4070 (PCIe 4.0 x16) + RTX 3060 (PCIe 3.0 x4),
-sm tensor -ts 0.625/0.375 -as 1/3, q5_1 cache, native FA, copy-engine AllReduce (#16).llama-bench, t/s:-ub 512-ub 256 -so 1Each lane's ubatch size in the prototype (pp2048, t/s): 128 → 1119, 256 → 1179, 384 → 1066, 512 → 965. Smaller pieces pipeline better, until the fixed cost per ubatch wins.
llama-serverwith the production configuration (262144 tokens of q5_1 cache in 2 slots, MTP,-ub 256):--split-overlapAgainst #16 at
-ub 512(733 and 570 t/s for the 10k and 95k prompts), the overlap adds 29%.Review
A review (reviewer-xhigh) found 4 issues; all are fixed in d7e2304:
swa_full = false).MetaandMeta -sonow give bitwise identical logits in every run.Meta -sopassed even with the waits removed. The fixtures above did reproduce the race and are what verified the fix; the test-llama-archs config only covers the plumbing.decode(), so one large ubatch per call always ran on lane 1. It now carries over between calls.ggml_backend_meta_share_lanes()now returns false there, and the lanes stay off with a warning.With the fix, prompt processing is faster than before (1138 → 1180 t/s, at 16k 984 → 1047): subgraphs without state no longer wait. The table above shows the new numbers. #16's review fixes are merged into this branch.
Tests
Meta -soconfig passes every check that plainMetapasses: 163 rows, 308 OK cells each. The ubatches of 64 tokens alternate between the lanes there. The only failure is maion-coder MoE in "Mixed batch", the same asMetaand a single GPU.🤖 Generated with Claude Code