kv-cache : spend the partial residency budget on the slowest link first - #68
Open
Piggidragon wants to merge 10 commits into
Open
Piggidragon wants to merge 10 commits into
Piggidragon wants to merge 10 commits into
Conversation
This was referenced Sep 3, 2026
Owner
|
Automated preliminary review by Codex; the repository owner plans a separate manual review. Verdict: FAIL. Blocking
Will slow review
Developmental progress
Reviewed head: fe9617e |
--kv-gpu-layers was resolved inside each cache, so a cache built from several sub-caches (iSWA, DSA, DSV4, MSA) would have given each of them the full budget and was disabled for all of them. It also counted layers the attention cache does not own, so on a hybrid model most of the budget went to recurrent layers, and it took layers in layer order, which fills the device owning the first layers and leaves the free memory of the others unused. Resolve one set of layer indices for the whole model instead, from the layers the requesting context actually owns, and take them per owning device. An MTP context owns the nextn layers, which sit above the layers of the main context. Assisted-by: Claude Opus 5
The picker excluded every recurrent layer and counted its own choice as the result. Falcon H1 marks all of its layers recurrent yet caches all of them, so a request placed nothing; Nemotron H caches only the non-recurrent layers without an FFN, so part of the budget went to layers the cache then dropped, and the count still said they were resident, which can enable the attention compute offload for nothing. Ask the same ownership filter the hybrid cache uses, and report the layers the caches did place. Assisted-by: Claude Opus 5
Piggidragon
force-pushed
the
mgpu/kv-residency-bandwidth
branch
from
September 6, 2026 06:04
fe9617e to
3c04a16
Compare
A cache built from several sub-caches placed the same layer in each of them. The residency tests get their own invocation instead of running in the arch sweep. Assisted-by: Claude Opus 5
A device-resident layer saves the host-to-device transfer it would otherwise cost every token, which is worth most where the link is slowest. Measure the bandwidth once at startup, through the same path the cache is delivered on, and take the layers of the slowest device first. Devices within 15 percent of each other stay one group and keep the round-robin, so their memory use stays even. Assisted-by: Claude Opus 5
The ranking measured a pinned source buffer while the cache uses pageable storage unless kv_cpu_pinned is set, so it timed a path the default configuration does not take. It also gave every eligible layer of the slowest device away without looking at the free memory of that device or at the size of the layer, and the cache has no fallback if its allocation then fails. Measure the storage the cache will use, and stop taking layers from a device before its reported free memory runs out. Assisted-by: Claude Opus 5
A meta device reports the free memory of all its devices while a layer only takes its share from each, the layer estimate now errs high rather than low, and the link measurement is kept instead of re-run for every context. Assisted-by: Claude Opus 5
Piggidragon
force-pushed
the
mgpu/kv-residency-bandwidth
branch
from
September 7, 2026 20:02
3c04a16 to
3944f4e
Compare
Refresh the PR against llama/dev. Fix router and nextn ownership, scope the sliding-window guard to owned layers, and strengthen placement tests and documentation. Assisted-by: Codex
Integrate the reviewed PR67 ownership fixes and size resident KV through the cache layout and backend allocation rules. Assisted-by: Codex
…ffers The residency budget ignored the compute buffers and recurrent state allocated after the cache, so a request that reached the free memory bound failed to allocate the compute buffers. Layer sizes also came from a separate formula that charged SWA layers the full context. Measure the compute buffers with a size-only reserve before the cache is created, record the tensors each cache owns in a pass without KV storage, and pick against the free memory minus both. The fit dry run keeps attention KV on the host. Assisted-by: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01TrrQUGmn1qZsxKF3p9TvYh
# Conflicts: # tests/test-llama-archs.cpp
This was referenced Sep 17, 2026
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.
Overview
Builds on the residency PR. There,
--kv-gpu-layersspreads round-robin over the owning devices, so each device gives up the same number of layers. That is the right default only when the devices are alike.A device-resident layer saves the host-to-device transfer it would otherwise cost every token, and that transfer costs most where the link is slowest. On an asymmetric pair the two links differ by a lot:
This PR measures the host-to-device bandwidth once at startup, using the storage the cache is delivered from (pinned or pageable), and spends the budget on the slowest device first. Devices within 15% of each other stay in one group and keep the round-robin, so a symmetric machine sees no change.
Memory budget
The residency set is bounded by the free memory of each device. The first version of the bound kept only 1/8 of free memory back. The compute buffers and recurrent state allocated after the cache did not fit in that, so a request that reached the bound failed to start (
failed to allocate compute pp buffers). It also sized layers with its own formula, which charged SWA layers the full context (about 85x too much for Gemma 4 at 131k).Now:
--kv-gpu-layersset, the context first builds the caches without KV storage and runs the existing size-only reserve (the path the fit dry run uses), which gives the compute buffer size of each device.Not reserved: memory that other processes or a later context (draft/MTP) allocate.
Testing
Ordering, Qwen3.8-27B-UD-Q5_K_M, 15216-token prompt,
-c 20480 -n 128 -ngl 99, f16 cache,-sm layer -nkvo --kv-cpu-pinned --recurrent-state-offload. 16 owned attention layers, 8 per GPU. "round-robin" is #67, "slowest first" is this PR.--kv-gpu-layersAt 8 layers, where the 3060 holds none of the host-resident cache, both orders use the same memory, but generation is +86% faster and prefill +51% faster.
Memory bound, RTX 4070 + RTX 3060, 17k-token prompt:
-fit offtest-llama-archs --test-kv-residencypasses, with an added capacity case for memory the context reserves. These also pass:test-phase-aware-workspace,test-live-context-workspace,test-recurrent-state-rollback*,test-save-load-stateandtest-llama-archs -s 1.Not done here
--attn-splitor--tensor-splitfrom the same measurement. It would change the reduction order for every multi-GPU user, so it waits until it has run on more than one machine.Requirements
Assisted-by:commit trailers.🤖 Generated with Claude Code
https://claude.ai/code/session_01TrrQUGmn1qZsxKF3p9TvYh