Skip to content

server: save the draft state in the slot file - #30574

Merged
ggerganov merged 1 commit into
ggml-org:masterfrom
ServeurpersoCom:slot-save-draft-state
Oct 15, 2026
Merged

ggerganov merged 1 commit into
ggml-org:masterfrom
ServeurpersoCom:slot-save-draft-state

Conversation

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Overview

Follow-up to #30514, fixes #28619 (thanks @dgabehar for the report).

A slot restored with --slot-save-path gets back the main model memory but not the draft model memory, so speculative decoding restarts with an empty draft and accepts far fewer tokens.

The slot file now also stores the draft memory, the same way the RAM prompt cache already does, and restores it. A draft that does not match is skipped and starts empty, and old slot files and old servers keep working.

Additional information

Draft acceptance rate on the turn after save, erase and restore (the output is identical in all cases):

  • Qwen3.8-27B with draft-mtp: 37% on master, 49% with this PR, same as a slot that was never saved
  • Nemotron-3-Nano-4B as its own draft (same model, so a draft with the right memory accepts everything): 38% on master, 100% with this PR, same as a slot that was never saved

test_slot_restore_draft_state fails without this PR.

Requirements

The slot file held the target context and the context checkpoints,
but never the draft context, so a restored slot drafted with an
empty or stale draft KV until the cache refilled.

The file now ends with the live draft state, the full draft context
and the speculative state, in the same appendix style as the
checkpoints. A draft state that does not fit the draft context is
dropped and the draft starts empty, while older files and older
servers keep working.
@ServeurpersoCom
ServeurpersoCom requested a review from a team as a code owner October 15, 2026 07:45
@ServeurpersoCom

Copy link
Copy Markdown
Contributor Author

I think the file plumbing (open for append, flush and error check on save, open and seek to the offset on load) could be shared between the checkpoint appendix and the draft block with two small helpers, but I left the checkpoint code from #26004 untouched to keep this change focused, happy to factor it if you prefer.

@ggerganov

Copy link
Copy Markdown
Member

I think the file plumbing (open for append, flush and error check on save, open and seek to the offset on load) could be shared between the checkpoint appendix and the draft block with two small helpers, but I left the checkpoint code from #26004 untouched to keep this change focused, happy to factor it if you prefer.

Yes, we can improve plumbing in general. Something we should refactor in follow-ups - for now it's nice to patch the gaps.

@ggerganov ggerganov added the merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. label Oct 15, 2026
@ggerganov
ggerganov merged commit ea736c1 into ggml-org:master Oct 15, 2026
18 checks passed
axh-xecoy added a commit to axh-xecoy/llama.cpp that referenced this pull request Oct 21, 2026
… start

With --slot-save-path set, the live slot is written to auto-slot0.bin when
the server stops and read back after the model loads, so a long session
resumes with a prefix hit instead of a full re-prefill. Measured on a
5900-token prompt: prompt_n 5900 -> 516 after a restart.

The draft memory goes to an auto-slot0.drft sidecar. Without it a restored
slot keeps an empty draft and accepts far fewer speculative tokens
(llama.cpp ggml-org#30574, merged upstream one day after this tree).

The target file keeps the /slots save format byte for byte, so a snapshot
taken here can be restored through the REST API and vice versa. Anything
that does not fit the running context is a warning plus a cold start.
Garretsw pushed a commit to Garretsw/llama.cpp that referenced this pull request Oct 26, 2026
Upstream master now persists context checkpoints (and the draft state)
in slot save files itself (ggml-org#26004, ggml-org#30574), and load_tgt/load_dft return
false instead of aborting. Resolve the conflicts in favour of master's
implementation:

- common: take master's bool load_tgt/load_dft and drop the now
  redundant try_load_tgt/try_load_dft
- server: drop the branch's file-scope "CKPC" appendix writer/reader in
  favour of master's save/load_slot_checkpoints + save/load_slot_draft,
  and master's checkpoint restore fallback (failed slot-file checkpoints
  force a full re-process and are invalidated)
- keep reporting n_ckpt_saved / n_ckpt_restored in the slot save/restore
  responses and the slot_checkpoints /props flag

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186dV229bL7yh4joD2nXXAF
auRose94 pushed a commit to auRose94/llama.cpp that referenced this pull request Oct 28, 2026
The slot file held the target context and the context checkpoints,
but never the draft context, so a restored slot drafted with an
empty or stale draft KV until the cache refilled.

The file now ends with the live draft state, the full draft context
and the speculative state, in the same appendix style as the
checkpoints. A draft state that does not fit the draft context is
dropped and the draft starts empty, while older files and older
servers keep working.

[no release]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge ready A maintainer can use this label to indicate that they consider the changes final and ready to merge. server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Misc. bug: /slots save/restore never persists the draft-model context (ctx_dft) on speculative-decoding deployments

2 participants