Skip to content

Commit 60f5926

Browse files
committed
Enable unified KV for KVarN
Allow KVarN runtime validation and server auto-slot mode to use kv-unified, and gate prompt-cache state restore on actual memory stream safety instead of disabling unified KV globally. Add CUDA KVarN irregular-index coverage and update docs/tests.
1 parent 52740a9 commit 60f5926

20 files changed

Lines changed: 190 additions & 43 deletions

docs/beellama-args.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ For current long-context Qwen and Gemma DFlash serving, the common asymmetric ch
205205

206206
Do not assume enum compatibility with TheTom's public TurboQuant fork. Bee uses the buun enum order for Turbo/TCQ cache types while keeping a 128-value `turbo3` block. Bee keeps TCQ cache IDs at `45` and `46`; Tom's `TQ3_1S` and `TQ4_1S` model weight formats use new GGML type IDs `47` and `48`.
207207

208-
KVarN pseudo types are accepted only on the target `--cache-type-k` / `--cache-type-v` path. Draft cache arguments intentionally reject them. If only one side is specified, Bee mirrors that KVarN bit width to the other side; all K/V pairs over `2`, `3`, `4`, `5`, `6`, and `8` bits are selectable. KVarN still requires a supported attention/cache path, non-unified KV streams, 128-slice-compatible key/value head dimensions, and backend native KVarN ops unless `--kv-kvarn-fallback` is enabled.
208+
KVarN pseudo types are accepted only on the target `--cache-type-k` / `--cache-type-v` path. Draft cache arguments intentionally reject them. If only one side is specified, Bee mirrors that KVarN bit width to the other side; all K/V pairs over `2`, `3`, `4`, `5`, `6`, and `8` bits are selectable. KVarN supports both normal per-sequence KV streams and `--kv-unified`, and still requires a supported attention/cache path, 128-slice-compatible key/value head dimensions, and backend native KVarN ops unless `--kv-kvarn-fallback` is enabled.
209+
210+
When KVarN runs with `--kv-unified`, it uses one physical structured stream and standard KV metadata for sequence isolation. Per-sequence prompt-cache state restore is used only when that shared stream is exclusive; otherwise the server keeps correctness by skipping the RAM state restore and processing the prompt normally.
209211

210212
Layers that cannot use structured KVarN records (for example iSWA sliding-window layers, whose rolling eviction is incompatible with KVarN 128-token tile groups) fall back to a normal KV cache whose type matches the requested bit width: `kvarn2``q2_0`, `kvarn3``q3_0`, `kvarn4``q4_0`, `kvarn5``q5_0`, `kvarn6``q6_0`, `kvarn8``q8_0`. This keeps total KV memory at the requested bit level instead of silently storing the fallback layers in `f16`.
211213

