CompressedGemma commited on
Commit
e18c1dc
·
verified ·
1 Parent(s): 74795f9

Upload patch_llamacpp_hpcq_seg.py

Browse files
Files changed (1) hide show
  1. patch_llamacpp_hpcq_seg.py +977 -0
patch_llamacpp_hpcq_seg.py ADDED
@@ -0,0 +1,977 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Patch llama.cpp to natively run HPCQ.SEG.V1 segmented Q2_K / Q3_K models
3
+ with ZERO weight expansion in RAM/VRAM.
4
+
5
+ How it works
6
+ ------------
7
+ * Tensors remain in their native ``GGML_TYPE_Q2_K`` (2.625 bpw) and
8
+ ``GGML_TYPE_Q3_K`` (3.4375 bpw) formats in RAM/VRAM (and stay ``mmap``-backed
9
+ on disk).
10
+ * Only the compact ``HQS1`` nibble stream (128 bytes per 256-weight superblock)
11
+ is bound to the tensor's payload address range in ``libggml-base``.
12
+ * No ``uint16_t`` order tables or ``uint8_t`` unpacked label arrays are
13
+ allocated on the heap. Instead, ``uint16_t ord[256]`` (512 bytes) is
14
+ reconstructed on the stack (CPU) or in ``__shared__`` memory (CUDA) per
15
+ 256-weight superblock:
16
+ - CPU ``dequantize_row_q2_K`` / ``dequantize_row_q3_K``: scatters each block's
17
+ 256 dequantized values via the 512-byte stack ``ord[256]``.
18
+ - CPU ``vec_dot`` (``ggml-cpu.c``): wraps ``ggml_vec_dot_q2_K_q8_K`` and
19
+ ``ggml_vec_dot_q3_K_q8_K``. For unsegmented tensors it tail-calls the stock
20
+ SIMD kernel directly; for segmented tensors it gathers ``block_q8_K y_perm``
21
+ (292 bytes on the stack) per superblock and calls the native AVX2/AVX512/
22
+ NEON SIMD ``vec_dot`` on ``(&x[i], &y_perm)``.
23
+ - CUDA ``dequantize_block_q2_K`` / ``dequantize_block_q3_K`` (``convert.cu``)
24
+ + ``ggml_cuda_mul_mat`` (``ggml-cuda.cu``): scatters each 256-weight
25
+ superblock in ``__shared__`` memory and routes segmented ``src0`` to the
26
+ pooled-scratch ``ggml_cuda_mul_mat_cublas`` path.
27
+
28
+ Usage
29
+ -----
30
+ python3 tools/patch_llamacpp_hpcq_seg.py --selftest
31
+ python3 tools/patch_llamacpp_hpcq_seg.py --llama /home/node/Desktop/Dev/llama.cpp --check
32
+ python3 tools/patch_llamacpp_hpcq_seg.py --llama /home/node/Desktop/Dev/llama.cpp --apply
33
+ python3 tools/patch_llamacpp_hpcq_seg.py --llama /home/node/Desktop/Dev/llama.cpp --revert
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import argparse
39
+ import shutil
40
+ import subprocess
41
+ import sys
42
+ import tempfile
43
+ from pathlib import Path
44
+
45
+ BEGIN = "HPCQ_SEG_PATCH_BEGIN"
46
+ END = "HPCQ_SEG_PATCH_END"
47
+ HEADER_REL = "ggml/include/hpcq-seg.h"
48
+
49
+ # --------------------------------------------------------------------------
50
+ # 1. C/C++/CUDA header: ggml/include/hpcq-seg.h
51
+ # --------------------------------------------------------------------------
52
+
53
+ HEADER = r"""// hpcq-seg.h — Zero-expansion HPCQ.SEG.V1 band-major support for Q2_K / Q3_K.
54
+ // Generated by HPC-Quantize tools/patch_llamacpp_hpcq_seg.py.
55
+ #pragma once
56
+
57
+ #include <stdint.h>
58
+ #include <stddef.h>
59
+ #include <string.h>
60
+ #include <stdbool.h>
61
+ #include "ggml.h"
62
+
63
+ #ifdef __cplusplus
64
+ extern "C" {
65
+ #endif
66
+
67
+ #define HPCQ_SEG_PREFIX "HPCQ.SEG.V1."
68
+ #define HPCQ_SEG_MAX_ENTRIES 2048
69
+
70
+ #ifdef __CUDACC__
71
+ #define HPCQ_HD __host__ __device__
72
+ #else
73
+ #define HPCQ_HD
74
+ #endif
75
+
76
+ struct hpcq_seg_entry {
77
+ uintptr_t base; // payload start (host ptr on CPU, device ptr on CUDA)
78
+ uintptr_t end; // payload end (exclusive)
79
+ int64_t block_bytes; // 84 for Q2_K, 110 for Q3_K
80
+ int64_t n_blocks; // number of 256-weight superblocks
81
+ uint8_t enc; // 0 = 4-bit nibbles (128B/blk), 1 = 8-bit (256B/blk)
82
+ uint8_t * packed; // compact packed label stream (128B or 256B per block)
83
+ void * dev_packed; // lazily allocated device copy for CUDA (or NULL)
84
+ };
85
+
86
+ GGML_API void ggml_hpcq_seg_bind_raw(
87
+ const void * payload, int64_t n_bytes,
88
+ const uint8_t * hqs1, size_t hqs1_len, int64_t block_bytes);
89
+
90
+ GGML_API const struct hpcq_seg_entry * ggml_hpcq_seg_find(
91
+ const void * ptr, int64_t block_bytes, int64_t * out_block_idx);
92
+
93
+ GGML_API void ggml_hpcq_seg_set_dev_packed(
94
+ const struct hpcq_seg_entry * entry, void * dev_packed);
95
+
96
+ // Reconstruct slot -> original_position permutation `order[256]` on the stack
97
+ // or in __shared__ memory from a single 256-weight block's packed labels.
98
+ // Matches `np.argsort(labels, kind="stable")`: slot `s` holds original pos `order[s]`.
99
+ static inline HPCQ_HD void hpcq_seg_make_order_block(
100
+ const uint8_t * blk_packed, uint8_t enc, uint16_t * order) {
101
+ if (enc == 0) {
102
+ uint16_t start[16];
103
+ for (int b = 0; b < 16; ++b) start[b] = 0;
104
+ for (int p = 0; p < 256; ++p) {
105
+ const uint8_t lab = (blk_packed[p >> 1] >> ((p & 1) * 4)) & 0x0F;
106
+ start[lab]++;
107
+ }
108
+ uint16_t acc = 0;
109
+ for (int b = 0; b < 16; ++b) {
110
+ const uint16_t c = start[b];
111
+ start[b] = acc;
112
+ acc = (uint16_t) (acc + c);
113
+ }
114
+ for (uint16_t p = 0; p < 256; ++p) {
115
+ const uint8_t lab = (blk_packed[p >> 1] >> ((p & 1) * 4)) & 0x0F;
116
+ order[start[lab]++] = p;
117
+ }
118
+ } else {
119
+ uint16_t start[256];
120
+ for (int b = 0; b < 256; ++b) start[b] = 0;
121
+ for (int p = 0; p < 256; ++p) start[blk_packed[p]]++;
122
+ uint16_t acc = 0;
123
+ for (int b = 0; b < 256; ++b) {
124
+ const uint16_t c = start[b];
125
+ start[b] = acc;
126
+ acc = (uint16_t) (acc + c);
127
+ }
128
+ for (uint16_t p = 0; p < 256; ++p) {
129
+ order[start[blk_packed[p]]++] = p;
130
+ }
131
+ }
132
+ }
133
+
134
+ #ifdef __cplusplus
135
+ }
136
+ #endif
137
+ """
138
+
139
+ # --------------------------------------------------------------------------
140
+ # 2. ggml/src/ggml.c: registry implementation in libggml-base
141
+ # --------------------------------------------------------------------------
142
+
143
+ GGML_C_INCLUDE = f"""
144
+ // {BEGIN}: hpcq seg header
145
+ #include "hpcq-seg.h"
146
+ // {END}
147
+ """
148
+
149
+ GGML_C_API = f"""
150
+ // {BEGIN}: compact nibble registry (no order/F16 expansion)
151
+ static int hpcq_seg_g_count = 0;
152
+ static struct hpcq_seg_entry hpcq_seg_g_entries[HPCQ_SEG_MAX_ENTRIES];
153
+
154
+ void ggml_hpcq_seg_bind_raw(
155
+ const void * payload, int64_t n_bytes,
156
+ const uint8_t * hqs1, size_t hqs1_len, int64_t block_bytes) {{
157
+ if (payload == NULL || hqs1 == NULL || n_bytes <= 0 || block_bytes <= 0) return;
158
+ if (hqs1_len < 10 || hqs1[0] != 'H' || hqs1[1] != 'Q' || hqs1[2] != 'S' || hqs1[3] != '1') return;
159
+ const uint8_t enc = hqs1[5];
160
+ const uint32_t n_labels = (uint32_t) hqs1[6] | ((uint32_t) hqs1[7] << 8) |
161
+ ((uint32_t) hqs1[8] << 16) | ((uint32_t) hqs1[9] << 24);
162
+ if (n_labels == 0 || (n_labels % 256) != 0) return;
163
+ const int64_t n_blocks = (int64_t) (n_labels / 256);
164
+ if (n_blocks * block_bytes != n_bytes) return;
165
+ const size_t stride = (enc == 0) ? 128u : 256u;
166
+ const size_t need = (size_t) n_blocks * stride;
167
+ if (hqs1_len < 10u + need) return;
168
+
169
+ const uintptr_t base = (uintptr_t) payload;
170
+ const uintptr_t end = base + (uintptr_t) n_bytes;
171
+ for (int i = 0; i < hpcq_seg_g_count; ++i) {{
172
+ if (hpcq_seg_g_entries[i].base == base) {{
173
+ if (hpcq_seg_g_entries[i].packed) free(hpcq_seg_g_entries[i].packed);
174
+ uint8_t * copy = (uint8_t *) malloc(need);
175
+ if (!copy) return;
176
+ memcpy(copy, hqs1 + 10, need);
177
+ hpcq_seg_g_entries[i].end = end;
178
+ hpcq_seg_g_entries[i].block_bytes = block_bytes;
179
+ hpcq_seg_g_entries[i].n_blocks = n_blocks;
180
+ hpcq_seg_g_entries[i].enc = enc;
181
+ hpcq_seg_g_entries[i].packed = copy;
182
+ hpcq_seg_g_entries[i].dev_packed = NULL;
183
+ return;
184
+ }}
185
+ }}
186
+ if (hpcq_seg_g_count >= HPCQ_SEG_MAX_ENTRIES) return;
187
+ uint8_t * copy = (uint8_t *) malloc(need);
188
+ if (!copy) return;
189
+ memcpy(copy, hqs1 + 10, need);
190
+ struct hpcq_seg_entry * e = &hpcq_seg_g_entries[hpcq_seg_g_count++];
191
+ e->base = base;
192
+ e->end = end;
193
+ e->block_bytes = block_bytes;
194
+ e->n_blocks = n_blocks;
195
+ e->enc = enc;
196
+ e->packed = copy;
197
+ e->dev_packed = NULL;
198
+ }}
199
+
200
+ const struct hpcq_seg_entry * ggml_hpcq_seg_find(
201
+ const void * ptr, int64_t block_bytes, int64_t * out_block_idx) {{
202
+ const uintptr_t p = (uintptr_t) ptr;
203
+ const int n = hpcq_seg_g_count;
204
+ for (int i = 0; i < n; ++i) {{
205
+ const struct hpcq_seg_entry * e = &hpcq_seg_g_entries[i];
206
+ if (p >= e->base && p < e->end && e->block_bytes == block_bytes) {{
207
+ if (out_block_idx) {{
208
+ *out_block_idx = (int64_t) ((p - e->base) / (uintptr_t) block_bytes);
209
+ }}
210
+ return e;
211
+ }}
212
+ }}
213
+ return NULL;
214
+ }}
215
+
216
+ void ggml_hpcq_seg_set_dev_packed(const struct hpcq_seg_entry * entry, void * dev_packed) {{
217
+ if (!entry) return;
218
+ const int n = hpcq_seg_g_count;
219
+ for (int i = 0; i < n; ++i) {{
220
+ if (&hpcq_seg_g_entries[i] == entry) {{
221
+ hpcq_seg_g_entries[i].dev_packed = dev_packed;
222
+ return;
223
+ }}
224
+ }}
225
+ }}
226
+ // {END}
227
+ """
228
+
229
+ # --------------------------------------------------------------------------
230
+ # 3. ggml/src/ggml-quants.c: stack-based scatter in dequantize_row_q2_K / q3_K
231
+ # --------------------------------------------------------------------------
232
+
233
+ Q2K_DEQ_OLD = """ const int nb = k / QK_K;
234
+
235
+ for (int i = 0; i < nb; i++) {
236
+
237
+ const float d = GGML_FP16_TO_FP32(x[i].d);
238
+ const float min = GGML_FP16_TO_FP32(x[i].dmin);
239
+
240
+ const uint8_t * q = x[i].qs;
241
+
242
+ int is = 0;
243
+ float dl, ml;
244
+ for (int n = 0; n < QK_K; n += 128) {
245
+ int shift = 0;
246
+ for (int j = 0; j < 4; ++j) {
247
+
248
+ uint8_t sc = x[i].scales[is++];
249
+ dl = d * (sc & 0xF); ml = min * (sc >> 4);
250
+ for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l] >> shift) & 3)) - ml;
251
+
252
+ sc = x[i].scales[is++];
253
+ dl = d * (sc & 0xF); ml = min * (sc >> 4);
254
+ for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3)) - ml;
255
+
256
+ shift += 2;
257
+ }
258
+ q += 32;
259
+ }
260
+ }
261
+ }"""
262
+
263
+ Q2K_DEQ_NEW = f""" const int nb = k / QK_K;
264
+
265
+ // {BEGIN}: stack-based per-block scatter for segmented Q2_K
266
+ int64_t hpcq_b0 = 0;
267
+ const struct hpcq_seg_entry * hpcq_seg = ggml_hpcq_seg_find(x, (int64_t) sizeof(block_q2_K), &hpcq_b0);
268
+ const size_t hpcq_stride = (hpcq_seg && hpcq_seg->enc != 0) ? 256u : 128u;
269
+ uint16_t hpcq_ord[QK_K];
270
+ // {END}
271
+
272
+ for (int i = 0; i < nb; i++) {{
273
+
274
+ float * y_out = y + i * QK_K;
275
+ if (hpcq_seg) {{
276
+ hpcq_seg_make_order_block(hpcq_seg->packed + (size_t) (hpcq_b0 + i) * hpcq_stride, hpcq_seg->enc, hpcq_ord);
277
+ }}
278
+
279
+ const float d = GGML_FP16_TO_FP32(x[i].d);
280
+ const float min = GGML_FP16_TO_FP32(x[i].dmin);
281
+
282
+ const uint8_t * q = x[i].qs;
283
+
284
+ int is = 0;
285
+ int base = 0;
286
+ float dl, ml;
287
+ for (int n = 0; n < QK_K; n += 128) {{
288
+ int shift = 0;
289
+ for (int j = 0; j < 4; ++j) {{
290
+
291
+ uint8_t sc = x[i].scales[is++];
292
+ dl = d * (sc & 0xF); ml = min * (sc >> 4);
293
+ for (int l = 0; l < 16; ++l) {{
294
+ const float v = dl * ((int8_t)((q[l] >> shift) & 3)) - ml;
295
+ if (hpcq_seg) y_out[hpcq_ord[base + l]] = v; else y_out[base + l] = v;
296
+ }}
297
+ base += 16;
298
+
299
+ sc = x[i].scales[is++];
300
+ dl = d * (sc & 0xF); ml = min * (sc >> 4);
301
+ for (int l = 0; l < 16; ++l) {{
302
+ const float v = dl * ((int8_t)((q[l+16] >> shift) & 3)) - ml;
303
+ if (hpcq_seg) y_out[hpcq_ord[base + l]] = v; else y_out[base + l] = v;
304
+ }}
305
+ base += 16;
306
+
307
+ shift += 2;
308
+ }}
309
+ q += 32;
310
+ }}
311
+ }}
312
+ }}"""
313
+
314
+ Q3K_DEQ_OLD = """ for (int i = 0; i < nb; i++) {
315
+
316
+ const float d_all = GGML_FP16_TO_FP32(x[i].d);
317
+
318
+ const uint8_t * GGML_RESTRICT q = x[i].qs;
319
+ const uint8_t * GGML_RESTRICT hm = x[i].hmask;
320
+ uint8_t m = 1;
321
+
322
+ memcpy(aux, x[i].scales, 12);
323
+ uint32_t tmp = aux[2];
324
+ aux[2] = ((aux[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4);
325
+ aux[3] = ((aux[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4);
326
+ aux[0] = (aux[0] & kmask2) | (((tmp >> 0) & kmask1) << 4);
327
+ aux[1] = (aux[1] & kmask2) | (((tmp >> 2) & kmask1) << 4);
328
+
329
+ int is = 0;
330
+ float dl;
331
+ for (int n = 0; n < QK_K; n += 128) {
332
+ int shift = 0;
333
+ for (int j = 0; j < 4; ++j) {
334
+
335
+ dl = d_all * (scales[is++] - 32);
336
+ for (int l = 0; l < 16; ++l) {
337
+ *y++ = dl * ((int8_t)((q[l+ 0] >> shift) & 3) - ((hm[l+ 0] & m) ? 0 : 4));
338
+ }
339
+
340
+ dl = d_all * (scales[is++] - 32);
341
+ for (int l = 0; l < 16; ++l) {
342
+ *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3) - ((hm[l+16] & m) ? 0 : 4));
343
+ }
344
+
345
+ shift += 2;
346
+ m <<= 1;
347
+ }
348
+ q += 32;
349
+ }
350
+
351
+ }
352
+ }"""
353
+
354
+ Q3K_DEQ_NEW = f""" // {BEGIN}: stack-based per-block scatter for segmented Q3_K
355
+ int64_t hpcq_b0 = 0;
356
+ const struct hpcq_seg_entry * hpcq_seg = ggml_hpcq_seg_find(x, (int64_t) sizeof(block_q3_K), &hpcq_b0);
357
+ const size_t hpcq_stride = (hpcq_seg && hpcq_seg->enc != 0) ? 256u : 128u;
358
+ uint16_t hpcq_ord[QK_K];
359
+ // {END}
360
+
361
+ for (int i = 0; i < nb; i++) {{
362
+
363
+ float * y_out = y + i * QK_K;
364
+ if (hpcq_seg) {{
365
+ hpcq_seg_make_order_block(hpcq_seg->packed + (size_t) (hpcq_b0 + i) * hpcq_stride, hpcq_seg->enc, hpcq_ord);
366
+ }}
367
+
368
+ const float d_all = GGML_FP16_TO_FP32(x[i].d);
369
+
370
+ const uint8_t * GGML_RESTRICT q = x[i].qs;
371
+ const uint8_t * GGML_RESTRICT hm = x[i].hmask;
372
+ uint8_t m = 1;
373
+
374
+ memcpy(aux, x[i].scales, 12);
375
+ uint32_t tmp = aux[2];
376
+ aux[2] = ((aux[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4);
377
+ aux[3] = ((aux[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4);
378
+ aux[0] = (aux[0] & kmask2) | (((tmp >> 0) & kmask1) << 4);
379
+ aux[1] = (aux[1] & kmask2) | (((tmp >> 2) & kmask1) << 4);
380
+
381
+ int is = 0;
382
+ int base = 0;
383
+ float dl;
384
+ for (int n = 0; n < QK_K; n += 128) {{
385
+ int shift = 0;
386
+ for (int j = 0; j < 4; ++j) {{
387
+
388
+ dl = d_all * (scales[is++] - 32);
389
+ for (int l = 0; l < 16; ++l) {{
390
+ const float v = dl * ((int8_t)((q[l+ 0] >> shift) & 3) - ((hm[l+ 0] & m) ? 0 : 4));
391
+ if (hpcq_seg) y_out[hpcq_ord[base + l]] = v; else y_out[base + l] = v;
392
+ }}
393
+ base += 16;
394
+
395
+ dl = d_all * (scales[is++] - 32);
396
+ for (int l = 0; l < 16; ++l) {{
397
+ const float v = dl * ((int8_t)((q[l+16] >> shift) & 3) - ((hm[l+16] & m) ? 0 : 4));
398
+ if (hpcq_seg) y_out[hpcq_ord[base + l]] = v; else y_out[base + l] = v;
399
+ }}
400
+ base += 16;
401
+
402
+ shift += 2;
403
+ m <<= 1;
404
+ }}
405
+ q += 32;
406
+ }}
407
+
408
+ }}
409
+ }}"""
410
+
411
+ # --------------------------------------------------------------------------
412
+ # 4. ggml/src/ggml-cpu/ggml-cpu.c: stack-gathered SIMD vec_dot wrappers
413
+ # --------------------------------------------------------------------------
414
+
415
+ CPU_VECDOT_WRAPPERS = f"""
416
+ // {BEGIN}: stack-gathered SIMD vec_dot wrappers for segmented Q2_K / Q3_K
417
+ #include "hpcq-seg.h"
418
+
419
+ static void hpcq_vec_dot_q2_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {{
420
+ int64_t b0 = 0;
421
+ const struct hpcq_seg_entry * seg = ggml_hpcq_seg_find(vx, (int64_t) sizeof(block_q2_K), &b0);
422
+ if (seg == NULL) {{
423
+ ggml_vec_dot_q2_K_q8_K(n, s, bs, vx, bx, vy, by, nrc);
424
+ return;
425
+ }}
426
+ const block_q2_K * GGML_RESTRICT x = (const block_q2_K *) vx;
427
+ const block_q8_K * GGML_RESTRICT y = (const block_q8_K *) vy;
428
+ const int nb = n / QK_K;
429
+ const size_t stride = (seg->enc != 0) ? 256u : 128u;
430
+ uint16_t ord[QK_K];
431
+ block_q8_K y_perm;
432
+ float sumf = 0.0f;
433
+ for (int i = 0; i < nb; ++i) {{
434
+ hpcq_seg_make_order_block(seg->packed + (size_t) (b0 + i) * stride, seg->enc, ord);
435
+ y_perm.d = y[i].d;
436
+ for (int g = 0; g < 16; ++g) {{
437
+ int16_t bsum = 0;
438
+ for (int l = 0; l < 16; ++l) {{
439
+ const int8_t qv = y[i].qs[ord[16 * g + l]];
440
+ y_perm.qs[16 * g + l] = qv;
441
+ bsum = (int16_t) (bsum + qv);
442
+ }}
443
+ y_perm.bsums[g] = bsum;
444
+ }}
445
+ float blk_s = 0.0f;
446
+ ggml_vec_dot_q2_K_q8_K(QK_K, &blk_s, bs, &x[i], bx, &y_perm, by, 1);
447
+ sumf += blk_s;
448
+ }}
449
+ *s = sumf;
450
+ }}
451
+
452
+ static void hpcq_vec_dot_q3_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {{
453
+ int64_t b0 = 0;
454
+ const struct hpcq_seg_entry * seg = ggml_hpcq_seg_find(vx, (int64_t) sizeof(block_q3_K), &b0);
455
+ if (seg == NULL) {{
456
+ ggml_vec_dot_q3_K_q8_K(n, s, bs, vx, bx, vy, by, nrc);
457
+ return;
458
+ }}
459
+ const block_q3_K * GGML_RESTRICT x = (const block_q3_K *) vx;
460
+ const block_q8_K * GGML_RESTRICT y = (const block_q8_K *) vy;
461
+ const int nb = n / QK_K;
462
+ const size_t stride = (seg->enc != 0) ? 256u : 128u;
463
+ uint16_t ord[QK_K];
464
+ block_q8_K y_perm;
465
+ float sumf = 0.0f;
466
+ for (int i = 0; i < nb; ++i) {{
467
+ hpcq_seg_make_order_block(seg->packed + (size_t) (b0 + i) * stride, seg->enc, ord);
468
+ y_perm.d = y[i].d;
469
+ for (int g = 0; g < 16; ++g) {{
470
+ int16_t bsum = 0;
471
+ for (int l = 0; l < 16; ++l) {{
472
+ const int8_t qv = y[i].qs[ord[16 * g + l]];
473
+ y_perm.qs[16 * g + l] = qv;
474
+ bsum = (int16_t) (bsum + qv);
475
+ }}
476
+ y_perm.bsums[g] = bsum;
477
+ }}
478
+ float blk_s = 0.0f;
479
+ ggml_vec_dot_q3_K_q8_K(QK_K, &blk_s, bs, &x[i], bx, &y_perm, by, 1);
480
+ sumf += blk_s;
481
+ }}
482
+ *s = sumf;
483
+ }}
484
+ // {END}
485
+ """
486
+
487
+ CPU_TRAITS_OLD = """ [GGML_TYPE_Q2_K] = {
488
+ .from_float = quantize_row_q2_K,
489
+ .vec_dot = ggml_vec_dot_q2_K_q8_K,
490
+ .vec_dot_type = GGML_TYPE_Q8_K,
491
+ .nrows = 1,
492
+ },
493
+ [GGML_TYPE_Q3_K] = {
494
+ .from_float = quantize_row_q3_K,
495
+ .vec_dot = ggml_vec_dot_q3_K_q8_K,
496
+ .vec_dot_type = GGML_TYPE_Q8_K,
497
+ .nrows = 1,
498
+ },"""
499
+
500
+ CPU_TRAITS_NEW = f""" [GGML_TYPE_Q2_K] = {{
501
+ .from_float = quantize_row_q2_K,
502
+ .vec_dot = hpcq_vec_dot_q2_K_q8_K, // {BEGIN}
503
+ .vec_dot_type = GGML_TYPE_Q8_K,
504
+ .nrows = 1,
505
+ }},
506
+ [GGML_TYPE_Q3_K] = {{
507
+ .from_float = quantize_row_q3_K,
508
+ .vec_dot = hpcq_vec_dot_q3_K_q8_K, // {END}
509
+ .vec_dot_type = GGML_TYPE_Q8_K,
510
+ .nrows = 1,
511
+ }},"""
512
+
513
+ # --------------------------------------------------------------------------
514
+ # 5. ggml/src/ggml-cuda/convert.cu & ggml-cuda.cu: shared-mem scatter on GPU
515
+ # --------------------------------------------------------------------------
516
+
517
+ CUDA_CONVERT_OLD_KERNELS = """template<typename dst_t>
518
+ static __global__ void dequantize_block_q2_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
519
+ const int64_t i = blockIdx.x;
520
+
521
+ dequantize_q2_K(vx, i, yy + i*QK_K, threadIdx.x);
522
+ }
523
+
524
+ template<typename dst_t>
525
+ static __global__ void dequantize_block_q3_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
526
+ const int64_t i = blockIdx.x;
527
+
528
+ dequantize_q3_K(vx, i, yy + i*QK_K, threadIdx.x);
529
+ }"""
530
+
531
+ CUDA_CONVERT_NEW_KERNELS = f"""// {BEGIN}: shared-memory per-block scatter for segmented Q2_K / Q3_K on CUDA
532
+ #include "hpcq-seg.h"
533
+
534
+ static inline const uint8_t * hpcq_cuda_get_dev_packed(
535
+ const void * vx, int64_t bs, int64_t * out_b0, uint8_t * out_enc) {{
536
+ const struct hpcq_seg_entry * seg = ggml_hpcq_seg_find(vx, bs, out_b0);
537
+ if (!seg) return nullptr;
538
+ *out_enc = seg->enc;
539
+ if (seg->dev_packed == nullptr) {{
540
+ const size_t stride = (seg->enc != 0) ? 256u : 128u;
541
+ const size_t nbytes = (size_t) seg->n_blocks * stride;
542
+ void * d_ptr = nullptr;
543
+ if (cudaMalloc(&d_ptr, nbytes) == cudaSuccess && d_ptr != nullptr) {{
544
+ if (cudaMemcpy(d_ptr, seg->packed, nbytes, cudaMemcpyHostToDevice) == cudaSuccess) {{
545
+ ggml_hpcq_seg_set_dev_packed(seg, d_ptr);
546
+ }} else {{
547
+ cudaFree(d_ptr);
548
+ d_ptr = nullptr;
549
+ }}
550
+ }}
551
+ }}
552
+ return (const uint8_t *) seg->dev_packed;
553
+ }}
554
+
555
+ template<typename dst_t>
556
+ static __global__ void dequantize_block_q2_K(
557
+ const void * __restrict__ vx, dst_t * __restrict__ yy,
558
+ const uint8_t * __restrict__ d_packed = nullptr, int64_t b0 = 0, uint8_t enc = 0) {{
559
+ const int64_t i = blockIdx.x;
560
+ if (d_packed == nullptr) {{
561
+ dequantize_q2_K(vx, i, yy + i*QK_K, threadIdx.x);
562
+ return;
563
+ }}
564
+ __shared__ dst_t sh_y[QK_K];
565
+ __shared__ uint16_t sh_ord[QK_K];
566
+ dequantize_q2_K(vx, i, sh_y, threadIdx.x);
567
+ if (threadIdx.x == 0) {{
568
+ const size_t stride = (enc != 0) ? 256u : 128u;
569
+ hpcq_seg_make_order_block(d_packed + (size_t) (b0 + i) * stride, enc, sh_ord);
570
+ }}
571
+ __syncthreads();
572
+ dst_t * y_out = yy + i * QK_K;
573
+ for (int s = threadIdx.x; s < QK_K; s += 64) {{
574
+ y_out[sh_ord[s]] = sh_y[s];
575
+ }}
576
+ }}
577
+
578
+ template<typename dst_t>
579
+ static __global__ void dequantize_block_q3_K(
580
+ const void * __restrict__ vx, dst_t * __restrict__ yy,
581
+ const uint8_t * __restrict__ d_packed = nullptr, int64_t b0 = 0, uint8_t enc = 0) {{
582
+ const int64_t i = blockIdx.x;
583
+ if (d_packed == nullptr) {{
584
+ dequantize_q3_K(vx, i, yy + i*QK_K, threadIdx.x);
585
+ return;
586
+ }}
587
+ __shared__ dst_t sh_y[QK_K];
588
+ __shared__ uint16_t sh_ord[QK_K];
589
+ dequantize_q3_K(vx, i, sh_y, threadIdx.x);
590
+ if (threadIdx.x == 0) {{
591
+ const size_t stride = (enc != 0) ? 256u : 128u;
592
+ hpcq_seg_make_order_block(d_packed + (size_t) (b0 + i) * stride, enc, sh_ord);
593
+ }}
594
+ __syncthreads();
595
+ dst_t * y_out = yy + i * QK_K;
596
+ for (int s = threadIdx.x; s < QK_K; s += 64) {{
597
+ y_out[sh_ord[s]] = sh_y[s];
598
+ }}
599
+ }}
600
+ // {END}"""
601
+
602
+ CUDA_CONVERT_OLD_LAUNCH = """template<typename dst_t>
603
+ static void dequantize_row_q2_K_cuda(const void * vx, dst_t * y, const int64_t k, cudaStream_t stream) {
604
+ const int nb = k / QK_K;
605
+ dequantize_block_q2_K<<<nb, 64, 0, stream>>>(vx, y);
606
+ }
607
+
608
+ template<typename dst_t>
609
+ static void dequantize_row_q3_K_cuda(const void * vx, dst_t * y, const int64_t k, cudaStream_t stream) {
610
+ const int nb = k / QK_K;
611
+ dequantize_block_q3_K<<<nb, 64, 0, stream>>>(vx, y);
612
+ }"""
613
+
614
+ CUDA_CONVERT_NEW_LAUNCH = f"""template<typename dst_t>
615
+ static void dequantize_row_q2_K_cuda(const void * vx, dst_t * y, const int64_t k, cudaStream_t stream) {{
616
+ const int nb = k / QK_K;
617
+ int64_t b0 = 0; uint8_t enc = 0;
618
+ const uint8_t * d_packed = hpcq_cuda_get_dev_packed(vx, (int64_t) sizeof(block_q2_K), &b0, &enc);
619
+ dequantize_block_q2_K<<<nb, 64, 0, stream>>>(vx, y, d_packed, b0, enc);
620
+ }}
621
+
622
+ template<typename dst_t>
623
+ static void dequantize_row_q3_K_cuda(const void * vx, dst_t * y, const int64_t k, cudaStream_t stream) {{
624
+ const int nb = k / QK_K;
625
+ int64_t b0 = 0; uint8_t enc = 0;
626
+ const uint8_t * d_packed = hpcq_cuda_get_dev_packed(vx, (int64_t) sizeof(block_q3_K), &b0, &enc);
627
+ dequantize_block_q3_K<<<nb, 64, 0, stream>>>(vx, y, d_packed, b0, enc);
628
+ }}"""
629
+
630
+ CUDA_MULMAT_OLD = """ if (ggml_cuda_should_use_mmvq(src0->type, cc, ne11)) {
631
+ ggml_cuda_mul_mat_vec_q(ctx, src0, src1, nullptr, dst);
632
+ return;
633
+ }
634
+ if (ggml_cuda_should_use_mmq(src0->type, cc, ne11, /*n_experts =*/ 0)) {
635
+ ggml_cuda_mul_mat_q(ctx, src0, src1, nullptr, dst);
636
+ return;
637
+ }
638
+ ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst);"""
639
+
640
+ CUDA_MULMAT_NEW = f""" // {BEGIN}: route segmented Q2_K/Q3_K to pooled-scratch cublas dequant path
641
+ if ((src0->type == GGML_TYPE_Q2_K || src0->type == GGML_TYPE_Q3_K) &&
642
+ ggml_hpcq_seg_find(src0->data, (int64_t) ggml_type_size(src0->type), nullptr) != nullptr) {{
643
+ ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst);
644
+ return;
645
+ }}
646
+ // {END}
647
+ if (ggml_cuda_should_use_mmvq(src0->type, cc, ne11)) {{
648
+ ggml_cuda_mul_mat_vec_q(ctx, src0, src1, nullptr, dst);
649
+ return;
650
+ }}
651
+ if (ggml_cuda_should_use_mmq(src0->type, cc, ne11, /*n_experts =*/ 0)) {{
652
+ ggml_cuda_mul_mat_q(ctx, src0, src1, nullptr, dst);
653
+ return;
654
+ }}
655
+ ggml_cuda_mul_mat_cublas(ctx, src0, src1, dst);"""
656
+
657
+
658
+ def _read(p: Path) -> str:
659
+ return p.read_text(encoding="utf-8")
660
+
661
+
662
+ def _write(p: Path, s: str) -> None:
663
+ p.write_text(s, encoding="utf-8")
664
+
665
+
666
+ def _backup(p: Path) -> None:
667
+ bak = p.with_suffix(p.suffix + ".hpcq-bak")
668
+ if not bak.exists():
669
+ shutil.copy2(p, bak)
670
+
671
+
672
+ def _require_once(text: str, needle: str, what: str) -> None:
673
+ n = text.count(needle)
674
+ if n != 1:
675
+ raise SystemExit(f"anchor for {what}: found {n} occurrence(s), expected 1")
676
+
677
+
678
+ def _insert_after(text: str, anchor: str, block: str, what: str) -> str:
679
+ _require_once(text, anchor, what)
680
+ i = text.index(anchor) + len(anchor)
681
+ return text[:i] + block + text[i:]
682
+
683
+
684
+ def _replace_block(text: str, old: str, new: str, what: str) -> str:
685
+ _require_once(text, old, what)
686
+ return text.replace(old, new, 1)
687
+
688
+
689
+ # --------------------------------------------------------------------------
690
+ # Patch steps
691
+ # --------------------------------------------------------------------------
692
+
693
+ def step_header(root: Path) -> None:
694
+ _write(root / HEADER_REL, HEADER)
695
+ old_src_h = root / "ggml" / "src" / "hpcq-seg.h"
696
+ if old_src_h.exists():
697
+ old_src_h.unlink()
698
+
699
+
700
+ def step_ggml_c(root: Path) -> None:
701
+ p = root / "ggml" / "src" / "ggml.c"
702
+ s = _read(p)
703
+ if BEGIN in s:
704
+ return
705
+ _backup(p)
706
+ anchor = '#include "ggml-impl.h"'
707
+ s = _insert_after(s, anchor, "\n" + GGML_C_INCLUDE, "ggml.c include")
708
+ marker = "////////////////////////////////////////////////////////////////////////////////"
709
+ i = s.rindex(marker)
710
+ s = s[:i] + GGML_C_API + "\n\n" + s[i:]
711
+ _write(p, s)
712
+
713
+
714
+ def step_ggml_quants(root: Path) -> None:
715
+ p = root / "ggml" / "src" / "ggml-quants.c"
716
+ s = _read(p)
717
+ if BEGIN in s:
718
+ return
719
+ _backup(p)
720
+ anchor = '#include "ggml-quants.h"'
721
+ s = _insert_after(s, anchor, '\n#include "hpcq-seg.h"\n', "ggml-quants.c include")
722
+ s = _replace_block(s, Q2K_DEQ_OLD, Q2K_DEQ_NEW, "dequantize_row_q2_K")
723
+ s = _replace_block(s, Q3K_DEQ_OLD, Q3K_DEQ_NEW, "dequantize_row_q3_K")
724
+ _write(p, s)
725
+
726
+
727
+ def step_ggml_cpu(root: Path) -> None:
728
+ p = root / "ggml" / "src" / "ggml-cpu" / "ggml-cpu.c"
729
+ s = _read(p)
730
+ if BEGIN in s:
731
+ return
732
+ _backup(p)
733
+ anchor = "static const struct ggml_type_traits_cpu type_traits_cpu[GGML_TYPE_COUNT] = {"
734
+ _require_once(s, anchor, "ggml-cpu.c type_traits_cpu")
735
+ s = s.replace(anchor, CPU_VECDOT_WRAPPERS + "\n" + anchor, 1)
736
+ s = _replace_block(s, CPU_TRAITS_OLD, CPU_TRAITS_NEW, "ggml-cpu.c Q2_K/Q3_K traits")
737
+ _write(p, s)
738
+
739
+
740
+ def step_ggml_cuda(root: Path) -> None:
741
+ conv = root / "ggml" / "src" / "ggml-cuda" / "convert.cu"
742
+ s = _read(conv)
743
+ if BEGIN not in s:
744
+ _backup(conv)
745
+ s = _replace_block(s, CUDA_CONVERT_OLD_KERNELS, CUDA_CONVERT_NEW_KERNELS, "convert.cu kernels")
746
+ s = _replace_block(s, CUDA_CONVERT_OLD_LAUNCH, CUDA_CONVERT_NEW_LAUNCH, "convert.cu launch")
747
+ _write(conv, s)
748
+
749
+ cu = root / "ggml" / "src" / "ggml-cuda" / "ggml-cuda.cu"
750
+ s2 = _read(cu)
751
+ if BEGIN not in s2:
752
+ _backup(cu)
753
+ anchor = '#include "ggml-cuda.h"'
754
+ s2 = _insert_after(s2, anchor, '\n#include "hpcq-seg.h"', "ggml-cuda.cu include")
755
+ s2 = _replace_block(s2, CUDA_MULMAT_OLD, CUDA_MULMAT_NEW, "ggml-cuda.cu mul_mat")
756
+ _write(cu, s2)
757
+
758
+
759
+ def step_loader(root: Path) -> None:
760
+ cpp = root / "src" / "llama-model-loader.cpp"
761
+ s = _read(cpp)
762
+ if BEGIN in s:
763
+ return
764
+ _backup(cpp)
765
+
766
+ anchor = '#include "llama-model-loader.h"'
767
+ s = _insert_after(s, anchor, '\n#include "hpcq-seg.h"', "loader include")
768
+
769
+ # prevent CPU repack buffer selection on segmented tensors so they stay in
770
+ # native block_q2_K / block_q3_K layout for hpcq_vec_dot_q2_K_q8_K
771
+ anchor_buft = """ if (!buft) {
772
+ buft = select_weight_buft(hparams, t_meta, op, info.src1_noncont, buft_list);
773
+ if (!buft) {
774
+ throw std::runtime_error(format("failed to find a compatible buffer type for tensor %s", tn.str().c_str()));
775
+ }
776
+ }"""
777
+ new_buft = anchor_buft + f"""
778
+ // {BEGIN}: keep segmented CPU tensors in standard host/mmap buffer (no 8x8 interleave repack)
779
+ if (buft && metadata) {{
780
+ const std::string seg_key = std::string(HPCQ_SEG_PREFIX) + tn.str();
781
+ if (gguf_find_key(metadata, seg_key.c_str()) >= 0) {{
782
+ auto * bdev = ggml_backend_buft_get_device(buft);
783
+ if (bdev && ggml_backend_dev_type(bdev) == GGML_BACKEND_DEVICE_TYPE_CPU &&
784
+ buft != ggml_backend_cpu_buffer_type()) {{
785
+ buft = ggml_backend_cpu_buffer_type();
786
+ }}
787
+ }}
788
+ }}
789
+ // {END}"""
790
+ s = _replace_block(s, anchor_buft, new_buft, "loader select_weight_buft")
791
+
792
+ # bind compact HQS1 nibble stream directly to the tensor's payload pointer
793
+ anchor_tail = " size_done += n_size;\n }"
794
+ new_tail = f""" // {BEGIN}: bind compact HQS1 nibble stream to payload range (no weight/order expansion)
795
+ if (metadata && cur->data != NULL && (cur->type == GGML_TYPE_Q2_K || cur->type == GGML_TYPE_Q3_K)) {{
796
+ const std::string seg_key = std::string(HPCQ_SEG_PREFIX) + ggml_get_name(cur);
797
+ const int64_t seg_ki = gguf_find_key(metadata, seg_key.c_str());
798
+ if (seg_ki >= 0 && gguf_get_kv_type(metadata, seg_ki) == GGUF_TYPE_ARRAY &&
799
+ gguf_get_arr_type(metadata, seg_ki) == GGUF_TYPE_UINT8) {{
800
+ ggml_hpcq_seg_bind_raw(
801
+ cur->data,
802
+ (int64_t) ggml_nbytes(cur),
803
+ (const uint8_t *) gguf_get_arr_data(metadata, seg_ki),
804
+ gguf_get_arr_n(metadata, seg_ki),
805
+ (int64_t) ggml_type_size(cur->type));
806
+ }}
807
+ }}
808
+ // {END}
809
+ size_done += n_size;
810
+ }}"""
811
+ s = _replace_block(s, anchor_tail, new_tail, "loader load_all_data tail")
812
+ _write(cpp, s)
813
+
814
+
815
+ STEPS = [
816
+ ("header", step_header),
817
+ ("ggml.c", step_ggml_c),
818
+ ("ggml-quants.c", step_ggml_quants),
819
+ ("ggml-cpu.c", step_ggml_cpu),
820
+ ("ggml-cuda", step_ggml_cuda),
821
+ ("loader", step_loader),
822
+ ]
823
+
824
+ TOUCHED_FILES = (
825
+ "ggml/src/ggml.c",
826
+ "ggml/src/ggml-quants.c",
827
+ "ggml/src/ggml-cpu/ggml-cpu.c",
828
+ "ggml/src/ggml-cuda/convert.cu",
829
+ "ggml/src/ggml-cuda/ggml-cuda.cu",
830
+ "src/llama-model-loader.cpp",
831
+ "src/llama-model-loader.h",
832
+ )
833
+
834
+
835
+ def check(root: Path) -> int:
836
+ ok = True
837
+ checks = [
838
+ ("ggml.c", root / "ggml/src/ggml.c", ['#include "ggml-impl.h"']),
839
+ ("ggml-quants.c", root / "ggml/src/ggml-quants.c", [Q2K_DEQ_OLD, Q3K_DEQ_OLD]),
840
+ ("ggml-cpu.c", root / "ggml/src/ggml-cpu/ggml-cpu.c", [CPU_TRAITS_OLD]),
841
+ ("convert.cu", root / "ggml/src/ggml-cuda/convert.cu", [CUDA_CONVERT_OLD_KERNELS, CUDA_CONVERT_OLD_LAUNCH]),
842
+ ("ggml-cuda.cu", root / "ggml/src/ggml-cuda/ggml-cuda.cu", [CUDA_MULMAT_OLD]),
843
+ ("loader.cpp", root / "src/llama-model-loader.cpp", [" size_done += n_size;\n }"]),
844
+ ]
845
+ for label, p, needles in checks:
846
+ s = _read(p)
847
+ if BEGIN in s:
848
+ print(f"{label:15s}: already patched")
849
+ else:
850
+ present = all(n in s for n in needles)
851
+ print(f"{label:15s}: anchors {'ok' if present else 'MISSING'}")
852
+ ok &= present
853
+ return 0 if ok else 1
854
+
855
+
856
+ def apply(root: Path) -> int:
857
+ for name, fn in STEPS:
858
+ fn(root)
859
+ print(f"patched {name}")
860
+ print("done.")
861
+ return 0
862
+
863
+
864
+ def revert(root: Path) -> int:
865
+ for rel in TOUCHED_FILES:
866
+ p = root / rel
867
+ bak = p.with_suffix(p.suffix + ".hpcq-bak")
868
+ if bak.exists():
869
+ shutil.copy2(bak, p)
870
+ print(f"restored {rel}")
871
+ for hrel in (HEADER_REL, "ggml/src/hpcq-seg.h"):
872
+ h = root / hrel
873
+ if h.exists():
874
+ h.unlink()
875
+ print(f"removed {hrel}")
876
+ return 0
877
+
878
+
879
+ SELFTEST_CPP = r"""
880
+ #include <cstdio>
881
+ #include <cstdlib>
882
+ #include <cstring>
883
+ #include <vector>
884
+
885
+ #define GGML_API
886
+ #include "hpcq-seg.h"
887
+
888
+ int main() {
889
+ // Verify that hpcq_seg_make_order_block produces the exact stable argsort
890
+ // (slot -> original_position) for both nibble (enc=0) and byte (enc=1) streams,
891
+ // and that gathering y_perm by ord[s] matches the scattered dot product.
892
+ uint8_t labels[256];
893
+ uint8_t nibbles[128];
894
+ for (int p = 0; p < 256; ++p) {
895
+ labels[p] = (uint8_t) ((p * 7 + 3) % 16);
896
+ }
897
+ for (int i = 0; i < 128; ++i) {
898
+ nibbles[i] = (uint8_t) ((labels[2 * i] & 0x0F) | ((labels[2 * i + 1] & 0x0F) << 4));
899
+ }
900
+ uint16_t ord0[256], ord1[256];
901
+ hpcq_seg_make_order_block(nibbles, 0, ord0);
902
+ hpcq_seg_make_order_block(labels, 1, ord1);
903
+ for (int s = 0; s < 256; ++s) {
904
+ if (ord0[s] != ord1[s]) return 1;
905
+ if (s > 0) {
906
+ uint8_t l_prev = labels[ord0[s - 1]];
907
+ uint8_t l_curr = labels[ord0[s]];
908
+ if (l_prev > l_curr) return 2;
909
+ if (l_prev == l_curr && ord0[s - 1] >= ord0[s]) return 3;
910
+ }
911
+ }
912
+ // Check dot-product identity: sum_s x_slot[s] * y_orig[ord[s]] == sum_p x_orig[p] * y_orig[p]
913
+ int x_orig[256], x_slot[256], y_orig[256], y_perm[256];
914
+ for (int p = 0; p < 256; ++p) {
915
+ x_orig[p] = (p * 13 - 97);
916
+ y_orig[p] = (p * 5 - 41);
917
+ }
918
+ for (int s = 0; s < 256; ++s) {
919
+ x_slot[s] = x_orig[ord0[s]];
920
+ y_perm[s] = y_orig[ord0[s]];
921
+ }
922
+ long dot_orig = 0, dot_perm = 0;
923
+ for (int i = 0; i < 256; ++i) {
924
+ dot_orig += (long) x_orig[i] * (long) y_orig[i];
925
+ dot_perm += (long) x_slot[i] * (long) y_perm[i];
926
+ }
927
+ if (dot_orig != dot_perm) return 4;
928
+ std::printf("selftest ok (dot=%ld)\n", dot_perm);
929
+ return 0;
930
+ }
931
+ """
932
+
933
+
934
+ def selftest() -> int:
935
+ with tempfile.TemporaryDirectory() as td:
936
+ td = Path(td)
937
+ (td / "ggml.h").write_text("#pragma once\n", encoding="utf-8")
938
+ (td / "hpcq-seg.h").write_text(HEADER, encoding="utf-8")
939
+ src = td / "selftest.cpp"
940
+ src.write_text(SELFTEST_CPP, encoding="utf-8")
941
+ exe = td / "selftest"
942
+ for cmd in (
943
+ ["g++", "-O2", "-std=c++11", "-I", str(td), str(src), "-o", str(exe)],
944
+ [str(exe)],
945
+ ):
946
+ r = subprocess.run(cmd, capture_output=True, text=True)
947
+ if r.returncode != 0:
948
+ print(r.stderr, file=sys.stderr)
949
+ return 1
950
+ if r.stdout:
951
+ print(r.stdout.strip())
952
+ return 0
953
+
954
+
955
+ def main() -> int:
956
+ ap = argparse.ArgumentParser()
957
+ ap.add_argument("--llama", default="/home/node/Desktop/Dev/llama.cpp")
958
+ g = ap.add_mutually_exclusive_group(required=True)
959
+ g.add_argument("--check", action="store_true")
960
+ g.add_argument("--apply", action="store_true")
961
+ g.add_argument("--revert", action="store_true")
962
+ g.add_argument("--selftest", action="store_true")
963
+ a = ap.parse_args()
964
+ if a.selftest:
965
+ return selftest()
966
+ root = Path(a.llama)
967
+ if not (root / "ggml" / "src" / "ggml-quants.c").exists():
968
+ raise SystemExit(f"not a llama.cpp tree: {root}")
969
+ if a.check:
970
+ return check(root)
971
+ if a.apply:
972
+ return apply(root)
973
+ return revert(root)
974
+
975
+
976
+ if __name__ == "__main__":
977
+ sys.exit(main())