KV cache quantization: fp8 (KV8) + 4-bit TurboQuant (KV_TQ) on CPU, CUDA, and Metal#399
KV cache quantization: fp8 (KV8) + 4-bit TurboQuant (KV_TQ) on CPU, CUDA, and Metal#399NeuralNotwerk wants to merge 3 commits into
Conversation
dc2bf2c to
613236f
Compare
|
Reviewed against post-v1.0.0 How the ragged branch interacts with the fp8 device shadow (does a ragged gather read the shadow rows, or does it re-upload?) is a semantic call I'm not comfortable resolving for you, and I have no CUDA hardware here to validate it. Could you rebase the series onto current |
|
Rebased onto current The ragged Γ fp8-shadow call, made explicit in the code (comment at the gate in Also folded in during the rebase: the batch-absorb gate keeps its |
b02bc92 to
606fe19
Compare
|
Heads-up: |
Upstream PR JustVugg#399 (KV8 fp8 / TQ4 quantized latent KV) leaves Lc/Rc NULL when a quantized tier is active β the mirror sync would deref NULL. Guard on the arrays themselves (env-independent), falling back to the CPU attention path; an fp8-aware VK mirror (upload Lc8+scale, decode e4m3 in the shader, 4x less mirror traffic) is the follow-up once JustVugg#399 merges.
CUDA validation on fleet hardware (consolidated)Ran the rebased series on our fleet box β 4Γ RTX 5090 (sm_120) + RTX 4090 (sm_89), EPYC 7532, 503 GB RAM, CUDA 12.8.1. (Context for the sparse CUDA numbers lately: this box pulls ~4.5 kW and North Carolina is mid-heat-wave, so it only comes up in cool windows.) Build & tests: real Correctness, live on GLM-5.2 744B ( Performance β measured at the production operating point (serve mode over HTTP, exact prod env: On the #391 heads-up ( |
|
Tested this branch on an M5 Pro, 64 GB, macOS 26.5.2, GLM-5.2 REAP-504B int4 container, expert-pruned to 168 per layer, streamed from disk. Two findings, one of which you probably want before merge.
Caveat on both: the CLI prompt is untemplated and the model degenerates into a token loop after about 30 tokens in every arm, merge-base included. The degeneration is deterministic, so the first-token divergence and the relative throughput stand, but the absolute tok/s is not a chat workload. I can rerun with different knobs or capture fuller logs if that helps narrow down the qmode question. |
Review fixes for JustVugg#399 (michael-denyer, M5 Pro): (1) f32 regression: both KV tiers OFF diverged from merge-base at the first decode token. Root cause: coli_metal_init compiled the WHOLE MTLLibrary with MTLMathModeSafe (added for the fp8 RNE encoder), silently recompiling every f32 kernel fast-math-off. A byte-identical A/B proved mm_gemv alone drifts ~4e-6, compounding to flip greedy argmax at token 1. Fix: two libraries β libFast (fast-math, all f32/MoE + quantized consumers; restores merge-base parity) and libSafe (only a_fp8enc/a_tq_enc/a_tq_enc1). fp8 stays byte-exact. (2) TQ4 ~2x slower than f32: it re-dequantized the ENTIRE cache to f32 staging every layer every token, then ran plain f32 score/clat. codec-1 (rotated int4) fix uses the Hadamard orthogonality identity q.x_hat == rotate(q).c and sum_t w_t x_hat_t == unrotate(sum_t w_t c_t): rotate the query once per head (a_tq_qrot), dot packed nibbles through the codebook (a_score_tq), accumulate (a_clat_tq), unrotate once (a_tq_unrot); parallel producer a_tq_enc1. codec-0 (PolarQuant) keeps the a_tq_deq staging path. Native vs staging: 1.4-1.9x faster, gap widens with context, equivalence ~5e-7. Tests: test_kv_tq.c gains the score/context orthogonality identities + a full MLA-consumer native-vs-dequant check; test_backend_metal.mm gains a native-vs-staging equivalence + speedup benchmark. make metal-test + test-c green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ready for review β validated on Metal, CPU, and CUDABoth review findings are root-caused and fixed, and the KV-quant stack is now hardware-validated across all three backends (incl. an end-to-end run on GLM-5.2 744B). @michael-denyer's findings β both fixed
Validation
Also in this push
RemainingOne open item: the rebase onto the |
6c238fa to
7d62599
Compare
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Rebased onto current Rebased tree is green locally: |
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7d62599 to
9b7c577
Compare
|
Rebase needed: #298 just merged into |
Upstream PR JustVugg#399 (KV8 fp8 / TQ4 quantized latent KV) leaves Lc/Rc NULL when a quantized tier is active β the mirror sync would deref NULL. Guard on the arrays themselves (env-independent), falling back to the CPU attention path; an fp8-aware VK mirror (upload Lc8+scale, decode e4m3 in the shader, 4x less mirror traffic) is the follow-up once JustVugg#399 merges.
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9b7c577 to
c32e38f
Compare
|
Rebased onto
Validated on hardware (5ΓRTX 5090 + RTX 4090,
And this closes @michael-denyer's original findings. The "TQ4 slower than f32" one is fixed β fully-resident 744B, CUDA decode (MTP off):
TQ4 is now at parity (was ~2Γ slower) at ~28% less KV memory β the native rotated-int4 consumer landed, so it no longer re-dequantizes the cache to f32 every step. I ran the full FP32/FP8/TQ4 Γ MTP matrix across CUDA / CPU-x86 / Metal / CPU-ARM (resident and disk-streaming); happy to drop the whole table here if it's useful for the v1.0.1 notes. One additive extra on the branch: |
|
To merge this I need validation data I can't produce myself (no such GPU here). The bar every backend holds: (1) correctness first β a teacher-forcing token-exact check on a tiny model ( For KV8 / KV_TQ quantization: this changes numerics, so I need the quality picture, not just speed β perplexity or a token-exact-within-tolerance check vs full-precision KV on a tiny model, per backend (CPU/CUDA/Metal) you touched. That''s the gate for a precision-changing feature. Thanks @NeuralNotwerk. |
Upstream PR JustVugg#399 (KV8 fp8 / TQ4 quantized latent KV) leaves Lc/Rc NULL when a quantized tier is active β the mirror sync would deref NULL. Guard on the arrays themselves (env-independent), falling back to the CPU attention path; an fp8-aware VK mirror (upload Lc8+scale, decode e4m3 in the shader, 4x less mirror traffic) is the follow-up once JustVugg#399 merges.
|
Status: this conflicts with On the substance: KV quantization is a real lever here and I'd like it, but the shape of the PR is what's slowing it down. It's ~3,400 lines across 20 files covering two schemes (fp8 KV8 and 4-bit TurboQuant) on three backends (CPU, CUDA, Metal). I can validate the CPU path; I have neither NVIDIA nor Apple hardware, so the other two thirds rest entirely on your measurements. That's a lot to accept in one merge. What would unblock it: land the CPU path first, on its own. It's the one I can verify end to end against the oracle, and once the format and the KV plumbing are settled and merged, the CUDA and Metal kernels become much smaller, more focused follow-ups β each with a hardware owner who can gate it (this project's rule for GPU changes is a token-identity check from someone with the silicon). Also worth stating explicitly in the PR: what happens to KV persistence ( Tell me if splitting is workable and I'll prioritise the CPU half. |
Upstream PR JustVugg#399 (KV8 fp8 / TQ4 quantized latent KV) leaves Lc/Rc NULL when a quantized tier is active β the mirror sync would deref NULL. Guard on the arrays themselves (env-independent), falling back to the CPU attention path; an fp8-aware VK mirror (upload Lc8+scale, decode e4m3 in the shader, 4x less mirror traffic) is the follow-up once JustVugg#399 merges.
|
Splitting is workable β I'll carve the CPU path out as its own PR on current Teacher-forcing token-exact vs the transformers oracle
Greedy generation (decode path β this is where the native CUDA/Metal quantized-KV kernels engage):
The TQ4 generated sequence is byte-identical CUDA vs Metal vs CPU. Reading this honestly:
KV persistence across mode changesAlready handled the way you describe, and covered by The test covers v1βv2/v3 upgrade (old file untouched until the first save rewrites it), v2/v3-under-f32 reject, TQ codec/bits mismatch reject, and the append-side self-heal. Perf reference (already posted above, environment for the record)Resident 744B, driver 610.43.02, CUDA 12.8.1 runtime, 4ΓRTX 5090 + RTX 4090 ( Next from me: the CPU-only PR (KV8 + KV_TQ consumers, |
|
Split done β the CPU path is now its own PR: #553 (1,282 lines / 12 files, no backend code), rebased on today's Converting this PR to draft: it stays as the reference for the full three-backend implementation, and once #553 lands I'll rebase the CUDA and Metal kernels out of it as the two focused follow-ups (each with its hardware validation + token-identity data β the CUDA half is already validated on 4Γ5090+4090 at f32-parity decode on the 744B). |
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c32e38f to
23b7628
Compare
|
Rebased onto current Four files conflicted. Two were mechanical, three were semantic and worth review: 1. DSA gather β dev's 2. 3. HIP portability β this one is a real behavior change. 4. Validation on the rebased treeRun here on macOS 26.5.1 / Apple M4 / 32 GB:
What this does not re-validateThe fleet-box CUDA numbers I posted on the 20th were measured on the pre-split tree, and the DSA-gather routing and the reserve accounting both changed in this rebase. Those need a re-run on |
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
23b7628 to
85852e2
Compare
|
Rebased onto current The rebaseOne conflict, in Also folded in from the #553 review pass (cherry-picked, so it collapses cleanly when #553 lands):
Token identity across four backends, on this treeThe claim this PR has been making is that the quantized flips are deterministic quantization loss rather than backend divergence. That now holds across two ISAs and two GPU vendors, all re-measured on
Identical positions, identical tokens, four backends. The AMD column is new β these kernels had never been run on ROCm. Other backends on the rebased tree:
What this still does not claimNo perf numbers are carried forward. The fleet-box CUDA throughput figures I posted on the 20th were measured pre-split, and this rebase changed both the DSA-gather routing and the One observation for whoever owns the AMD path: on this box the tiny-model teacher-forcing rate went from ~3230 pos/s to ~159 pos/s after #599 enabled rocWMMA. It's a 5-layer random-weight model where launch overhead dominates, so it may well be meaningless β but it's a 20Γ delta on |
Upstream PR JustVugg#399 (KV8 fp8 / TQ4 quantized latent KV) leaves Lc/Rc NULL when a quantized tier is active β the mirror sync would deref NULL. Guard on the arrays themselves (env-independent), falling back to the CPU attention path; an fp8-aware VK mirror (upload Lc8+scale, decode e4m3 in the shader, 4x less mirror traffic) is the follow-up once JustVugg#399 merges.
β¦β rebased onto colibri.c Rebases the JustVugg#399 series onto current dev (colibri.c + extracted headers, post-JustVugg#391), which also picks up JustVugg#445's CUDA_RELEASE_HOST pin-budget fix for free. The KV-quant work is additive β dev had no KV8/TQ code β so the split just relocated scaffolding: * colibri.c β KV8/TQ globals + KVState fp8/packed byte caches, kv_alloc, the attention consumers (CPU rotated-int4 orthogonality path; Metal/CUDA native fused kernels dispatch), env parsing, the pin_load KV8-shadow VRAM projection (merged with JustVugg#445's additive prefix budget). * kv_fp8.h / kv_tq.h β the fp8 e4m3 and rotated-int4/PolarQuant codecs (new headers). * kv_persist.h β .coli_kv disk format v2 (fp8) / v3 (TQ): magic-tagged, on-load format detection, v1->v2/v3 in-RAM upgrade + self-heal, fsync durability. * backend_metal.mm β two-library split (fixes the f32 fast-math regression: fast-math for f32/consumer kernels, safe-math only for the RNE encoders) + native codec-1 TQ4 fused attention (Hadamard-orthogonality: rotate the query once, dot packed nibbles, unrotate the context; no f32 restage). * backend_cuda.cu/.h β native codec-1 TQ4 kernel (attention_absorb_kernel_tq) + host entry. * openai_server.py β dispatcher skips unrecognized engine telemetry frames instead of tearing down (unified single/multi-slot interface, version-skew tolerant). Note: the KV-tier flag definitions (g_kv8/g_tq/g_tq_bits/g_tq_codec/g_kv_shadow) moved above the kv_persist.h include so the disk format can see them. Validated on this rebase: `make colibri` clean; `make test-c` green (incl. kv_fp8, kv_tq identities + MLA-consumer equivalence, and kv_disk v1/v2/v3 round-trip + upgrade + reject + self-heal); `make metal-test` green (f32 byte-exact, native TQ4 1.3-1.5x faster than staging, layer decode ok). CUDA compiles clean on the fleet box (sm_89+sm_120, cuda-test incl. attention_absorb_tq) and ran coherent end-to-end on GLM-5.2 744B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add opt-in (PROF=1) instrumentation for expert-weight disk I/O rates, which were previously reported only as seconds, never as throughput: - pin_load: '[PROF] pin load: X GB read in Ys = Z GB/s aggregate | N experts @ M experts/s' β the initial hot-expert load rate off disk at startup. Gated on getenv(PROF) directly since g_prof is parsed after pin_load runs. - prof_report: '[PROF] disk stream: E experts/s | A GB/s aggregate over the phase (Cx avg read concurrency, P GB/s per loader thread)' β the live streaming rate during prefill/decode. Aggregate = bytes/wall; read-service seconds sum across parallel loaders, so io_svc/wall is the concurrency and bytes/io_svc the per-thread rate (aggregate = per-thread x concurrency). Additive only; with PROF unset every mode's output stays byte-identical. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two no-silent-error gaps in the KV_TQ env handling, both found in review. 1. Power-of-two guard. Both codecs rotate through a radix-2 FWHT, and coli_kvq_quant_row returns an inert radius 0 for any other width. On a model whose kv_lora/qk_rope are not powers of two, that meant EVERY latent row quantized to zero and the engine generated confident garbage with no diagnostic -- the same silent-misread class the .coli_kv tier magic exists to prevent, just reached through model shape instead of file format. Now checked once after model_init and refused with the shapes named and KV8 (no width constraint) suggested. GLM-5.2 is 512/64, so nothing that works today changes; this only fires where the codec cannot represent the model. test_kv_tq pins the underlying behavior for all four entry points (both codecs, both dispatch paths) so the guard cannot become quietly harmless. 2. KV_TQ=1 clamped UP to 2, handing "just turn it on" the most aggressive, lowest-quality tier. It now lands on the recommended 4-bit tier and says so. >6 still clamps down to the grid. Unchanged: default (no KV env) is 32/32 token-exact, KV8 30/32, KV_TQ=4 23/32 on the tiny oracle -- identical to the pre-change numbers.
85852e2 to
d800ace
Compare
Summary
Quantized KV cache for the MLA latent across all three backends, as opt-in tiers:
KV8=1β fp8 e4m3 + per-row scale (~3.9Γ less KV RAM than f32), CPU + CUDA + Metal.KV_TQ=4β 4-bit KV (~7.8Γ less): rotated-int4 + Lloyd-Max codebook by default (full reconstruction, so it corrects the MLA key and value), or PolarQuant (arXiv 2502.02617,KV_TQ_POLAR=1, variable 2-6 bit). CPU + Metal; under CUDA the quantized paths self-disable (guarded, falls back to CPU attention).COLI_METAL=0to force CPU) β Apple unified memory has no separate VRAM pool to overflow, so the CUDA-style opt-in gate doesn't apply.Supersedes #299/#300, which I withdrew for fleet soak-testing: the VRAM-budget interaction I flagged there (fp8 shadow vs
CUDA_EXPERT_GB=auto) is fixed in this series ("KV8 shadow-aware auto VRAM budget" + "KV_SHADOW auto keyed on ragged decode"), and the stack has since gathered the review fixes, vectorized fp8 kernels (15.8Γ prefill, 4-6Γ decode vs scalar), the 4-bit tier, and a second architecture (Metal) worth of validation.Commits (bisectable, each builds)
.coli_kvv2 β encoder bit-exact with the engine's consumers (RNE, per-row amax/448 scale); disk format v2 with quantize-on-upgrade from v1, reject-on-mismatch, self-heal.kv_tq.hcodecs (randomized-Hadamard rotation + recursive polar / rotated-int4 + Lloyd codebook), MSL kernelsa_fp8enc/a_score8/a_clat8/a_tq_enc/a_tq_deq, 3-wayqmodein the fused layer decode,.coli_kvv3 (COLIKV3,h[7]=codec<<8|bits), Metal opt-out default, tests.Why rotated-int4 for the 4-bit tier
MLA's latent is both key and value, so score-only fixes (QJL-style) leave the value error uncorrected. Full reconstruction through a randomized-Hadamard rotation + fixed 16-level Lloyd-Max codebook (N(0,1)-optimal, scaled by radius/βn) measures ~0.096 rel-L2 at 4 bits vs ~0.147 for recursive-polar β and the rotation makes the radius invariant, so one per-row scale survives. 4-bit KV is a quality trade (tiny-oracle: f32 32/32, KV8 30/32, TQ4-int4 23/32) β that's the physics of 4 bits against MLA, not codec slack; KV8 is the lossless-feeling tier, TQ4 the memory-constrained one.
Validation
make test-cgreen (new suites:test_kv_fp8exhaustive e4m3 roundtrip + RNE;test_kv_tqrotation self-inverse, roundtrip, distortion, inert rows;test_kv_diskv1/v2/v3 round-trip + upgrade/reject/self-heal;test_kv_alloc).make metal-testgreen β fp8 GPU encoder byte-exact vscoli_fp8_enc; TQ GPUβCPU roundtrip ~3e-8; fused attention parity vs CPU ~5e-6 for fp8/int4/polar; full-layer residual parity for f32/KV8/TQ (~4-5e-6).DRAFT=2decodes at 0.30 tok/s with 100% draft acceptance on a counting prompt (MTP head repaired per tools: repair int4-converted MTP heads in place; warn on --mtp --ebits <8Β #397 β the two features compose).!g_tqguards on the absorb gates β no TQ CUDA kernels exist yet, phase 2). Not re-compiled on this macOS machine; last CUDA build/test was the fleet run.Notes for review
KV8/KV_TQunset β byte-identical behavior; the quantized byte-caches are NULL and every consumer branches ong_kv8||g_tq).COLI_METAL=0) and non-Metal builds behave exactly as the CPU tier.π€ Generated with Claude Code