Go to file
Nexesenex 52836917a1
DeepSeek V4 - Checkpoints support (#2195)
* DSV4 checkpoints WIP

* DSV4 checkpoints: fix per-sequence state save/restore writing all streams

Critical bug: llama_state_seq_get_data() and llama_state_seq_set_data()
were serializing/deserializing ALL DSV4 compressed cache streams instead
of only the stream for the target sequence. This corrupted other active
sequences' compressed indexer state during checkpoint restore.

Fix:
- Add dsv4_stream_offset_size() helper to compute per-stream byte
  offset and size for any DSV4 cache tensor (CSA K, LID K, HCA K,
  and all state tensors)
- write_kv_cache_data: emit dsv4_single_stream flag + stream_idx
  so per-sequence saves only write that stream's portion
- write_dsv4_cache: accept stream_idx parameter (-1 = full tensor,
  >= 0 = single stream at computed offset)
- read_kv_cache_data: read the new format, validate consistency
  (per-stream data needs dest seq_id, full data needs seq_id=-1),
  and restore only the destination stream's bytes into the correct
  tensor offset

Format change (WIP, backward compat not required):
  [has_dsv4_cache] [n_layer] [single_stream] [stream_idx] [n_stream]
  [per-layer: layer_type + stream tensor data]

* DSV4 checkpoints: fix checkpoint search using pos_max instead of pos_min

Bug: checkpoint search condition cur.pos_min < n_past || cur.pos_min == 0
always matched all DSV4 checkpoints because they all have pos_min=0 (the KV
cache starts at 0 and never evicts). The reverse-iterator always picked the
NEWEST checkpoint regardless of how far past the intended rewind/divergence
point it extended, causing n_past to be set to the checkpoint's pos_max
(e.g. 9500) instead of the rewind point (e.g. 5000). This made the system
skip reprocessing tokens between the rewind point and the checkpoint's
pos_max.

Fix in both batch_pending_prompt and apply_checkpoint:
- Condition changed to cur.pos_max < n_past — only checkpoints that end
  BEFORE the divergence/rewind point are eligible
- Post-restore n_past uses it->pos_max directly instead of the incorrect
  max(pos_min + 1, pos_max) which always returned pos_max for DSV4 anyway

Now when rewinding to position 5000 with checkpoints at pos_max=8000+:
no checkpoint matches, falls through to full reprocessing (correct).
When rewinding to position 8000 with a checkpoint at pos_max=7500: only
500 tokens need reprocessing (optimal).

* DSV4 checkpoints: throttle creation via interval gating on all paths

When ctx_checkpoints_interval > 0, DSV4 checkpoints (~145 MiB) were still
created at every transition point (PP done, TG start, release) because
direct create_checkpoint() calls bypassed the interval gate.

Fix:
- Modified create_checkpoint_at_interval() to handle interval <= 0 as
  'always create' (preserving recurrent model behavior for small state)
- Replaced all 4 external direct create_checkpoint() calls with
  create_checkpoint_at_interval() so the interval gate is respected
- Unified the prompt-loading branch that had split
  create_checkpoint / at_interval calls

Now with --ctx-checkpoints-interval N, all checkpoint creation is
throttled to at most 1 per N positions regardless of the transition
phase.

* DSV4 checkpoints: clarify divergence log message for models with state checkpoints

The message 'does not support partial KV reuse' was misleading for DSV4,
which now supports checkpoint-based state restoration. Split the fallback
message: models with state checkpoints (DSV4, recurrent, hybrid) now print
'no checkpoint before divergence point' instead of 'does not support
partial KV reuse', explaining that the restore failed due to missing
checkpoints at the right position, not due to lack of support.

* DSV4 checkpoints: don't erase the just-restored checkpoint

The erasure condition pos_max > pos_min_thold was equivalent to
pos_max >= pos_next, erasing any checkpoint whose data touched or
went past the current write position. The checkpoint just restored
from (pos_max == pos_next) was immediately erased, wasting a ~145 MiB
checkpoint that was perfectly valid.

Fix:
- Changed erasure condition to pos_max > pos_next (strictly greater
  than the next write position). Checkpoints at exactly the current
  position (pos_max == pos_next, e.g. the one we just restored from)
  are kept.
- Preserved cache-aligned pos_next through the restore block so the
  erasure compares against cache positions, not prompt positions
  (pre-existing bug where the prompt-tokens call at line 3677
  overwrote pos_next with a prompt position).

* DSV4 checkpoints: update interval gate position after restore

After a checkpoint restore, slot.checkpoint_pos was still 0 (from
slot.release()), so the interval gate in create_checkpoint_at_interval
always passed (0 + 2048 <= pos + 1), creating a new ~145 MiB checkpoint
immediately after every restore — even just 5 tokens past the restored
checkpoint's position.

Fix: set slot.checkpoint_pos = it->pos_max in both restore paths
(apply_checkpoint generic restore and batch_pending_prompt DSV4
restore). This tells the gate that a checkpoint already exists at the
restored position, and no new one is needed until another interval
(2048 tokens) has elapsed.

* Missing info

* DSV4 checkpoints: document float-reduction-order reproducibility after restore

After a checkpoint restore, the PP batch loop processes remaining tokens
sequentially from n_past_prompt in chunks of n_batch. Because the loop
is stateless with no carry-over from earlier batches, the chunk boundaries
at and after the restore point are identical to a full-reprocess control
arm. This ensures float-reduction-order reproducibility between arms
when performing correctness validation.

Addresses joelfarthing's finding on openPangu, where mismatched chunk
boundaries between restore+reprocess and full-reprocess controls caused
bit-level differences that masked actual restore bugs.

* DSV4 checkpoints: verify position after restore

After both restore paths (apply_checkpoint and DSV4 batch_pending_prompt),
verify that llama_kv_cache_seq_pos_max() matches the checkpoint's pos_max.
A size-matched but misplaced restore can silently corrupt the KV cache;
on mismatch, force a full reset.

The DSV4 path pre-sets restored = true on byte-level success, then the
position check can revert it to false.  Only if (restored) proceeds with
the restored state, matching the apply_checkpoint pattern.

* DSV4 checkpoints: correct misleading comment about chunk-boundary reproducibility

* DSV4 checkpoints: add FNV-1a checksum integrity check for checkpoint data

Sanity check (pos_max): catches misplaced restores (wrong stream offset,
partial overwrite) where the byte count matches but the cache position
doesn't.

Correctness check (FNV-1a hash of serialized data): catches in-memory
corruption of the checkpoint data vector between creation and restore.

Both checks are applied in the standard (apply_checkpoint) and DSV4
(batch_pending_prompt) restore paths. A mismatch in either causes the
restore to be treated as failed, falling back to full reprocess.

File format bumped to CKPT v2 (magic 0x434b5054, version 2) with a
data_hash field per checkpoint. Old-format files (LLAMA_STATE_SEQ_MAGIC)
are still loaded: the hash is computed on load so validation works
uniformly.

* Defer checkpoint hash computation to offload creation path

The FNV-1a hash (~5-15ms per 150 MiB checkpoint) is no longer computed
during checkpoint creation. Instead, data_hash is set to 0 and
hash_computed to false. The hash is computed lazily on first access via
ensure_checkpoint_hash(), called from:
- apply_checkpoint (before the integrity check during restore)
- save_checkpoints_to_file (before writing to disk)

This removes the hash computation from the time-critical checkpoint
creation path, reducing the pause between batches.

* Reuse pre-allocated scratch buffer for checkpoint serialization

Adds a reusable std::vector<uint8_t> scratch buffer to server_context,
eliminating the per-checkpoint zero-init allocation (~150 MiB memset)
from ckpt.data.resize(). The scratch is grown on demand and handed
off to the checkpoint via swap() — a zero-copy move.

Also removes default arguments from server_prompt_checkpoint_update()
since all callers already pass every parameter explicitly.

* Compute checkpoint data hash incrementally during serialization

Instead of a second pass over the serialized buffer (costly for 145 MiB DSV4
checkpoints) or deferring to save/restore time (breaks in-memory verification),
compute the FNV-1a hash as a streaming operation during llama_state_seq_get_data.

llama_data_write_buffer gains an optional fnv_hash pointer and updates it
during write() and write_tensor_data() — the hash is computed from bytes as
they land in the output buffer, with zero extra memory reads.

The server then obtains the hash at creation time by passing &ckpt.data_hash
(pre-initialized to the FNV-1a offset basis) to llama_state_seq_get_data.
This replaces the deferred hash approach (ensure_checkpoint_hash / hash_computed)
and restores in-memory round-trip verification.

* DSV4 checkpoints: add round-trip serialization verification

After restore, re-serialize the KV cache and compare byte-for-byte against
the original checkpoint data.  This directly catches serialization bugs
that produce internally-consistent but wrong values (Joel's 59/64 case:
correct position, corrupted tensor data).

The check is added to both restore paths (standard apply_checkpoint and
DSV4 batch_pending_prompt) and runs after the pos_max sanity check and
FNV-1a hash integrity check.  Cost: one extra llama_state_seq_get_size +
llama_state_seq_get_data + memcmp of the checkpoint data.

* Remove dead _ckpt_max_size member

_ckpt_max_size was set by server_prompt_checkpoint_update but never read.
Removed the member, the function parameter, and the call site.

* Remove no-op resize after swap in server_prompt_checkpoint_update

After swap, ckpt.data holds the scratch buffer which was already
resized to checkpoint_size. Since n == checkpoint_size (asserted),
the resize is a no-op.

* remove dead (void)has_hash cast

The variable is actually used later (for old-format file detection),
so the unused-variable suppression cast is misleading.

* add missing const qualifiers on to_json() methods

Both server_prompt_checkpoint::to_json() and server_prompt::to_json()
were missing const, preventing use on const references.

* remove duplicate n_kept_prompt assignment in server_prompt::from_json()

n_kept_prompt was assigned twice with the same value, clobbering the
slot where n_discarded_prompt should have been read.

* remove redundant params_base parameter from create_checkpoint_at_interval()

The parameter is already accessible as a member of server_context.
All callers were passing this->params_base, so the indirection was
unnecessary.

* factor duplicated restore verification into verify_restored_checkpoint() helper

The 3-step verification (pos_max sanity, FNV-1a hash, and round-trip
memcmp) was duplicated verbatim across apply_checkpoint() and
batch_pending_prompt().  Extract it into a shared static helper with
a label parameter for context-specific log messages.

Also eliminates the pos_next save/restore dance in apply_checkpoint
by using a local variable for the prompt-limit computation, and
removes a stray commented-out debug printf.

* fix two comments: fnv1a_hash comment was misleading, erasure comment imprecise

- fnv1a_hash() is used for all checkpoint verification (not just
  backward-compat file loading) — broadened the description.
- 'may contain stale per-position state' → 'its per-position state
  is stale' — the erasure is unconditional when pos_max > pos_next,
  so the staleness is definite, not possible.

* remove FNV-1a hash and file-format bump (perf, Joelfarthing's review feedback)

The streaming FNV-1a hash added 65 ms to checkpoint creation and 107 ms
to restore (75 MiB checkpoints; roughly double at DSV4's 145 MiB).  The
pos_max sanity check alone is sufficient for catching the real failure
modes (wrong stream offset, partial overwrite), and the initial byte-
count check from llama_state_seq_set_data catches outright corruption.

Removed:
- Streaming hash from llama_data_write_buffer (fnv_hash, fnv_update)
- hash_out parameter from llama_state_seq_get_data / llama.h API
- data_hash field from server_prompt_checkpoint struct
- FNV-1a computation during checkpoint creation and verification
- CKPT v2 file format (revert to LLAMA_STATE_SEQ_MAGIC/version)
- fnv1a_hash() helper function

Kept:
- pos_max sanity check in verify_restored_checkpoint (cheap, catches
  misplaced restores)
- Scratch buffer reuse via swap() in server_prompt_checkpoint_update
  (pure perf win, independent of hash)

* fix: restore off-by-one in n_past calculation after checkpoint restore

size_up_to_pos(pos_max) returns the number of cached tokens at positions
STRICTLY LESS THAN pos_max (non-mtmd: min(pos_max, size)).  Since the
checkpoint encodes state for positions [pos_min, pos_max], the next
position to process is pos_max + 1, not pos_max.

This matters for DSV4 whose accumulator state is not position-indexed:
reprocessing the token at pos_max would double-count it in the compressed
indexer.  For recurrent models the old pos_min+1 workaround happened to
give the right answer (since pos_min == pos_max there), but using
pos_max + 1 is correct for both.

Fixes both restore paths (apply_checkpoint and DSV4 in batch_pending_prompt).

* fix: only write/read DSV4 cache section for DSV4 models

The has_dsv4_cache uint32 was emitted unconditionally, changing the
serialized state layout for every model architecture without bumping
LLAMA_STATE_SEQ_VERSION.  Old state/session files (which end before
this field) would fail with 'unexpectedly reached end of file' when
read by the new code.

Fix: guard the entire DSV4 section on both write and read sides with
ctx->model.arch == LLM_ARCH_DEEPSEEK4.  Non-DSV4 models see the
identical layout they always had.

* fix: validate stream_idx < n_stream in dsv4_stream_offset_size

stream_idx was only checked >= 0 via GGML_ASSERT, but never checked
against n_stream.  An invalid seq_id could compute an out-of-range
tensor offset or size, leading to memory corruption.

Now asserts 0 <= stream_idx < n_stream.

* fix: scratch buffer reuse — copy instead of swap

swap(scratch) moved the written data into ckpt.data but left scratch
empty.  The next call's resize would then re-allocate from scratch,
defeating the purpose.

Now copies the data (ckpt.data = scratch) so scratch retains its size
and capacity across calls.  resize becomes an in-place extension when
needed rather than a fresh allocation.

* fix: restore interval<=0 = disable semantics, split unconditional paths

The interval gate was inverted: interval <= 0 opened the gate, so every
call to create_checkpoint_at_interval created a checkpoint (PP, TG,
release, speculative).  This changed the documented behavior ('<=0
disable' per --help) and created extra checkpoints on every decoded
token for recurrent models.

Fix:
- create_checkpoint_at_interval returns immediately when interval <= 0
  (restoring the no-op semantics from the original code)
- Unconditional paths (release, PP end, PP start with slot.do_checkpoint)
  call create_checkpoint(slot) directly, matching the original layout
- Interval-gated paths (TG tokens, PP start without slot.do_checkpoint,
  speculative decoding) stay behind create_checkpoint_at_interval

* fix: gate ALL checkpoint creation by interval, not just TG paths

Three call sites bypassed the interval gate by calling create_checkpoint(slot)
directly instead of create_checkpoint_at_interval(slot):

  - PP batch-boundary (was creating mid-PP checkpoints at unpredictable positions)
  - PP end (created a checkpoint at every end-of-prompt, even if within the interval)
  - release (created a checkpoint at every release, even if just 5 tokens later)

This caused checkpoints 5 and 6 in the log to be created only 5 tokens apart
(pos_max=8488 and pos_max=8493), and checkpoint 7 at release 455 tokens later,
all with interval=2048.

The original code had all checkpoint creation gated by interval (single
create_checkpoint_at_interval function called everywhere). The 'unconditional'
paths were introduced by our earlier fix that split create_checkpoint_at_interval
into a no-op for interval<=0 — but the split was too aggressive, making release,
PP-end, and PP-batch-boundary always fire.

Fix: route all checkpoint creation through create_checkpoint_at_interval, which
already handles do_checkpoint (early return) and interval <= 0 (no-op) correctly.
create_checkpoint is now an internal helper called only from
create_checkpoint_at_interval.

Result: with interval=2048 and an 8494-token prompt, checkpoints are created at
2048, 4096, 6144, 8192 only — the original semantics.

* fix: off-by-one in checkpoint gate condition, use -1 sentinel

The gate condition 'checkpoint_pos + interval <= 1 + pos' opened one
position early for non-first intervals.  With checkpoint_pos=6143,
interval=2048: 6143+2048=8191, and pos=8190 gives 8191 <= 1+8190=8191
→ TRUE, creating a checkpoint at pos_max=8190 instead of 8191.

Root cause: checkpoint_pos=0 served dual duty ('no checkpoint yet' and
'checkpoint at position 0').  The '1 +' in the condition compensated
for this at startup but overcompensated later.

Fix:
- Change checkpoint_pos from size_t to llama_pos, initialized to -1
- Drop the '1 +' — condition is now checkpoint_pos + interval <= pos

With checkpoint_pos=-1: -1+2048=2047 <= 2047 → first checkpoint after
2048 tokens (correct).
With checkpoint_pos=6143: 6143+2048=8191 <= 8190 → FALSE (no early
open), 8191 <= 8191 → TRUE (opens at correct position).

Also fixes the mixed signed/unsigned comparison that existed with
size_t checkpoint_pos vs llama_pos pos.

* perf: serialize directly into ckpt.data, drop scratch buffer

The ckpt.data = scratch copy added ~10ms to checkpoint creation
(memcpy of 145 MiB).  The scratch buffer was originally introduced to
avoid per-checkpoint resize allocation, but the lazy-zero paging of
modern OSes makes the resize essentially free.

Drop the _ckpt_scratch member entirely.  Serialize directly into
ckpt.data after resize — same allocation cost, no extra copy.

* fix: replace GGML_ASSERT with runtime check in dsv4_stream_offset_size

GGML_ASSERT is compiled out in release builds (NDEBUG). An invalid
non-negative seq_id from the public state API would then compute
out-of-range tensor offsets and sizes, leading to memory corruption.

Replace with a runtime conditional that logs the error and sets
safe fallback values (offset=0, size=0).  The caller that reads/writes
0 bytes will fail downstream in a defined way.

* fix: restore tolerance mechanism, slot.do_checkpoint bypasses interval gate

Samuel reviewed that we removed the slot.do_checkpoint branch from PP
batch-boundary, but batch_pending_prompt still sets slot.do_checkpoint
when the tolerance threshold is reached.  Nowhere checks it, so the
tolerance checkpoint for short prompts (shorter than interval) is dead.

Fix: create_checkpoint_at_interval now checks slot.do_checkpoint — if
true, the interval gate is bypassed.  After a successful creation the
flag is cleared so normal interval gating resumes for subsequent
checkpoints.  Also handles interval <= 0 + slot.do_checkpoint correctly:
the early-return for disabled interval is itself gated by
!slot.do_checkpoint.

* revert: erasure condition back to cur.pos_max > pos_min_thold

The change from pos_min_thold to pos_next affected all models, not just
DSV4. Revert to the original condition (cur.pos_max >= pos_next after
integer simplification) which correctly erases checkpoints at or past
the write position.

* restore unconditional release checkpoint per firecoperana review

Release is a lifecycle boundary.  The interval gate is for throttling
mid-processing checkpoints; the release should always capture the final
state (when do_checkpoint is enabled).

* restore original PP batch-boundary branching per firecoperana review

The explicit slot.do_checkpoint branch in the PP batch-boundary is
restored.  The tolerance bypass is removed from create_checkpoint_at_interval
since it was only ever intended for the PP batch-boundary path (the
original code checked slot.do_checkpoint exclusively there).  This keeps
the tolerance mechanism from leaking into TG, PP-end, and other paths.

* restore original PP-end checkpoint condition per firecoperana review

The original created an unconditional checkpoint at PP end when tolerance
is disabled (<=0).  When tolerance > 0, the tolerance mechanism in the PP
loop handles the end-of-prompt capture at the tolerance point, so no
additional PP-end checkpoint is needed.

* consolidate DSV4 restore path into apply_checkpoint per firecoperana review

The DSV4-specific restore path in batch_pending_prompt duplicated the core
logic of apply_checkpoint (search, restore, verify) with different search
conditions and missing erasure.  Consolidate by:

- Adding is_state_ckpt_model flag to apply_checkpoint
- Bypassing the pos_min >= pos_min_thold guard for state-checkpoint models
  (DSV4 always has pos_min=0 from no eviction, so the guard blocked entry)
- Using pos_next instead of pos_min_thold for the search condition when
  is_state_ckpt_model (allows finding checkpoints at pos_max == n_past - 1)
- Differentiating the reset log message per model type
- Recomputing n_past_offset and n_discarded_prompt after apply_checkpoint
  (previously handled in the DSV4-specific path)

* conditional pos_next formula

State-checkpoint models (DSV4, recurrent) use pos_max + 1 — correct
for DSV4's multi-position checkpoints where pos_min=0, po neviction
max(pos_min+1, pos_max) = pos_max, which undercounts by 1.
For recurrent models pos_min==pos_max so both formulas agree.

Non-state-checkpoint models keep the original
max(pos_min + 1, pos_max) formula unchanged.

* remove redundant n_past_offset / n_discarded_prompt after apply_checkpoint

Both n_past and n_past_prompt are shifted by the same delta from the
restored checkpoint, so the difference (n_past_offset) is unchanged.
n_discarded_prompt is not used in the critical path.

* remove redundant speculative-decoding checkpoint per firecoperana review

speculative_decoding_accept is called from within the TG generation loop
which already creates interval-gated checkpoints at n_decoded > 1 (line
4779).  The inner call would double-create.

* narrow DSV4-specific search and pos_next formula to DSV4 only per firecoperana review

is_state_ckpt_model includes recurrent models (e.g. Qwen 3.6) where
pos_max < pos_next search semantics may not be appropriate.  Only
DSV4 needs pos_max+1 formula and pos_next-based search threshold.

* revert divergence-reset guard to original per firecoperana review

Unnecessary wrapping of the OpenPangu-only divergence path inside
!llama_model_supports_state_checkpoints.  The condition is already
specific enough (!llama_model_supports_partial_kv_reuse is
OpenPangu-only), and OpenPangu does not support state checkpoints,
so the original code was functionally identical.

* narrow guard bypass to DSV4 only per firecoperana review

Recurrent state-checkpoint models don't need the pos_min >=
pos_min_thold guard bypass — only DSV4 (which always has pos_min=0
due to no KV cache eviction) requires it.

* narrow reset log message to DSV4 only per firecoperana review

Replace remaining is_state_ckpt_model with is_dsv4 in the
do_reset log branch; remove the now-unused variable.

* cleanup: revert unnecessary newlines, spacing, and comment changes

* fix: restore partial KV reuse for DSV4 in llama_model_supports_partial_kv_reuse

DSV4 has private per-position state but uses state checkpoints to
restore after a mid-sequence divergence.  The function was returning
false, causing batch_pending_prompt to reset n_past=0 before
apply_checkpoint could restore from a checkpoint, which broke the
entire checkpoint mechanism.

* Remove bloat

* Reinstate deleted comment

* replace strcmp(arch_string) with llama_model_is_deepseek4()

SamuelOliveirads added the helper upstream — cleaner and avoids
the fragile string comparison.

* inline llama_model_supports_state_checkpoints into call site

Replaced with the inline expression
  llama_model_has_recurrent(model) || llama_model_is_deepseek4(model)
and removed the now-unused function from llama.h and llama-model.cpp.

* fix: GCC 13.3 variadic macro trailing comma in SLT_WRN

SLT_WRN expands to LOG_WRN with __VA_ARGS__ at the end. When no extra
args follow the format string, the dangling comma causes GCC 13.3 to
error with 'expected primary-expression before')' token. Use '%s'
pattern consistent with all other zero-arg SLT_WRN callers.

* dsv4_stream_offset_size: bool return, GGML_ASSERT on write, graceful abort on read

dsv4_stream_offset_size silently returned offset=0, size=0 for invalid
stream indices. Now returns bool — writer hard-aborts via GGML_ASSERT
(prevents writing corrupt checkpoints), reader aborts the restore via
return false (handles corrupt checkpoints gracefully).
2026-07-30 18:50:59 +03:00
.devops Update nix flake: sync with upstream, fix for newer nixpkgs (#1371) 2026-03-24 08:17:52 +01:00
.github Update links (#2207) 2026-07-30 15:55:42 +03:00
ci common : introduce composable PEG parser combinators for chat parsing and new jinja template engine (#1369) 2026-03-09 11:03:33 +01:00
cmake Graph parallel: the next generation (#1080) 2025-12-24 08:31:48 +01:00
common Feat speculative benchmark standard (#2208) 2026-07-30 18:38:48 +03:00
docker Update docker (#2123) 2026-07-13 13:27:47 +03:00
docs DeepSeek V4 spec checkpoints (#2205) 2026-07-30 13:34:33 +03:00
examples DeepSeek V4 - Checkpoints support (#2195) 2026-07-30 18:50:59 +03:00
ggml Chunked experts (CPU) (#2202) 2026-07-30 13:16:02 +03:00
gguf-py DFlash: add Laguna XS 2.1 support (#2124) 2026-07-27 07:40:10 +03:00
github-data Add GitHub data: filename sanitization (#640) 2025-07-23 13:31:53 +02:00
grammars llama : add token matching support to llama-grammar (#1220) 2026-02-03 07:57:17 +02:00
include DeepSeek V4 spec checkpoints (#2205) 2026-07-30 13:34:33 +03:00
media README: add graphic for matrix multiplication (#6881) 2024-04-24 21:29:13 +02:00
models DS4: slowly approaching a meaningful performance (#2165) 2026-07-22 17:18:57 +03:00
pocs `build`: rename main → llama-cli, server → llama-server, llava-cli → llama-llava-cli, etc... (#7809) 2024-06-13 00:41:52 +01:00
prompts
requirements Prune examples/llava. Dead code. (#2025) 2026-06-26 08:48:48 +02:00
scripts Remove deprecated Kompute (Vulkan compute) backend (#2097) 2026-07-08 10:01:01 +02:00
spm-headers Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
src DeepSeek V4 - Checkpoints support (#2195) 2026-07-30 18:50:59 +03:00
tests fix: MiniMax-M3 streaming parser when tool calls start before `</mm:think>` (#2085) 2026-07-09 18:12:47 +03:00
vendor Replace image resizers with avx2/neon simd impls from stb_img_resize2.h 2026-06-14 20:28:08 +01:00
.dockerignore Added workflow to build container images (#1279) 2026-04-10 08:06:47 +02:00
.ecrc Nomic Vulkan backend (#4456) 2024-01-29 15:50:50 -05:00
.editorconfig Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
.flake8 Initial dflash implementation 2026-05-28 18:57:58 -03:00
.gitignore webui: update llamacpp webui (#1903) 2026-06-04 15:41:23 +02:00
.gitmodules Remove deprecated Kompute (Vulkan compute) backend (#2097) 2026-07-08 10:01:01 +02:00
.mailmap Add .mailmap 2025-07-22 14:53:50 +03:00
.pre-commit-config.yaml Update autofix and presets (#1867) 2026-05-24 07:30:44 +03:00
AUTHORS Update AUTHORS 2026-07-07 08:04:07 +00:00
CMakeLists.txt Remove deprecated Kompute (Vulkan compute) backend (#2097) 2026-07-08 10:01:01 +02:00
CMakePresets.json Update autofix and presets (#1867) 2026-05-24 07:30:44 +03:00
CONTRIBUTING.md Merge mainline - Aug 12 2024 (#17) 2024-08-12 15:14:32 +02:00
LICENSE Use links for ggml/llama.cpp authors (#318) 2025-04-07 17:25:06 +02:00
Package.swift Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
README.md Update docker (#2123) 2026-07-13 13:27:47 +03:00
convert_hf_to_gguf.py DFlash: add Laguna XS 2.1 support (#2124) 2026-07-27 07:40:10 +03:00
convert_hf_to_gguf_update.py model: add openPangu-2.0-Flash (92B-A6B) with MLA-latent cache, DSA/SWA, mHC, and multi-head MTP (#2065) 2026-07-11 12:29:20 +03:00
convert_imatrix_gguf_to_dat.py Vibe coded script + constants from mainline + pip requirements (#1405) 2026-03-11 15:41:17 +01:00
convert_llama_ggml_to_gguf.py Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
convert_lora_to_gguf.py Fix missing rope_freqs with convert_hf_to_gguf (#402) 2025-05-09 09:17:41 -05:00
docker-bake.hcl Fix Build and Push Container Image (#1633) 2026-04-16 11:24:19 +02:00
docker-bake.override.hcl Update docker readme and local build (#1710) 2026-04-30 08:16:12 +02:00
flake.lock Update nix flake: sync with upstream, fix for newer nixpkgs (#1371) 2026-03-24 08:17:52 +01:00
flake.nix Update nix flake: sync with upstream, fix for newer nixpkgs (#1371) 2026-03-24 08:17:52 +01:00
llama-mmap.h on-demand tensor reload (#1989) 2026-06-22 16:36:34 +02:00
mypy.ini
poetry.lock Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
pyproject.toml Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
pyrightconfig.json Merge mainline llama.cpp (#3) 2024-07-27 07:55:01 +02:00
requirements.txt Vibe coded script + constants from mainline + pip requirements (#1405) 2026-03-11 15:41:17 +01:00
test-function-calls.md Function calling support for Kimi-K2 (#628) 2025-07-23 18:11:42 +02:00

README.md

ik_llama.cpp: llama.cpp fork with better CPU performance

License: MIT

TL;DR

This repository is a fork of llama.cpp with better CPU and hybrid GPU/CPU performance, new SOTA quantization types, first-class Bitnet support, better DeepSeek performance via MLA, FlashMLA, fused MoE operations and tensor overrides for hybrid GPU/CPU inference, row-interleaved quant packing, etc.

[!IMPORTANT] If you are running hybrid CPU/GPU inference for MoE models with all or some experts left on the CPU, do not use -rtr unless you know what you are doing. The -rtr option causes all tensors left in RAM to be repacked to row-interleaved format while loading the model. As not all quantization types have a CUDA implementation, this will result in matrix multiplications with these tensors to be always done on the CPU, even when it would have been much better to offload the computation to the GPU, typically resulting in much lower prompt processing speed. Most notably, k-quants (K2_K, Q3_K, Q4_K, Q5_K, Q6_K) do not have CUDA row-interleaved implementation.

[!NOTE] The only fully functional and performant compute backends are CPU (AVX2 or better, ARM_NEON or better) and CUDA (Turing or newer). Please do not enter issues related to ROCm, Vulkan, Metal, old Nvidia GPUs, AVX CPUs, etc. They will not get resolved unless you roll up your sleeves and help bring your favorite backend up to speed. With the current regular contributors this project simply does not have the bandwidth to work on all backends available in llama.cpp.

[!IMPORTANT] Do not use quantized models from Unsloth that have _XL in their name. These are likely to not work with ik_llama.cpp.

The above has caused some stir, so to clarify: the Unsloth _XL models that are likely to not work are those that contain f16 tensors (which is never a good idea in the first place). All others are fine.

[!NOTE] Some users have reported issues with graph parallel (a.k.a. split mode graph) and partial GPU offload (using --cpu-moe or --n-cpu-moe or tensor overrides). If you are using/want to use split mode graph and observe gibberish/incoherent responses, try adding -cuda graphs=0 to your command line.

Quickstart

Prerequisites

git clone https://github.com/ikawrakow/ik_llama.cpp

cd ik_llama.cpp

On Debian/Ubuntu Linux, install the required packages (if using another Linux distro, you need to find the corresponding packages and adapt):

apt-get update && apt-get install build-essential git libcurl4-openssl-dev curl libgomp1 cmake

Build for CPU

cmake -B build -DGGML_NATIVE=ON

cmake --build build --config Release -j$(nproc)

For AVX-512-capable CPUs (AMD Zen4 / Intel Sapphire Rapids+), see docs/build.md section "CPU build flags for AVX-512" for the additional flags that activate the IQK quantized GEMM kernels (the HAVE_FANCY_SIMD path). Without those flags, a vanilla Release build silently falls back to the AVX2 path on this hardware.

Build for GPU

Install Nvidia Drivers and CUDA Toolkit.

cmake -B build -DGGML_NATIVE=ON -DGGML_CUDA=ON

cmake --build build --config Release -j$(nproc)

Step-by-step instructions for a case of a successful Windows build

https://github.com/ikawrakow/ik_llama.cpp/blob/main/docs/build.md

Run

Download .gguf model files (e.g. bartowski/Qwen_Qwen3-0.6B-IQ4_NL.gguf) to your favorite directory (e.g. /my_local_files/gguf).

Start the server with one of the commands (CPU or GPU):

./build/bin/llama-server --model /my_local_files/gguf/Qwen_Qwen3-0.6B-IQ4_NL.gguf --ctx-size 4096
./build/bin/llama-server --model /my_local_files/gguf/Qwen_Qwen3-0.6B-IQ4_NL.gguf --ctx-size 4096 -ngl 999

That's all! Open http://127.0.0.1:8080 in Browser and start chatting, or use the available API endpoins in your program/harness.

Run in Docker or Podman

Pull one of the available images from ghcr.io. View all tags

docker pull ghcr.io/ikawrakow/ik-llama-cpp:cpu-swap
docker pull ghcr.io/ikawrakow/ik-llama-cpp:cpu-server
docker pull ghcr.io/ikawrakow/ik-llama-cpp:cpu-full

docker pull ghcr.io/ikawrakow/ik-llama-cpp:cu12-swap
docker pull ghcr.io/ikawrakow/ik-llama-cpp:cu12-server
docker pull ghcr.io/ikawrakow/ik-llama-cpp:cu12-full

Check Step by step guide for image customization and other details.

Common parameters and options

Latest News

Model Support

LlaMA-3-Nemotron PR 377, Qwen3 PR 355, GLM-4 PR 344, Command-A PR 341, bitnet-b1.58-2B-4T PR 337, LLaMA-4 PR 321, Gemma3 PR 276, DeepSeek-V3 PR 176, Kimi-2 PR 609, dots.llm1 PR 573, Hunyuan PR 565, GLM-4.5 PR 668 (4.5/4.6/4.7/AIR), Ernie 4.5 MOE and 0.3B PR 759, grok-2 PR 782, Ling/Ring (Bailing-MoE2) PR 833, Qwen3-VL PR 883, SmolLM3 PR 934, GigaChat3 PR 995, ministral3 PR 1030, Mimo-V2-Flash PR 1096, GLM-4.7-Flash PR 1168, Seed-OSS PR 1218, Step-3.5-Flash PR 1231, GLM-5 PR 1268, Qwen3-Next PR 1266, Qwen3.5-MoE PR 1288 and dense Qwen-3.5 1326, Mistral 4 PR 1450, Bonsai 1-bit PR 1570, Gemma4 PR 1581 including assistant, Mimo-2.5 PR 1723, JetBrains Mellum2 PR 1919, Poolside Laguna XS.2 PR 1911, Cohere2-MoE North Mini Code PR 1945, MiniMax-M3 PR 1963, Laguna M.1 PR 2003

Quantization

Quantization additions

Trellis quants (IQ1_KT, IQ2_KT, IQ3_KT, IQ4_KT)

Information and the original CUDA implementation in PR 113. Additional implementations: Metal PR 475, Neon PR 471, CPU PR 441. IQ1_KT was added more recently in PR 616. Note: these are base on a novel, integer-base trellis, which allows to achieve reasonable CPU performance, see PR 529 and PRs quoted there for details.

IQK quants

Information can be found in Discussion 8.

Initial implementations (Zen4, AVX2, NEON): IQ5_KS_R4 PR 426, IQ5_KS PR 422, IQ4_KS_R4 PR 150, IQ5_K_R4 PR 149, IQ2_K_R4 PR 146, IQ3_K_R4 PR 145, IQ4_K_R4 PR 138, IQ4_KSS PR 89, IQ2_KS PR 85, IQ4_KS PR 83, IQ6_K PR 14, IQ2_K, IQ3_K and IQ5_K PR 7, IQ4_K PR 6

Cuda implementations: IQ4_KS_R4 and IQ5_KS_R4 PR 493, IQ1_S_R4 PR 492, IQ1_M_R4 PR 494. IQ4_KS_R4 and IQ5_KS_R4 PR 462, IQ2_K_R4, IQ3_K_R4, IQ4_K_R4, IQ5_K_R4 PR 461, IQ4_K, IQ5_K, IQ6_K PR 417, IQ2_KS, IQ2_K, IQ3_K PR 418

IQ2_KL is a more recent addition in PR 602

Hadamard transforms for K-cache

CPU PR 1033 and CUDA PR 1034

Hadamard transforms for V-cache

PR 1527

MXFP4 as used in gpt-oss models

Implemented for Zen4, AVX2, ARM_NEON, Metal, CUDA PR 682

Quantization improvements

  • IQ1_M PR 327, IQ2_XS PR 312, Q2_K, Q4_K, Q5_K, Q4_1, Q5_1 PR 302, Q4_0, Q5_0, Q6_0, Q3_K, Q6_K, IQ4_XS, IQ4_NL PR 295
  • Low perplexity Q4_0 KV cache PR 1547 PR 1556
  • MTP: option to use re-quantized output tensor --mtp-requantize-output-tensor new_type PR 1809

Quantization performance improvements

  • Much faster CPU prompt processing for all non-interleaved quants. Initial idea in PR 515 and PR 531, with many follow up PRs to apply to all quantization types for the 3 supported CPU platforms.
  • All quantization types now have quantized matrix multiplication CUDA kernels, see PR 557 and several others
  • Faster CPU prompt processing for Trellis quants and MoE models. PR 488
  • Trellis quants: faster CPU prompt processing PR 482.
  • Minor (~2%) iq2_ks TG performance improvement on CUDA PR 468
  • Faster IQ3_KT and IQ4_KT PR 453
  • Zen4: Faster PP for IQ2_KS, IQ4_KS, IQ5_KS PR 428
  • Fast GEMM/GEMV for IQ1_S PR 212
  • AVX-VNNI optimizations PR 1446 PR 1455 PR 1467 PR 1474 PR 1482

Features

  • New split mode "graph" for multi GPU setups PR 1022
  • Fused delta-net for Qwen3-Next and Qwen3.5-MoE PR 1315 PR 1333 PR 1362 PR 1373
  • Hadamard transforms for K-cache and V-cache PR 1033 PR 1034 PR 1527
  • Auto-fit offloaded tensors to available VRAM (MoE and dense models) PR 1501 PR 1504, allows per GPU fit margin PR 1872
  • Checkpoints for recurrent models PR 1310 PR 1398
  • MTP decoding support for popular models like GLM-4.x MoE 1270, Qwen 3.5/3.6 1698 1745, Gemma 4 1744, GLM 5 1890
  • Self speculative decoding, ngram PR 1261, suffix PR 1646
  • DFlash initial support PR 1970
  • GLM-DSA architecture indexer cache
  • String ban function for all completions PR 1185 PR 1243
  • Expiring Logit Bias PR 1731
  • OpenAI /v1/responses API endpoint PR 1184
  • Function call support PR 628
  • jinja template support PR 677
  • Webui: New Features for Conversations, Settings, and Chat Messages PR 618, MCP PR 1904
  • On-demand tensor reload PR 1989
  • Dynamic control vector management endpoints PR 1223
  • Legacy quants conversion schemes in convert_hf_to_gguf.py PR 449, Q6_0 in PR 483
  • Adaptive-P Sampler PR 1100 implemented as designed by it's author; supported on Webui
  • Multi-modal Vision support in llama-mtmd-cli PR 798 and in llama-server PR 901
  • mikupad as an alternative WebUI PR 558
  • June 8 2025: Webui updated (legacy still available when --path ./examples/server/public_legacy is passed) PR 481
  • June 8 2025: RPC improvements PR 480
  • June 7 2025: Add an endpoint that lists all the saved prompt caches to server PR 502
  • June 6 2025: Make prompt cache saving and restoring MLA aware PR 497
  • June 3 2025: Added samplers, XTC PR 486, top-n σ PR 489.
  • May 22 2025: Refactor iqk_mul_mat.cpp which speeds up compilation time significantly. PR 435
  • May 17 2025: Option to enable or disable the CPU FA kernels PR 429.
  • May 12 2025: User can now control if/which operations with tensors held in RAM are offloaded to the GPU. See PR 405
  • May 12 2025: Compatibility issues with mainline llama.cpp GGUFs for DeepSeek models with MLA enabled were resolved in PR 394. The lower prompt processing performance resulting from using llama.cpp-style MLA GGUFs was recovered in PR 409.
  • April 21 2025: ik_llama.cpp builds and runs successfully on Android (using termux), see PR 336
  • March 1 2025: Smart Expert Reduction for faster DeepSeek inference PR 239
  • Feb 25 2025: Tensor overrides for better control where model weights are stored (GPU or CPU) PR 232
  • Feb 23 2025: sweep-bench - better performance benchmarking PR 225
  • Feb 19 2025: Q8_KV - new type for 8-bit KV-cache quantization PR 208
  • March 7 2025: Custom quantization mixes using regular expressions PR 244

Performance improvements

  • Better GPU offload strategy for MoE models when using hybrid HPU/CPU inference, see PR 520
  • Much faster rng sampling PR 1187
  • May 13 2025: Better CPU FA performance for DeepSeek-Lite. PR 410
  • May 11 2025: Slightly faster flash attention for DeepSeek models on CUDA, along with extending compatibility to Touring or newer GPUs. PR 408
  • May 4 2025: Significant token generation performance improvement on CUDA with Flash Attention for GQA models. For details and benchmarks. PR 370
  • April 17 2025: Better CPU Flash Attention token generation performance. PR 332
  • April 3 2025: Much faster MoE implementation on Metal. PR 307
  • March 25 2025: Better MoE performance on CUDA PR 283
  • March 23 2025: Better batched processing speed for DeepSeek models PR 282
  • March 18 2025: Reduce compute buffer size PR 237
  • March 10 2025: Better TG performance for MoE models on CUDA PR 248
  • Feb 23 2025: Fused FFN ops for faster MoE inference PR 229

Flash-MLA

  • May 7 2025: 🚀 FlashMLA-3 for DeepSeek models on CUDA. PR 386. Caveat: Ampere or newer Nvidia GPU required
  • March 21 2025: 🚀 FlashMLA-3: fastest CPU-only inference for DeepSeek models PR 273
  • March 17 2025: 🚀 FlashMLA-2 performance improvements PR 253
  • March 12 2025: Allow Q8_0 KV cache with FlashMLA-2 on CUDA PR 265
  • March 9 2025: 🚀 FlashMLA on CUDA PR 247
  • March 8 2025: 🚀 Faster FlashMLA CPU implementation PR 243
  • March 3 2025: 🚀 Introducing FlashMLA - MLA with Flash Attention PR 240
  • Feb 27 2025: MLA without transposed cache PR 235
  • Feb 13 2025: Allow Q8_0 quantized cache with MLA PR 206
  • Feb 11 2025: 🚀 Flash Attention support for DeepSeek models PR 200
  • Feb 9 2025: 🚀 MLA for DeepSeek models PR 188

Fixes

  • Fix bug in MMVQ kernel PR 446
  • Fix AVX2 implementation of IQ4_K, IQ4_KS, IQ5_K, IQ6_K PR 427
  • Fix standard attention on the CPU PR 421
  • Fix imatrix calculation for MLA models PR 411
  • Fix new CUDA FA on Touring PR 413
  • Fix SER. CPU: PR 415 CUDA: PR 416

Resources

There is no single point of reference describing all new ik_llama.cpp features. Pull requests often contain detailed information, so browsing the PRs is often the best way to learn about new features and how to use them. In addition

  • The Wiki page has performance comparisons to mainline llama.cpp
  • This guide is a good place to start if you came here because of DeepSeek models
  • This discussion is about running DeepSeek-V3/R1 on a 16 x 3090 setup
  • This discussion describes the new quantization types available in ik_llama.cpp

Testing

Function Calls Tests

To run the function calls test suite:

cd build
cmake --build . --target test-function-calls
./bin/test-function-calls

The test suite covers parser functionality, streaming, error handling, content cleaning, and server integration. All tests should pass to ensure production readiness.

Contributing

Contributions in form of pull requests, issue submissions (bug reports, feature requests), or general discussions, are welcome.

License

Development documentation

Seminal papers and background on the models

If your issue is with model generation quality, then please at least scan the following links and papers to understand the limitations of LLaMA models. This is especially important when choosing an appropriate model size and appreciating both the significant and subtle differences between LLaMA models and ChatGPT:

Completions

Command-line completion is available for some environments.

Bash Completion

$ build/bin/llama-cli --completion-bash > ~/.llama-completion.bash
$ source ~/.llama-completion.bash

Optionally this can be added to your .bashrc or .bash_profile to load it automatically. For example:

$ echo "source ~/.llama-completion.bash" >> ~/.bashrc

Dependencies

  • yhirose/cpp-httplib - Single-header HTTP server, used by llama-server - MIT license
  • stb-image - Single-header image format decoder, used by multimodal subsystem - Public domain
  • nlohmann/json - Single-header JSON library, used by various tools/examples - MIT License
  • miniaudio.h - Single-header audio format decoder, used by multimodal subsystem - Public domain
  • subprocess.h - Single-header process launching solution for C and C++ - Public domain