kingjones777 commited on
Commit
721fc7f
·
verified ·
1 Parent(s): 21a3548

fix: complete MTP patch + QSA checkpoint fix (2026-09-17)

Browse files
Files changed (1) hide show
  1. qwen4exp-qsa-checkpoint-fix.patch +122 -0
qwen4exp-qsa-checkpoint-fix.patch ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ From 85d8f7e83499e434c24993e6e1f3800568b5adfd Mon Sep 17 00:00:00 2001
2
+ From: kingjones30 <myron@deploy365.us>
3
+ Date: Thu, 3 Sep 2026 12:33:12 +0000
4
+ Subject: [PATCH] fix(qwen4exp): serialize QSA indexer cache in context
5
+ checkpoints
6
+
7
+ llama_memory_hybrid_idx inherited state_write/state_read from the hybrid
8
+ base and never overrode them, so checkpoints omitted mem_idx. A restore
9
+ then left the QSA index pointing at a different position than the KV
10
+ caches; the next kernel could wedge the GPU SDMA queue (field report:
11
+ kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF#6, @liusecret).
12
+
13
+ Also treat empty seq_rm ranges as no-ops and honor mem_idx->seq_rm.
14
+ ---
15
+ common/common.cpp | 16 ++++++++++++++++
16
+ src/llama-memory-hybrid-idx.cpp | 34 ++++++++++++++++++++++++++++++++-
17
+ src/llama-memory-hybrid-idx.h | 3 +++
18
+ 3 files changed, 52 insertions(+), 1 deletion(-)
19
+
20
+ diff --git a/common/common.cpp b/common/common.cpp
21
+ index 1421040..e64a71b 100644
22
+ --- a/common/common.cpp
23
+ +++ b/common/common.cpp
24
+ @@ -1510,6 +1510,22 @@ done:
25
+
26
+ void common_context_seq_rm(llama_context * ctx, llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
27
+ auto * mem = llama_get_memory(ctx);
28
+ + if (mem == nullptr) {
29
+ + return;
30
+ + }
31
+ + // empty range is a no-op, not a fatal. recurrent caches refuse p0 == n_past,
32
+ + // p1 == -1 instead of succeeding, which used to abort the server.
33
+ + const llama_pos p0n = p0 < 0 ? 0 : p0;
34
+ + if (p1 >= 0) {
35
+ + if (p0n >= p1) {
36
+ + return;
37
+ + }
38
+ + } else {
39
+ + const llama_pos p_max = llama_memory_seq_pos_max(mem, seq_id);
40
+ + if (p_max >= 0 && p0n > p_max) {
41
+ + return;
42
+ + }
43
+ + }
44
+ if (!llama_memory_seq_rm(mem, seq_id, p0, p1)) {
45
+ GGML_ABORT("%s", string_format("failed to remove sequence %d with p0=%d, p1=%d\n", seq_id, p0, p1).c_str());
46
+ }
47
+ diff --git a/src/llama-memory-hybrid-idx.cpp b/src/llama-memory-hybrid-idx.cpp
48
+ index 586b340..b32b1b7 100644
49
+ --- a/src/llama-memory-hybrid-idx.cpp
50
+ +++ b/src/llama-memory-hybrid-idx.cpp
51
+ @@ -142,6 +142,16 @@ void llama_memory_hybrid_idx::clear(bool data) {
52
+ }
53
+
54
+ bool llama_memory_hybrid_idx::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_pos p1) {
55
+ + // empty range is a no-op. the recurrent cache refuses p0 == n_past, p1 == -1
56
+ + // (rollback past n_rs_seq) instead of succeeding, which made common_context_seq_rm abort.
57
+ + {
58
+ + const llama_pos p0n = p0 < 0 ? 0 : p0;
59
+ + const llama_pos p_max = llama_memory_hybrid::seq_pos_max(seq_id);
60
+ + if (p1 >= 0 ? p0n >= p1 : (p_max >= 0 && p0n > p_max)) {
61
+ + return true;
62
+ + }
63
+ + }
64
+ +
65
+ // same order as llama_memory_hybrid::seq_rm: try the recurrent cache first since it is the
66
+ // one that may refuse, and if it does the caches are left untouched
67
+ if (!get_mem_recr()->seq_rm(seq_id, p0, p1)) {
68
+ @@ -149,7 +159,9 @@ bool llama_memory_hybrid_idx::seq_rm(llama_seq_id seq_id, llama_pos p0, llama_po
69
+ }
70
+
71
+ if (mem_idx) {
72
+ - mem_idx->seq_rm(seq_id, p0, p1);
73
+ + if (!mem_idx->seq_rm(seq_id, p0, p1)) {
74
+ + return false;
75
+ + }
76
+ }
77
+
78
+ return get_mem_attn()->seq_rm(seq_id, p0, p1);
79
+ @@ -199,6 +211,26 @@ std::map<ggml_backend_buffer_type_t, size_t> llama_memory_hybrid_idx::memory_bre
80
+ return mb;
81
+ }
82
+
83
+ +void llama_memory_hybrid_idx::state_write(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) const {
84
+ + llama_memory_hybrid::state_write(io, seq_id, flags);
85
+ +
86
+ + // mem_idx is a KV cache — same PARTIAL_ONLY rule as mem_attn in the base.
87
+ + // without this, context checkpoints restore attn+recr and silently drop the QSA
88
+ + // indexer. after a restore the index describes a different position than the KV
89
+ + // caches, and a later kernel can wedge the GPU SDMA queue.
90
+ + if (mem_idx && (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
91
+ + mem_idx->state_write(io, seq_id, flags);
92
+ + }
93
+ +}
94
+ +
95
+ +void llama_memory_hybrid_idx::state_read(llama_io_read_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) {
96
+ + llama_memory_hybrid::state_read(io, seq_id, flags);
97
+ +
98
+ + if (mem_idx && (flags & LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY) == 0) {
99
+ + mem_idx->state_read(io, seq_id, flags);
100
+ + }
101
+ +}
102
+ +
103
+ llama_kv_cache * llama_memory_hybrid_idx::get_mem_idx() const {
104
+ return mem_idx.get();
105
+ }
106
+ diff --git a/src/llama-memory-hybrid-idx.h b/src/llama-memory-hybrid-idx.h
107
+ index d5e75ef..18a64c4 100644
108
+ --- a/src/llama-memory-hybrid-idx.h
109
+ +++ b/src/llama-memory-hybrid-idx.h
110
+ @@ -75,6 +75,9 @@ public:
111
+
112
+ std::map<ggml_backend_buffer_type_t, size_t> memory_breakdown() const override;
113
+
114
+ + void state_write(llama_io_write_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) const override;
115
+ + void state_read (llama_io_read_i & io, llama_seq_id seq_id = -1, llama_state_seq_flags flags = 0) override;
116
+ +
117
+ //
118
+ // llama_memory_hybrid_idx specific API
119
+ //
120
+ --
121
+ 2.43.0
122
+