CUDA Optimization Step Documents — Master Index

This directory is the expansion layer of docs/CUDA_OPTIMIZATION.md: it writes every step of the twelve sessions, the two Phase-8 batch records (78–79), and ~60 optimization levers from 2026-08-29 → 2026-09-09 as a standalone, readable document — background, the GPU principle (arguing with arithmetic), real code before/after, verification methods, results, and lessons.

Reading guidance: only care about the current state → read docs/CUDA_OPTIMIZATION.md §1 (current status) and the doc 77 methodology at the end of this directory; want to understand why a mechanism is the way it is → find that step in the table below; want to follow the whole campaign → read in number order — the story is continuous.

Status legend: 🟢 LANDED · 🔵 MEAS-ONLY · 🔴 REVERTED (with the veto mechanism) · ⚪ CLOSED (no code, or analytical conclusions)

The writing contract is in STYLE.md.


Part I · Foundations (Era A: Phase 7/8, 2026-08-29 → 08-30)

#doctopicstatus
01phase7-cuda-backendCUDA backend: raw-FFI device layer + graph backend (the 30.7 tok/s starting point)🟢
02wmma-f16-prefill-gemm-8mwmma f16 tiled GEMM: 30.7→1204 tok/s (39×)🟢
03fa-tiled-prefill-attention-8nFA-style tiled prefill attention: 176→8.5 ms/layer (20×)🟢
04decode-start-stall-8odecode start stall: killing the 635 ms heavyweight clone (724→35 ms first step)🟢
05persistent-f16-cache-8president f16 weight cache + dequant folded into the GEMM (→~1400 tok/s)🟢
06decode-mmvq-8edecode MMVQ (dp4a × q8_0): +37% on q4_K🟢
78phase8-correctness-batchthe 8a review batch (11 fixes) + the F32-matmul latent bug + 8h①/8i tests🟢
79phase8-coverage-batchKV f16, shaped Q8_0 GEMM, split-K attention, Q5_K/Q5_1/Q5_0 kernels, the 8l llama baseline🟢/🔵

Part II · The R-and-P5 sessions (Era B: R/P5, 2026-08-31 → 09-01)

#doctopicstatus
07r3-small-model-overheadsmall-model per-token overhead: prefill single-split🟢
08r1-int8-mmq-prefill-gemmint8 MMQ prefill GEMM (opt-in): the parity-first strategy🟢
09r2-mmvq-weight-streamingMMVQ weight-streaming rework: tg128 +6.9%🟢
10r4-split-attention-dim-parallelsplit-attention dim-parallel rewrite: the bulk of the @2K gap🟢
11p5-gemm-tiles-fa-rewriteP5: TM=128 big tiles + FA rewrite (2.37×→1.43×)🟢

Part III · The q4_K campaign (Era C: r5–r37, 2026-08-31 → 09-05)

