Skip to content

kv-cache : honor LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY in state_write / state_read_sinfo - #28873

Draft
douyamv wants to merge 1 commit into
ggml-org:masterfrom
douyamv:pr/kv-cache-honor-partial-only
Draft

douyamv wants to merge 1 commit into
ggml-org:masterfrom
douyamv:pr/kv-cache-honor-partial-only

Conversation

@douyamv

@douyamv douyamv commented Sep 14, 2026

Copy link
Copy Markdown

llama-server writes its context checkpoints with LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY for the target and, when
speculative decoding runs a draft context, for the draft context too. llama_kv_cache::state_write and
state_read_sinfo ignored the flag, so with an MTP draft model every request serialized the draft's whole KV cache
(about 2 KB per token, 400–900 MB at 200K context) to the host and read it back on restore.

A full-attention KV cache is rolled back with seq_rm (common_memory::seq_rm already does this for both
contexts), so a partial checkpoint carries nothing for it. This PR returns early in both functions when the flag is
set and the cache is not SWA (hparams.is_swa_any()), mirroring the existing gates for the indexer caches.

Effect: with Qwen3.8-Flash-Next at 200K context on a 4-GPU box the time to first token of a new turn dropped from
3.5 s to under 1 s; checkpoint rewinds (edited history) still restore correctly (tested by re-sending a prompt whose
last 300 tokens differ and checking the restored position and the generated tokens).

🤖 Generated with Claude Code

…state_read_sinfo

llama-server writes its context checkpoints with LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY for both the target and
the draft context. llama_kv_cache ignored the flag, so with an MTP draft model every request serialized the
draft's whole KV cache (about 2 KB/token, 400-900 MB at 200K context) to the host and read it back on restore.
The draft KV needs no checkpoint: common_memory::seq_rm rolls both contexts back.

On a 4x CMP 170HX box serving Qwen3.8-Flash-Next at 200K context, time to first token dropped from 3.5 s to
under 1 s; checkpoint rewinds still restore correctly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@douyamv
douyamv requested a review from ggerganov as a code owner September 14, 2026 01:24
@ggml-gh-bot

ggml-gh-bot Bot commented Sep 14, 2026

Copy link
Copy Markdown

Hi @douyamv, thanks for your contribution!

Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:

  • PR Template not respected: Please respect the template when creating a new pull request. Make sure to fill out all required sections.

  • Multiple open PRs from a new contributor: We limit new contributors (those without a previously merged PR) to 1 open PR at a time. You currently have 3 open PRs.

  • AI-generated content: While code is allowed to be generated by AI, please write the PR description and commit messages on your own without the help of AI.


Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below.

@ggml-gh-bot ggml-gh-bot Bot added the draft PR will be changed to draft by github-actions bot label Sep 14, 2026
@github-actions
github-actions Bot marked this pull request as draft September 14, 2026 01:29
@github-actions github-actions Bot removed the draft PR will be changed to draft by github-actions bot label Sep 14, 2026
@skoulik

skoulik commented Sep 15, 2026 •

Copy link
Copy Markdown

A related case in the same function, in case you'd like to cover it here. The SWA-masked-cell filter in state_write also applies to LLAMA_STATE_SEQ_FLAGS_NONE saves, which the server's --cache-ram prompt cache uses. The prompt cache saves the slot including the generated reply, then restores only the prompt prefix. Cells masked relative to the end of the sequence still fall inside the prefix's window. With --swa-full the server sets n_swa = 0, so it never notices, and the restored prompt silently produces different logits.

We hit this with Gemma 4 26B: the drift grows with the reply length, up to ~8 nats on the first token after a 755-token reply. It also reproduces on master with gemma-3-270m, text only. Applying the filter only to partial saves fixes it for us; the restore then matches slot reuse exactly:

if (add_cell && seq_id != -1 && (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY)) {

Happy to open a separate issue with the repro script if you'd rather keep this PR focused.

Our issue was introduced by #23981

SelfRef added a commit to SelfRef/llama.cpp-rdna that referenced this pull request Sep 19, 2026
…te_write/read)

Assisted-by: Claude Opus 5
@sanmai

sanmai commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Fixes the same issue #29509 (it is not fully correct AFAIK)

P.S. Glad to see a familiar face here. Long time.

@skoulik

skoulik commented Oct 14, 2026

Copy link
Copy Markdown

P.S. Glad to see a familiar face here. Long time.

It's a small world indeed. :)

@sanmai

sanmai commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Superseded by #30514

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants