File size: 22,417 Bytes
032410e
 
 
 
 
 
 
 
 
 
 
c1fa642
 
 
 
 
 
 
 
 
 
 
 
7263337
c1fa642
 
7263337
 
032410e
 
c1fa642
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1c1a805
 
 
 
c1fa642
 
 
 
ad53eb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a2918a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad53eb4
 
 
 
 
 
 
 
 
 
 
 
032410e
 
 
 
 
 
 
 
5d3e027
176ef13
 
 
 
 
 
 
 
 
 
032410e
 
 
 
 
 
 
 
5d3e027
20c42e1
176ef13
 
 
c1ddb47
032410e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d3e027
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20c42e1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176ef13
 
 
 
 
fa0329a
 
 
176ef13
 
 
 
 
 
 
fa0329a
176ef13
 
 
 
fa0329a
 
 
 
176ef13
 
fa0329a
176ef13
 
 
 
 
5482b0f
 
 
176ef13
 
 
 
 
 
 
 
 
 
 
 
5482b0f
 
 
176ef13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c1ddb47
 
 
 
 
 
 
 
 
 
1c1a805
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176ef13
 
 
 
 
 
 
 
 
 
032410e
 
 
 
 
 
 
 
 
 
 
 
 
5d3e027
 
fa0329a
 
 
032410e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
---
license: gpl-3.0
library_name: llama.cpp
tags:
  - openpangu
  - llama.cpp
  - moe
  - gguf
  - cpu-inference
---

# openPangu-2.0-Flash support for llama.cpp v0.7.0

This repository contains a patch that adds support for **openPangu-2.0-Flash**
(92B MoE, ~6B active parameters, 512K context) to the latest llama.cpp release
**v0.7.0** (commit `620d2225cc436ab0b001e3200e590e3b286ef9ab`, 2026-10-15).

The support was ported from
[mrexodia/llama.cpp-openPangu-2.0-Flash](https://github.com/mrexodia/llama.cpp-openPangu-2.0-Flash)
(which tracks an older llama.cpp base) and rebased on top of v0.7.0.

Files:

- `llama.cpp-openpangu-v0.7.0.diff` — the full patch (48 files, +3340 / −368)
- `patch.sh` — downloads the pinned llama.cpp commit, applies the patch and
  prints build/run instructions
- `PROMPT_REPRODUCE.md` — task brief for reproducing this project with a
  coding agent (port + A/B experiment protocol + validation + upload)
- `LICENSE` — GPL-3.0 (this project) with the references/licenses of the
  upstream projects it is built on

## 中文說明

本 repo 是將 openPangu-2.0-Flash(92B MoE、約 6B 激活參數、512K 上下文)
的 llama.cpp 支援,從 mrexodia 的 fork 移植到最新的 llama.cpp **v0.7.0** 上。

用法:

1. 執行 `./patch.sh`(會自動下載 v0.7.0 原始碼並套用 patch)
2. `cd llama.cpp-620d2225cc436ab0b001e3200e590e3b286ef9ab`
3. `cmake -B build -S . -DCMAKE_BUILD_TYPE=Release && cmake --build build -j`
4. 下載 GGUF 模型(見下方連結)後即可執行 `llama-cli` / `llama-server`

## What is included

- The `openpangu-v2` architecture: absorbed MLA attention, DSA sparse attention
  (lightning-indexer top-2048 selection on the global layers), per-layer
  sliding-window attention via a hybrid iSWA cache, 4-stream manifold
  hyper-connections (mHC), MoME causal convolutions with recurrent cross-batch
  state, and 128 learned cache-resident attention sinks per layer
- Fused CPU/CUDA kernels for the mHC mixing chain (`GGML_OP_SINKHORN`,
  `GGML_OP_HC_MIX`), with automatic fallback to the unfused ops on backends
  without the kernels
- Gather-based sparse attention at decode: DSA layers attend only the top-2048
  selected tokens (plus sinks), with a fused indexer-scoring kernel
  (`GGML_OP_DSA_SCORE`)
- Fused DSA indexer scoring at prefill (tiled kernel that skips the multi-GB
  scoring intermediate) plus a radix-select top-k for `GGML_OP_TOP_K`
- Multi-token-prediction self-speculative decoding (`--spec-type draft-mtp`,
  with the split MTP draft GGUF)
- Chat support: tool calling and ` thinking` reasoning parsing for the openPangu
  template
- HF → GGUF conversion (`conversion/pangu.py`) and a base/MTP split tool
  (`conversion/split_pangu_mtp.py`)

Ported and adapted to v0.7.0 APIs, plus fixes on top of the original fork:

- adapted to the v0.7.0 common chat parser API (`build_chat_peg_parser`),
  per-layer `n_ff_exp()`, and the new `build_attn_mha(..., n_kv_max, ...)`
  signature
- CPU AMX fix: the AMX weight packer only implements 2D layouts; batched
  (3D/4D) quantized weights — e.g. the MLA `wk_b`/`wv_b` tensors — were
  corrupted when routed through the AMX extra buffer, producing gibberish
  output. The AMX backend now rejects batched tensors and they run on the
  plain CPU path
- the absorbed-MLA `wk_b`/`wv_b` inputs are kept contiguous so they are also
  correct with weight repacking on other backends

## Requirements

- A C/C++ build environment (CMake ≥ 3.14, C++17 compiler)
- No GPU required (CPU-only works); CUDA/ Metal/ Vulkan also supported
- Get the GGUF models at
  [mrexodia/openPangu-2.0-Flash-GGUF](https://huggingface.co/mrexodia/openPangu-2.0-Flash-GGUF):
  - `openPangu-2.0-Flash-base-Q3_K_M.gguf` — 40.7 GiB
  - `openPangu-2.0-Flash-base-Q4_K_M.gguf` — 51.5 GiB
  - `openPangu-2.0-Flash-base-Q8_0.gguf` — 90.8 GiB
  - `openPangu-2.0-Flash-base-BF16.gguf` — 170.7 GiB
  - `openPangu-2.0-Flash-mtp-Q8_0.gguf` — 9.2 GiB (optional MTP head)

## Quick start

```sh
./patch.sh
cd llama.cpp-620d2225cc436ab0b001e3200e590e3b286ef9ab
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build -j --target llama-cli llama-server
```

CUDA build:

```sh
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON
```

## Run

```sh
./build/bin/llama-cli -m openPangu-2.0-Flash-base-Q3_K_M.gguf -c 65536 --jinja -t $(nproc)

./build/bin/llama-server -m openPangu-2.0-Flash-base-Q3_K_M.gguf \
    -c 65536 --jinja --host 0.0.0.0 --port 8080
```

Context scales up to `-c 524288`; the compressed MLA KV cache needs only ~12 GB
at the full 512K.

### Multi-token prediction (self-speculative decoding)

```sh
./build/bin/llama-cli -m openPangu-2.0-Flash-base-Q3_K_M.gguf \
    --spec-draft-model openPangu-2.0-Flash-mtp-Q8_0.gguf \
    --spec-type draft-mtp -c 65536 --jinja
```

Notes:

- The MTP draft adds ~10 GB of RAM usage on top of the base model
- On CPUs with AMX, weight repacking (`--repack`, enabled by default) costs
  ~16 GiB of extra RAM; if the combined footprint does not fit, run with `-nr`
  (no repack)
- On CPU-only setups the draft overhead can make generation slower than plain
  decoding — measure on your hardware (`llama-bench` does not support draft
  models; use `llama-cli` and compare the reported t/s)

## Test environment(測試環境)

All performance numbers below were measured on a real machine:

- **CPU**: Intel Xeon Platinum 8559C (Emerald Rapids, supports AMX); the test
  container is capped at **16 vCPUs** (host has 2 sockets × 48 cores × 2 SMT)
- **RAM**: 2.0 TiB host; the test environment enforces a **64 GiB per-process
  memory cap**, which is why all testing used the 40.7 GiB `Q3_K_M` quant
- **GPU**: none — CPU-only inference, 16 threads (`-t 16`)
- **OS/toolchain**: Linux, gcc 14.2.0, CMake 3.31.6
- **Model**: `openPangu-2.0-Flash-base-Q3_K_M.gguf` (40.72 GiB, 91.6 B params)

Measured resident memory of `llama-cli` with this model (`-c 512`, `-n 1`):

| configuration | peak RSS |
|---|---|
| default (AMX weight repacking enabled) | ~57.1 GiB |
| `-nr` (no repack) | ~41.2 GiB |
| `-nr` + MTP draft (Q8_0) | ~52 GiB |
| default + MTP draft (Q8_0) | exceeds 64 GiB — could not run under the test cap |

## Tests

- full `ctest` suite (61 tests): **61/61 pass** — including
  `test-generate-models` and `test-llama-context`, which now cover
  openpangu-v2 as a first-class arch (synthetic model fixtures, KV-cache
  cases) and round-trip its K-sink-prefix metadata through the model saver
- `test-backend-ops -b CPU -o SINKHORN -o HC_MIX -o DSA_SCORE -o TOP_K`:
  534/534 tests pass
- `test-chat`, `test-chat-template`, `test-chat-peg-parser`,
  `test-chat-auto-parser`: all pass

## Comparison with the original fork

Measured against the original
[mrexodia/llama.cpp-openPangu-2.0-Flash](https://github.com/mrexodia/llama.cpp-openPangu-2.0-Flash)
(HEAD `76c92350b`, llama.cpp base `6f4f53f2b` from 2026-06-29), same machine,
same model, same flags.

### Compatibility on this machine (AMX CPU)

| | original fork | this port (v0.7.0) |
|---|---|---|
| default settings | **aborts** — `GGML_ASSERT(*cur_backend_id != -1)` during `sched_reserve` (AMX weight repacking) | runs |
| `-nr` (weight repacking disabled) | runs | runs |

The original fork cannot be used with default settings on a CPU with AMX.
Its `llama-bench` has no option to disable repacking at all — the original
numbers below required a local source edit. This port fixes the underlying
AMX packing bug (the AMX packer silently corrupted batched/3D weights).

### llama-bench, `Q3_K_M`, `-t 16 -r 3` (2026-10-16)

Both builds with weight repacking disabled (`-nr`, the only common
runnable configuration on this machine):

| test | original fork | this port | change |
|------|--------------:|----------:|-------:|
| pp128 | 41.51 ± 2.21 | 60.47 ± 4.63 | **+46 %** |
| pp512 | 42.62 ± 0.83 | 64.75 ± 2.26 | **+52 %** |
| tg32  | 11.65 ± 0.19 | 11.52 ± 0.35 | ≈ |
| tg128 | 11.47 ± 0.21 | 11.82 ± 0.72 | ≈ |

This port with the default AMX weight repacking (original fork cannot run
this configuration):

| test | this port (default) |
|------|--------------------:|
| pp128 | 56.84 ± 1.32 |
| pp512 | 62.65 ± 0.54 |
| tg32  | 11.94 ± 0.71 |
| tg128 | 12.02 ± 0.30 |

Reading these numbers:

- Prefill is ~1.5× faster than the original fork, mostly from the v0.7.0
  base (3.5 months of upstream CPU optimizations). Generation is on par.
- On this CPU, AMX weight repacking is performance-neutral and costs
  ~16 GiB of extra RAM, so `-nr` is usually the better choice.
- The host is shared and measurements vary between runs (see the ±).

### Real inference (llama-cli end-to-end)

Actual generation with a real prompt (3,271 tokens of English text),
`llama-cli -c 8192 -n 128 -t 16 --no-warmup -st`, two runs each
(prompt eval / generation speed as reported by llama-cli):

| configuration | prompt eval | generation |
|---------------|------------:|-----------:|
| original fork, `-nr` | 29.7 / 28.9 t/s | 6.1 / 6.1 t/s |
| this port, `-nr` | 41.0 / 41.0 t/s | 6.0 / 6.0 t/s |
| this port, default (AMX repack) | 37.7 / 38.1 t/s | 5.6 / 5.5 t/s |

- real prompt processing is ~**+40 %** faster than the original fork
  (+29 % in the default AMX repack configuration)
- generation with a ~3K-token context is ~6 t/s in all configurations
  (the DSA indexer adds per-token work over the cached context, so this is
  lower than the tg128 llama-bench numbers on a fresh 128-token run)
- run-to-run variance on this host is small for these end-to-end runs

### MTP (self-speculative decoding)

Same prompt, `llama-cli -n 128 -nr`:

| | generation |
|---|---|
| original fork, MTP draft | 4.9 t/s |
| this port, MTP draft | 4.7 t/s |
| either fork, plain decoding (`llama-bench` tg128) | 11.5–12.0 t/s |

On CPU the MTP draft head is a net loss in both forks; it is included for
completeness and may pay off on GPUs where the draft forward pass is cheap.

## CPU optimization experiments(CPU 優化實驗記錄)

Upstream CPU-speedup candidates (open pull requests of llama.cpp) are
benchmarked one by one on the machine described above. Because this shared
host is noisy, each candidate is measured with an **alternating A/B
protocol**: two binaries built from the same source tree (baseline vs
baseline + candidate patch) are run interleaved in the same session
(`llama-bench -t 16 -r 3 -p 512 -n 128`, default settings, 3–8 rounds each);
the table reports the medians over all rounds. Every number is
**incremental**: each candidate is compared against the **previous merged
state**, not against the original port.

> Methodology fix (2026-10-16): a first attempt measured `-nr` via the
> `LLAMA_ARG_REPACK=0` env var. `llama-bench` ignores that variable (it has
> its own parser; only common-arg tools such as `llama-cli` /
> `llama-perplexity` honor it), so those runs were silently default-mode.
> The `-nr` entry for #27590 was re-measured with `llama-bench --repack 0`,
> the flag the tool actually supports.

Only candidates that win beyond the run-to-run noise are merged into the
patch (✅ 有幫助); candidates without a real gain are recorded here with
their data and are **not** merged (❌ 沒幫助).

| candidate | content | verdict | pp512 t/s (median) | tg128 t/s (median) |
|---|---|---:|---:|---:|
| upstream PR [#27024](https://github.com/ggml-org/llama.cpp/pull/27024) by [@jinzihao](https://github.com/jinzihao) | ggml-cpu/amx: fix the (dead) `block_q8_K` VNNI quantization and enable the VNNI path | ✅ 有幫助 — merged | 57.25 → 59.20 (**+3.4 %**) | 10.94 → 11.24 (**+2.7 %**) |
| upstream PR [#22525](https://github.com/ggml-org/llama.cpp/pull/22525) by [@HyeongiJeon](https://github.com/HyeongiJeon) | ggml-cpu: optimize `ggml_gemm_q4_K_8x8_q8_K` interleaving/staging for AVX-512 (and AVX2) | ✅ 有幫助(prefill)— merged | 55.78 → 57.42 (**+2.9 %**) | 10.70 → 10.87 (+1.5 %, neutral) |
| upstream PR [#19706](https://github.com/ggml-org/llama.cpp/pull/19706) by [@Manogna-Sree](https://github.com/Manogna-Sree) | Q6_K block interleaving for x86 SIMD (AVX-512/AVX2) | ❌ 沒幫助 — not merged | 58.16 → 58.34 (+0.3 %) | 11.06 → 11.07 (+0.1 %) |
| upstream PR [#27590](https://github.com/ggml-org/llama.cpp/pull/27590) by [@SongXiaoXi](https://github.com/SongXiaoXi) | ggml-cpu: add AVX-512/VNNI paths for Q5_K/Q6_K dot products | ✅ 有幫助(`-nr`)— merged | `-nr`: 65.91 → 66.35 (+0.7 %) | `-nr`: 11.16 → 11.32 (**+1.4 %**) |
| upstream PR [#18698](https://github.com/ggml-org/llama.cpp/pull/18698) by [@zzjianhui](https://github.com/zzjianhui) | ggml-cpu: repack weights in parallel (OpenMP, NUMA-local thread placement) | ❌ 沒幫助(推論退化)— not merged | 56.93 → 54.58 (**−4.1 %**) | 10.67 → 10.45 (**−2.1 %**) |
| draft PR [#27032](https://github.com/ggml-org/llama.cpp/pull/27032) by [@lexasub](https://github.com/lexasub) | CPU optimizations (GET_ROWS+ADD fusion, `get_rows` fast paths, tokenizer, KV-cell rework) — only the ggml-kernel subset is portable onto this tree | ❌ 沒幫助(不適用於本模型)— not merged | 56.64 → 56.88 (+0.4 %) | 10.82 → 10.73 (−0.8 %) |
| draft PR [#27396](https://github.com/ggml-org/llama.cpp/pull/27396) by [@lexasub](https://github.com/lexasub) | speculative draft-model prefill (zero-copy embedding, event-based sync) for EAGLE3/DFlash/GLM4-style draft heads | ❌ 沒幫助(不適用;未移植)— not merged | — | — |

Round-by-round for #27024 (candidate vs baseline, t/s):

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 57.66 vs 57.69 | 11.09 vs 10.57 |
| 2 | 59.20 vs 57.25 | 11.05 vs 10.94 |
| 3 | 58.66 vs 56.57 | 11.47 vs 11.27 |
| 4 | 62.13 vs 55.67 | 11.62 vs 10.83 |
| 5 | 61.76 vs 65.98 | 11.24 vs 12.01 |

The candidate won 4 of 5 pairwise rounds on both metrics; the single losing
round (r5) is a transient quiet window on the host (both absolute values
spike upward). Median deltas stay positive (+3.4 % / +2.7 %), so the change
is merged. All values t/s; measured 2026-10-16.

Round-by-round for #22525 (candidate vs baseline, t/s), default settings.
Note: `Q3_K_M` does contain 134 `Q4_K` tensors (the MoE expert weights),
so the Q4_K GEMM path this PR optimizes is actually exercised:

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 56.69 vs 57.18 | 10.97 vs 10.97 |
| 2 | 57.30 vs 57.15 | 10.88 vs 10.78 |
| 3 | 57.30 vs 55.90 | 10.30 vs 10.94 |
| 4 | 56.26 vs 55.66 | 10.85 vs 9.51 |
| 5 | 57.91 vs 55.07 | 10.55 vs 10.62 |
| 6 | 57.55 vs 56.81 | 10.60 vs 10.19 |
| 7 | 57.84 vs 55.52 | 11.04 vs 10.43 |
| 8 | 59.24 vs 55.06 | 10.97 vs 11.05 |

The candidate won 6 of 8 pairwise rounds on prefill (1 loss, 1 tie within
0.5 %); decode is neutral (4 W / 3 L / 1 T). The PR only changes the AVX-512
interleaving/staging of the Q4_K GEMM (the prefill path), so the measured
profile matches the expectation. Merged. Measured 2026-10-16.

Round-by-round for #19706 (candidate vs baseline, t/s), default settings:

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 58.42 vs 53.67 | 11.67 vs 11.45 |
| 2 | 59.46 vs 58.68 | 12.04 vs 10.84 |
| 3 | 54.57 vs 60.04 | 10.54 vs 11.82 |
| 4 | 62.32 vs 57.06 | 10.95 vs 11.16 |
| 5 | 57.66 vs 58.59 | 11.10 vs 10.86 |
| 6 | 57.26 vs 57.92 | 11.05 vs 11.17 |
| 7 | 59.71 vs 56.95 | 10.98 vs 10.96 |
| 8 | 58.25 vs 58.41 | 11.11 vs 10.83 |

**Verdict ❌ 沒幫助 (no measurable gain).** Medians differ by +0.3 %
(prefill) and +0.1 % (decode), with a 4 W / 3 L / 1 T split on both — pure
noise. The base `Q3_K_M` model contains only **one** single `Q6_K` tensor,
so a faster Q6_K kernel has almost no weight to act on. The PR is *not*
merged; the data is recorded here for the record. Measured 2026-10-16.

Round-by-round for #27590 (candidate vs baseline, t/s), `-nr` mode
(`llama-bench --repack 0`). The Q5_K/Q6_K dots this PR changes are used on
the plain CPU path selected by `-nr`; with default repacking those weights go
through the repack gemv/gemm kernels instead (default-mode incremental
measured ~neutral, within noise):

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 67.88 vs 67.80 | 11.17 vs 11.15 |
| 2 | 66.08 vs 66.46 | 11.46 vs 11.18 |
| 3 | 66.01 vs 65.34 | 11.32 vs 11.19 |
| 4 | 66.63 vs 65.36 | 11.33 vs 11.12 |

**Verdict ✅ 有幫助 (`-nr` 模式, +0.7 % prefill / +1.4 % decode medians;
decode won 4 of 4 rounds).** In this model the PR affects Q5_K (2 tensors,
the dense `ffn_down` of layers 0–1) and Q6_K (1 tensor — `output.weight`,
the 388 M-param head that is read on every token), so the consistent decode
win matches the expectation. One caveat: the upstream PR is *closed but never
merged* (only an automated AI-content flag, no review), so it received extra
local validation before merging:

- perplexity on a fixed corpus: 1.0354 → 1.0354 (identical)
- `test-backend-ops -b CPU -o MUL_MAT -p 'type=q5_K|type=q6_K'` passes

Merged. Re-measured 2026-10-16 with the correct `--repack 0` flag (see
methodology note above).

Round-by-round for #18698 (candidate vs baseline = current HEAD i.e. all
merged patches, t/s), default settings. This PR repacks the quantized
weights in parallel with OpenMP and pins each repack thread NUMA-local.
(Ported by hand: the year-old PR conflicts with the current tree and depends
on the never-merged PR #18239.)

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 54.24 vs 56.40 | 10.48 vs 10.35 |
| 2 | 55.50 vs 57.92 | 10.37 vs 10.67 |
| 3 | 54.58 vs 56.93 | 10.45 vs 10.87 |

**Verdict ❌ 沒幫助 (clear prefill regression, not merged).** Medians:
prefill −4.1 % (0 W / 3 L) and decode −2.1 % (1 W / 2 L); an earlier 5-round
block against the same effective baseline agreed on prefill (−2.7 %,
1 W / 4 L) with noisy decode. Side effect worth recording: the parallel
repack cuts model **load** wall time (load + tiny bench, warm page cache)
from 24 s (2/2 runs) to 10 s (2/2 runs) — but the inference phase itself
gets slower, so per the merge rule (real tok/s gains) the candidate is
**not** merged. Correctness: perplexity 1.0361 → 1.0361 (identical), i.e.
the parallel repack produces identical weights; the regression is presumably
a NUMA page-placement effect, not a data error. Measured 2026-10-16.

Round-by-round for draft #27032 (candidate vs baseline = current HEAD, t/s),
default settings. The draft bundles several optimizations (GET_ROWS+ADD
fusion, `get_rows` fast paths, tokenizer, KV-cell rework). The KV/batch and
tokenizer parts are either **not portable** (rooted in a pre-refactor
KV-cell design that conflicts with this tree) or not measurable with this
protocol; only the disjoint ggml CPU-kernel subset could be ported and
tested:

| round | pp512 | tg128 |
|---|---:|---:|
| 1 | 57.49 vs 56.64 | 10.73 vs 10.82 |
| 2 | 56.88 vs 58.68 | 10.85 vs 10.75 |
| 3 | 55.71 vs 56.50 | 10.35 vs 10.95 |

**Verdict ❌ 沒幫助 (not applicable to this model, not merged).** ≈±1 % on
both metrics, PPL identical (1.0361). The reason follows from the graph and
kernel dispatch: (1) the GET_ROWS+ADD fusion needs an ADD node immediately
after a GET_ROWS node — this model's graph has no such pattern; (2) the
optimized Q4_K dequant path is not used (`token_embd` is Q3_K); (3) the
remaining `get_rows` cache-hit path only helps repeated 1-row gathers, which
this workload barely has. Recorded for the record. Measured 2026-10-16.

Recorded verdict for draft #27396 (not ported, not measured): the draft
optimizes the *speculative draft-model prefill* path (zero-copy embedding,
event-based sync) for EAGLE3 / DFlash / GLM4-style draft heads, and it
touches core files (`llama-batch`, `llama-context`, `llama-graph`, ...) that
have diverged from its base — 7 of 17 files conflict and a faithful port
would require redesigning the speculative prefill plumbing. This CPU setup
does not use speculative decoding at all — the bundled MTP head measured
net-negative on CPU (see the inference section above) — so the draft has no
applicable surface here. Recorded 2026-10-16.

### Combined effect of the merged set

Interleaved A/B of the shipped tree (original port + all merged candidates)
against the original port, same session, 3 rounds each, medians:

| config | pp512 | tg128 |
|---|---:|---:|
| default, original port → shipped | 55.65 → 56.30 (**+1.2 %**, won 3/3) | 10.50 → 10.86 (**+3.4 %**, won 3/3) |
| `-nr`, original port → shipped | 60.96 → 64.87 (**+6.4 %**, won 3/3) | 10.20 → 10.26 (+0.6 %, noisy) |

The per-mechanism incremental numbers in the sections above are the
authoritative records; this table is the same data rolled up against the
original-port baseline in a single session. Note the separate, much larger
`-nr` vs default finding below.

### `-nr` vs default on this machine

Side observation from the re-anchoring session: on this AMX machine the
plain-CPU (`-nr`) path is clearly faster than the default repack path.
HEAD (all merged patches): pp512 56.93 → 66.35 (**+16.6 %**) and tg128
10.67 → 11.32 (**+6.1 %**) with `--repack 0` (3–4 interleaved rounds each,
2026-10-16). The repack kernels used by default have no AMX path, while the
plain Q4_K×Q8_K kernels use AMX (boosted further by #27024). On AMX-class
machines it is worth testing `-nr` for ~+15 % prefill.

## License

This project (the patch set, `patch.sh` and documentation) is licensed
under **GPL-3.0** — see [`LICENSE`](LICENSE). The patch is a derivative of
llama.cpp; the MIT-licensed portions remain under their original licenses,
with the references listed in the `LICENSE` header and repeated here:

- [llama.cpp](https://github.com/ggml-org/llama.cpp) — MIT — © ggml-org
  contributors (base commit `620d2225cc436ab0b001e3200e590e3b286ef9ab`)
- [mrexodia/llama.cpp-openPangu-2.0-Flash](https://github.com/mrexodia/llama.cpp-openPangu-2.0-Flash)
  — MIT — original openPangu-2.0-Flash port
- upstream PR [#27024](https://github.com/ggml-org/llama.cpp/pull/27024)
  by [@jinzihao](https://github.com/jinzihao) — MIT (merged)
- upstream PR [#22525](https://github.com/ggml-org/llama.cpp/pull/22525)
  by [@HyeongiJeon](https://github.com/HyeongiJeon) — MIT (merged)
- upstream PR [#27590](https://github.com/ggml-org/llama.cpp/pull/27590)
  by [@SongXiaoXi](https://github.com/SongXiaoXi) — MIT (merged; closed
  upstream unmerged, verified locally)
- [ggml](https://github.com/ggml-org/ggml) — MIT (bundled with llama.cpp)