#doctopicstatus
12r5-r6-rerank-rewrite-specre-ranking + the structural rewrite spec⚪
13r7-r8-raw-byte-kernelraw-byte kernel + wide tile + FA probe🟢
14r9-llama-mmq-referencellama.cpp MMQ reference decode; the shape axis closed⚪
15r10-r11-inner-loop-portreference inner-loop decomposition port; ILP verification🟢
16r12-warp-tile-ldmatrix16-chain warp tile + ldmatrix🟢
17staging-shape-familythe x-tile / j-tile / cp.async-db staging shape family⚪
18r13-counter-forensicscounter forensics vs llama.cpp⚪
19r14-b-fragments-ldmatrixldmatrix B fragments + widened scale reads🟢
20r15-f32-acc-mma-rank1f32-accumulate mma probe + rank-1 term2 rescale🟢
21r16-narrow-kernel-rank1-foldthe narrow kernel gains the rank-1 fold🟢
22r17-wide-warp-remapwide warp remap 32od×64tok🔴
23r18-load-time-b-preexpansionload-time B pre-expansion (W_exp's debut)🔴
24r19-weight-l2-residencyweight L2 residency🔴
25r20-split-phase-a-stagingsplit-phase A staging🟢
26r21-coalesced-block-linear-ablock-linear coalesced A staging🔴
27r22-qa8-xor-swizzleqa8 XOR swizzle (the d/ssum fold reverted separately)🟢
28r23-f16-wall-decompositionf16-path wall decomposition + FA_TKV lift🔴
29r24-scheduling-ladderthe scheduling-structure ladder (the +1.5% bar calibrated)🔴
30r25-sass-opcode-censusthe SASS opcode census; the unroll wall's inertia⚪
31r28-nb-kernel-2blocksthe Direction-A raw-nibble NB kernel, 2 blocks/SM🟢
32r29-nb-kd-loop-unrollthe NB kd-loop unroll🟢
33r30-swar-unpackSWAR unpack: the compiler already did it⚪
34r31-qmajor-sda-repackthe q-major sda scale-read rearrangement🟢
35r32-finite-lever-sweepthe finite-lever sweep: both regions bounded⚪
36r33-hybrid-inner-loopthe hybrid inner-loop port: falsified by SASS identity🔴
37r34-quantize-transpose-prepassthe quantize-transpose prepass (+9.72% of layout-transform locality)🟢
38r35-scale-predecodescale pre-decode🔴
39r36-a-frag-wavefrontA-fragment wavefront economics: H1 falsified⚪
40r37-post-parity-attributionpost-parity whole-prefill attribution⚪

Part IV · q6_K-FA and the promotion (Era D: r38–r60, 2026-09-05 → 09-06)

#doctopicstatus
41r38-q6k-bt-rawbyte-mmathe q6_K BT-style raw-byte mma kernel (+2.9%)🟢
42r39-q6k-kdr2-double-bufferq6_K KDR=2 double buffer (+13.3%)🟢
43r40-third-resident-blockthe launch_bounds(256,3) third resident block (+13.0%)🟢
44r41-q6k-bexpand-uint4q6_K B-expand uint4 widen (+30.7%)🟢
45r42-stage-wide-dsc-readstage-wide dsc scale reads🔴
46r43-pc-sampling-attributionPC-sampling attribution; the pre-expand-B parity FAIL⚪
47r44-wexp-stride-mismatchthe W_exp stride-mismatch root cause; the fix wall-neutral🔴
48r45-cpasync-q6k-a-stagingcp.async q6_K A-side staging🔴
49r46-fap1-fa-auditFAP1: the FA audit + occupancy/conflict levers (−11% kernel but wall-neutral)🔴
50r47-converged-wall-decompositionthe converged-regime wall decomposition⚪
51r48-fap2-register-softmaxFAP2: register-resident softmax (FA 2.43×, prefill +5.6%)🟢
52r49-a-quantize-shared-dedupthe A-quantize prepass's shared-A dedup🟢
53r50-fa-tkv-16FA_TKV 32→16🔴
54r51-producer-fused-a-quantizeproducer-fused A quantize (mode 1)🟢
55r52-skip-write-mode2skip-write mode 2 (MINFER_MMQ_A_FUSE=2)🟢
56r53-q6k-wexp-cpasync-bundlethe q6_K bundle: W_exp + cp.async B staging (prefill 1.05×)🟢
57r54-q6k-exp-optoutthe MINFER_MMQ_Q6K_EXP opt-out (−5.04% for 1.52 GB back)🟢
58r55-swiglu-roofline-prefill-graphthe swiglu roofline + prefill CUDA-Graph (both recorded on the books and skipped)⚪
59r56-q6k-a-cpasync-wdscthe q6_K A-side bundle: A cp.async + the W_dsc plane🟢
60r57-fa-kv-staging-dbFA KV staging double buffer🔴
61r58-q4k-bt-cpasync-transplantthe q4_K BT spec + cp.async-db2 transplant (−12.6%, the pipeline value formula)🔴
62r59-q4k-wdsc-planethe q4_K W_dsc plane + riders🟢
63r59b-clean-remeasurethe clean re-measurement + the baseline-pollution correction⚪
64r60-promotion-default-onthe promotion: the verified gate set flipped default-on (the 1.080× path)🟢

Part V · The decode campaign (§2D: D1–D4-4, 2026-09-07 → 09-09)

#doctopicstatus
65d1-decode-attributionD1 attribution: the split-attention staging depth is the only kernel that grows with KV⚪
66d2-kv-register-stagingD2: explicit K+V register staging (+2.0% @1641) + two negative results🟢
67d3-14b-attribution-bitwise-mmvqD3-1 14B attribution + the D3b bitwise MMVQ trio (1a/1b/1c)🟢/🔴
68d3a-fattn-rewrite-rpwD3a: the 4-warp fattn rewrite reverted (rpw pathology) + the tolerance gate package calibrated🔴
69d3-4-hybrid-rpw-dispatchD3-4: the hybrid rpw dual-kernel dispatch landed; the L2 prefetch reverted🟢
70d3-5-fused-producer-a-quantizeD3-5: fused-producer decode A quantize (quantize launches −78%)🟢
71d3-6-gqa-batching-revertedD3-6: GQA batching — all gates green, still reverted; the 5× L2 re-read was not the residual🔴
72d3-7-attnv-mmvq-rmsD3-7: attn_v MMVQ routing + the rms wide-block/positions memo🟢
73d3-8-fusedqkv-portD3-8: FusedQKV ported to CUDA (both layer classes covered, short KV breaks through)🟢
74d4-2-b0-correctness-fixD4-2: the B0 latent correctness fix (7B dropped 13.5% of down-proj) + all bitwise axes closed🟢
75d4-3-attention-attempt2-artifactD4-3: attention attempt 2 NO-GO + the llama-bench artifact correction🔴
76d4-4-dpl-q6k-finalD4-4: dpl dense split-plane q6_K (+5.5/+4.3%, +7.7/+8.1%); PDL/fused-FFN closed🟢
80d5-0-cost-modelD5-0: the speculative-decoding gate — measured costs + acceptance p≈0.68–0.70; conditional go at d=2, gate = nt=3 verify amortization ≥ 2.5×📏
81d5-1a-verify-gate-measuredD5-1a: the gate measured end-to-end (specverify instrument) — C_T(3)=106 ms, per-token amortization 0.52× vs ≥2.5× required; nt=2–8 batched path costs a flat ~35 ms/token (no regime anywhere), real tile step only at M≥16 → D5 CLOSED by the pre-registered stop rule; external check: llama-cli -md (same pair) lands at 0.99–1.00×🔴
82small-m-multi-token-mmvqsmall-M dispatch fix: multi-token MMVQ + token-looped legacy kernels — 7B nt=3 105.9→29.4 ms (3.60×), nt=8 5.75×, marginal 34.4→4.3 ms/token; bitwise batched-vs-serial on all 8 quants; pre-registered 2.5× bar missed at 1.87× (cost-model error recorded); D5 verdict unchanged🟢

Part V-B · D5-R — speculative decoding reopened and closed (2026-09-12)

The doc 81 §4.3 errata voided the original closure's external anchor, doc 82 made the verify amortization real (2.14× at nt=3), and the plan was rewritten (SPECULATIVE-DECODING-PLAN.md) with the old plan kept as an appendix. Six records:

#docwhatverdict
83d5-r-stage1-spec-loopthe greedy d=2 loop (--spec-draft): second GraphCache, lazy accept loop (unit-tested), namespaced weight registries + nb_bt_only global-mix fix — the three single-model assumptions a second model breaks; 14B d=2 = 1.34×/1.58×🟢
84d5-r-stage2-dual-engine-batterysame-window dual-engine protocol (3 reps × prose/code × 4 cells): minfer 1.33×/1.59× vs llama 1.64×/2.08× — the whole gap = verify row marginal (8.8 vs 2.5 ms/row)🟢
85d5-r-stage3-verify-marginal-ledgernsys per-kernel ledger: nt=3 marginal 17.6 ms = attention nt 2–63 hole 9.0 (legacy per-(token,head) kernel vs the 0.8 ms split path) + matmul 8.1 + elt 1.9 + idle 0.7; nt=9 = dispatch cliff onto padded GEMM📏
86d5-r-stage4a-attention-verify-shapesone gate: fa_prefill nt≥64 → nt≥2 — C_T(3) 56.9→48.8, C_T(9) 101.3→86.4; e2e 1.42×/1.68× (code ≥ llama's same-window 1.64×); ledger projection validated ~5%🟢
87d5-r-stage4b-multi-mmvq-nt16-closedmulti-MMVQ nt 9–16: groups-of-8 = parity (weights re-streamed per group), acc[16] = register spill (111 ms) → doc-82 GEMM boundary stands; d=8 retired (0.71× prose projected, 0.63× measured in doc 88)🔴
88d5-r-stage5-final-batteryfinal battery: minfer d=2 1.42×/1.68× (35.7/42.5 tok/s) = 95%/88% of llama's absolute speed; capture prize verified already banked (R3-B); D5-R closes🟢
89d5-r-row-marginal-localizationthe absolute-gap leader localized without ncu: cold-L2 real-kernel bench + chain nsys + ablation — q4_K 2.4 / q6_K 1.0 / norm-quant 0.7 ms/row; ~half the matmul term = block-per-row activation re-read; fix menu priced (R-rows-per-block, small-M mma, chain hygiene)📏
90d5-r-rrows-per-block-closedmenu item 1 implemented → measured → reverted: ~0 at d=2 (chain keeps act rows L2-hot; block-parallel latency hiding dominates utilization); nt≥6 flatten recorded; small-M mma re-confirmed as the only lever of size🔴
91mma-path-block-starvationBT GEMM already mma.m16n8k32; small-M floor root-caused to block starvation (ntb=1 → 40 blocks); conditional double-buffer shipped (bitwise-safe, prefill guarded); K-split designed as the fix that revives d=8🔬
92ksplit-shipped-flip-resolved-noK-split (grid.z + deterministic reduce) shipped for both BT kernels behind the gate; C_T(9) 86.4→72.9 but the ≤55 flip condition failed — multi-MMVQ stays production; residual = per-tile staging serialization; nt 9..64 auto-ksplit → §3b: enabled on the default path by user decision (default C_T(9) 73.0; d=8 still acceptance-bound)✅
93draft-quant-and-greedy-identitydraft-quant swap is a mixed knob (±3 pts acceptance, opposite signs per cell); greedy identity test FAILS — spec ≠ sequential, flips traced to batched verify attention/softmax; nt-invariance campaign proposed with the identity test as acceptance criterion🔬
94greedy-identity-and-d8-crossinggreedy identity achieved (spec = sequential byte-for-byte; attention nt-invariance + penalty-window cap); d=8 crosses on code with q4_k_m (46.6 tok/s, 96% of llama); prose stays d=2✅
95adaptive-draft-depthadaptive per-round draft depth (beta acceptance + min-window costs + 10% hysteresis + optimism for unseen depths); identity boundary pinned — verify nt ≤ 8 bitwise (multi-MMVQ), nt=9 BT lm_head tolerance-class → adaptive capped at d=7; all four gates pass; adaptive BEATS the best static on both code cells (46.5/48.4 vs 43.9/46.6 tok/s) — the buggy static sweep had never measured d=3..7✅
96nt9-profile-phase0nt=9 verify profiled (stop-gate measured): BT-MMQ = 84% of GPU time, attention ~1%; ncu: both BT kernels at ~20% of both roofs, smem scoreboard stalls = 40–59% of warp cycles → doc 92's staging serialization confirmed dominant; gate verdict PROCEED; cp.async double-buffer staged as the bitwise-preserving Phase-1 lever (narrow EV: prefill lever / identity-relaxed d=8, not spec throughput) — Phase 1 re-priced separately, below 战役 97✅ P0
97spec-conversation-serverspeculative decoding in --cnv and serve (Engine trait hooks + SpecAwareEngine + sibling spec loops mirroring the plain decode token-for-token); server position/termination contract (seed carry, mid-batch stop/EOG ends the turn); pre-existing plain-server bug fixed: cross-request slot GraphCache reuse leaked stale KV (identical requests hid it) → per-request cache reset✅
98bt-cpasync-null96 Phase 1 measured: cp.async double-buffered staging brought to the q4_K BT kernel (full r56 treatment, dbuf extended to ksplit) → NULL on GB10 (kernel µs / C_T / pp512 all baseline-within-noise; dbuf on/off identical) — the BT stall is compute-side (ldmatrix→mma chains), not staging; remaining levers are tolerance-class → patch reverted per doc-90 discipline, D5-R closed at its identity-safe ceiling⚫
99fastverify-p0-p1fast-verify P0/P1: doc 98's tolerance-class claim corrected (int mma exact → wider bitwise-safe set); fragment prefetch / non-volatile mma / cp.async all measured NULL; B-plane XOR swizzle landed (shared wavefront excess 40%→0, −4.3% kernel instance, bitwise 4/4); pc-sampling re-attributes the stall to L1TEX latency × 16-warp occupancy ceiling → knob not built, EV re-priced down✅
100qs-plane-driftthe last priced lever (aligned qs plane) measured timing-NULL under interleaved A/B; sequential "−12.4%" was clock-ramp drift (±7–12% band, 208 MHz idle → 3 GHz) — sequential before/after runs on dgxspark are invalid instruments; repack family closed, D5-R fully closed⚫
101steady-state-methoddoc 100's rule made executable: time-budget warmups in specverify/bench; headline table re-measured tight (pp512 2083 ± 7.2; adaptive 35.9 prose / 44.8 code; d8 collapse reproduced) — doc-95 absolutes confirmed as drift artifacts, structure exact✅
102draft-scale-sweepbigger drafts lose (acceptance bounded by the target, not draft capacity) — default draft stays 0.5B Q4_K_M; flushed + fixed a latent qwen3-loader namespaced-registration bug (Q6_K padded weights under raw name → both models to CPU); post-EOS token-text gate relaxed to warning, cross-family identity 4/4✅ fix + null
103q40-q80-mmvqq4_0/q8_0 decode joins the MMVQ family (8e structure, NEW CODE ONLY — every landed K-quant kernel/arm untouched, size-floored gates + MINFER_NO_Q40_MMVQ/MINFER_NO_Q80_MMVQ fallbacks): 7B q4_0 tg128 48.1→56.8 (+18.1%), 7B q8_0 26.7→28.8 (+7.9%), 7B q8_0 spec e2e 26.8→68.0 tok/s (+154%); same-file llama.cpp comparison — q4_0 decode 1.045× faster than llama.cpp, q8_0 closed 0.87×→0.94×; pp512 unchanged ✓, suite 187/0/3, q8_0 identity 4/4✅
104q80-p32-split-planensys located doc 103's remaining q8_0 gap inside the kernel (97% of decode GPU time; 16 scattered 2B weight loads per block at a 34B lane stride = ~2x q4_0's L1TEX wavefront cost per byte) → p32 split planes (payload 32B/block 16B-aligned for uint4 x2 + dense 2B d plane, traffic unchanged, raw registration untouched, byte-equal outputs): 7B Q8_0 tg128 28.5→31.9-32.1 (+12.3% over f32) = parity with llama.cpp (0.87x→0.94x→1.00x), spec e2e 69.1→79.0 tok/s = 2.47x sequential; q4_0-p32 and 36B-pad variants measured and rejected✅
105device-tier-tablesT-series T1: cc-keyed device tier table + selector (device_tier.rs, pure data, offline-tested) — GB10 Measured, consumer rows Adopted from llama.cpp (Blackwell K-quant caps 5/6/7, Orin K-quants→1, Turing mmq=false ruling #4), GENERIC fallback; MINFER_DEVICE_TIER override; mmq gate = resolved tier flag; batch caps tabled but unwired (R8). Encoding fix: runtime cc is 1201, table keys llama-encoded via conversion✅
106query-formula-gatesT-series T2: auto-ksplit SM-count parameterization (target max(256,2*SM), GB10-invariant), BT smem feasibility gate (single-source C formula + cuda_mmq_smem_bytes(); R2 fixed — externs now query the selected device, not device 0), plane VRAM budget gate on all optional planes (p32/W_exp/W_dsc) for 8 GB unified-memory devices. Tile candidates + cap activation + T3 deferred per plan✅
107c4-packed-q8-kv-cudaC4 #144: the packed Q8_0 cache's two missing tuned routes — the packed fused decode epilogue (attn_bias_rope_store_q8_0, one thread per (head, 32-element K block) and per V block, the store's own quantizer) and the packed FA prefill (fa_prefill_kv<CAUSAL,MAP,LAYOUT> dequantizes each block into the same f16 tile; general kernel stays the fallback). Qwen3-0.6B pp2048 564.5 → 8231.1 tok/s (14.58x; packed/f16 14.7x → 1.038x); 0.5B tg128 q8_0 161.5 → 170.1 (1.052x, the pre-registered 1.15x bar missed — the ticket's 1.18x was the f16-weight arm's cut). Two new device gates, three mutations, 124 launch sites🟢
108c4-dp4a-packed-q8-kv-cuda#186: the dp4a packed Q8_0 K dot — the decode split-K body accumulates int (__dp4a) against a per-(head, block)-quantized query and scales by d_q*d_k once per block; K is never converted to float (V still is). Bar named first (load-attributable share ≥ 10%), measured 20.3% on the 0.5B's hd-64 decode where both layouts share one 1-warp geometry; landed at 0.5B tg128 171.95 → 193.30 (1.124x, packed/f16 1.396x → 1.242x) and Qwen3-0.6B tg128 123.98 → 136.66 (parity with its f16 136.73); pp2048 flat. Real-model class re-measured (tail 2.479504, argmax 0.5527, greedy 9/9); prefill/verify left alone by measurement🟢
109c4-packed-q8-kv-l1-request#202: the packed Q8_0 KV cell's L1 request count, no layout change — the four s8 K/V quant loads per 4 elements become two u16 loads (34k + 2 + 4m is always 2-byte aligned even when only odd blocks are 4-byte aligned). The counter moves exactly as the ticket's mechanism predicted — packed/f16 L1 load-sector ratio 1.712x → 0.9845x (792 904 → 455 840), instructions −2.17% — but the pre-registered +2% tg128 bar was NOT cleared (+0.27%: 193.13 → 193.65, medians of 5 interleaved rounds) and the kernel is only 1.4-1.7% faster (nsys). A partial refutation: the 1.23x packed/f16 decode residual is not L1-request-bound (not L2: 0.56x, not instructions: 1.10x, not sectors: 0.98x). Landed counter-only, byte-identical, no layout/session/CPU change; the latency hypothesis is filed for the next attribution🟢 counter-only

Part VI · Methodology

#doctopic
77verification-methodologythe verification system in full: the gate chain, the GB10 tool protocol, the master library of transferable rules

State at the campaign's close (2026-09-12, after D5-R)

tg128@long KVdevice memory
Qwen2.5-7B Q4_K_M1.074× vs llama.cpp1.052× @1.6K~10.4 GB
Qwen2.5-14B Q4_K_M1.018×0.950× @3.3K~14.1 GB

Prefill: 7B pp3314 ~3581 tok/s (1.080×); 14B pp3254 ~1830 tok/s (1.12×). Speculative decoding (D5-R, closed): 14B+0.5B q4_0 d=2 = 1.42×/1.68× (prose/code, 35.7/42.5 tok/s) = 95%/88% of llama.cpp's absolute speculative speed in the same window; d=8 measured 0.63× (retired). Open leads: ncu on the small-M MMQ gap (counter permissions), nt-invariant accumulation (prose acceptance + exact greedy identity).