include/llama.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,17 @@ extern "C" {
911911
// Check if the memory supports shifting
912912
LLAMA_API bool llama_memory_can_shift(llama_memory_t mem);
913913

914+
// Returns the actual number of physical KV attention streams used by the memory object.
915+
// A value of 1 means all sequences share one physical KV stream.
916+
LLAMA_API uint32_t llama_memory_kv_n_stream(llama_memory_t mem);
917+
918+
// Convenience query for a context. Returns 0 if the context has no KV attention memory.
919+
LLAMA_API uint32_t llama_context_kv_n_stream(const struct llama_context * ctx);
920+
921+
// Returns true when restoring a per-sequence state can overwrite physical KV data
922+
// that may also contain cells for other sequences in the same stream.
923+
LLAMA_API bool llama_memory_state_seq_restore_requires_exclusive_kv_stream(llama_memory_t mem);
924+
914925
// Expand the recurrent state to new_n_seq_max cells (for deferred backup allocation).
915926
// Returns true on success. No-op if the memory is already large enough or has no recurrent component.
916927
LLAMA_API bool llama_memory_recurrent_expand(llama_memory_t mem, uint32_t new_n_seq_max);

src/llama-context.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8393,7 +8393,7 @@ llama_context * llama_init_from_model(
83938393
/*.attention_supported =*/ attention_supported,
83948394
/*.head_dims_supported =*/ head_dims_supported,
83958395
/*.n_seq_max =*/ std::max(1u, params.n_seq_max),
8396-
/*.kv_unified =*/ false,
8396+
/*.kv_unified =*/ params.kv_unified,
83978397
};
83988398

83998399
if (const char * reason = llama_kvarn_validate_runtime(params.kvarn, requirements)) {
@@ -8406,10 +8406,6 @@ llama_context * llama_init_from_model(
84068406
__func__, llama_kvarn_type_name(params.kvarn.type), reason);
84078407
params.kvarn = llama_kvarn_default_params();
84088408
} else {
8409-
if (params.kv_unified) {
8410-
LLAMA_LOG_WARN("%s: KVarN requires non-unified KV streams; forcing kv_unified=false\n", __func__);
8411-
params.kv_unified = false;
8412-
}
84138409
if (params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_ENABLED) {
84148410
LLAMA_LOG_WARN("%s: KVarN requires Flash Attention; enabling it\n", __func__);
84158411
params.flash_attn_type = LLAMA_FLASH_ATTN_TYPE_ENABLED;
@@ -9442,6 +9438,18 @@ bool llama_memory_can_shift(llama_memory_t mem) {
94429438
return mem->get_can_shift();
94439439
}
94449440

9441+
uint32_t llama_memory_kv_n_stream(llama_memory_t mem) {
9442+
return mem ? mem->get_kv_n_stream() : 0;
9443+
}
9444+
9445+
uint32_t llama_context_kv_n_stream(const llama_context * ctx) {
9446+
return ctx ? llama_memory_kv_n_stream(llama_get_memory(ctx)) : 0;
9447+
}
9448+
9449+
bool llama_memory_state_seq_restore_requires_exclusive_kv_stream(llama_memory_t mem) {
9450+
return mem && mem->state_seq_restore_requires_exclusive_kv_stream();
9451+
}
9452+
94459453
static llama_memory_recurrent * get_recurrent_mem(llama_memory_t mem) {
94469454
if (auto * h = dynamic_cast<llama_memory_hybrid *>(mem)) return h->get_mem_recr();
94479455
if (auto * h = dynamic_cast<llama_memory_hybrid_iswa *>(mem)) return h->get_mem_recr();

src/llama-kv-cache-iswa.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ bool llama_kv_cache_iswa::get_can_shift() const {
304304
kv_base->get_kv_size() == kv_swa->get_kv_size();
305305
}
306306

307+
bool llama_kv_cache_iswa::state_seq_restore_requires_exclusive_kv_stream() const {
308+
return kv_base->state_seq_restore_requires_exclusive_kv_stream() ||
309+
kv_swa->state_seq_restore_requires_exclusive_kv_stream();
310+
}
311+
307312
void llama_kv_cache_iswa::state_write(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) const {
308313
const bool include_base = (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0 ||
309314
kv_base->requires_state_for_partial_restore();

src/llama-kv-cache-iswa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class llama_kv_cache_iswa : public llama_memory_i {
7373
// state write/load
7474

7575
bool requires_state_for_partial_restore() const override;
76+
bool state_seq_restore_requires_exclusive_kv_stream() const override;
7677
void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
7778
void state_read (llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
7879

src/llama-kv-cache-kvarn.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,10 @@ bool llama_kv_cache_kvarn::requires_state_for_partial_restore() const {
651651
return true;
652652
}
653653

654+
bool llama_kv_cache_kvarn::state_seq_restore_requires_exclusive_kv_stream() const {
655+
return get_kv_n_stream() == 1;
656+
}
657+
654658
bool llama_kv_cache_kvarn::has_pending_stream_copies() const {
655659
return !pending_stream_copies.empty();
656660
}

src/llama-kv-cache-kvarn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class llama_kv_cache_kvarn : public llama_memory_i {
116116
std::map<ggml_backend_buffer_type_t, size_t> memory_breakdown() const override;
117117

118118
bool requires_state_for_partial_restore() const override;
119+
bool state_seq_restore_requires_exclusive_kv_stream() const override;
119120
void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
120121
void state_read(llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
121122

src/llama-kvarn.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,6 @@ const char * llama_kvarn_validate_runtime(
165165
if (!requirements.head_dims_supported) {
166166
return "KVarN requires key and value head dimensions to be 128-slice-compatible";
167167
}
168-
if (requirements.kv_unified) {
169-
return "KVarN requires non-unified KV streams";
170-
}
171-
172168
return nullptr;
173169
}
174170

src/llama-memory-hybrid-iswa.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ bool llama_memory_hybrid_iswa::requires_state_for_partial_restore() const {
226226
mem_recr->requires_state_for_partial_restore();
227227
}
228228

229+
bool llama_memory_hybrid_iswa::state_seq_restore_requires_exclusive_kv_stream() const {
230+
return mem_attn->state_seq_restore_requires_exclusive_kv_stream() ||
231+
mem_recr->state_seq_restore_requires_exclusive_kv_stream();
232+
}
233+
229234
void llama_memory_hybrid_iswa::state_write(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) const {
230235
mem_attn->state_write(io, seq_id, flags);
231236
mem_recr->state_write(io, seq_id, flags);

src/llama-memory-hybrid-iswa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class llama_memory_hybrid_iswa : public llama_memory_i {
8484
// state write/load
8585

8686
bool requires_state_for_partial_restore() const override;
87+
bool state_seq_restore_requires_exclusive_kv_stream() const override;
8788
void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
8889
void state_read (llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
8990

0 commit comments

Comments
 (0)