Feature β Gemma-4 A4B Dual Chunk Attention (DCA), training-free 1M context
Status (2026-06-10): DESIGN LANDED, patch
0078not yet captured. Feature home for the forthcomingvendors/patches/llamafile/0078-gemma4-dca.patch. The patch capture + build + RULER gate run in an out-of-tree clean-room (a separate llamafile checkout) β see "Capture without reset" β because the livevendors/sources/llamafileworking tree holds the only applied source of patches0001β0077and MUST NOT bereset/cleaned (buglog 2026-06-04:build:llamafile:reset=git reset --hard+git clean -fdxwipes uncommitted patch source). T87.pD.
Goal
Extend Gemma-4 26B-A4B (and 31B dense) to ~1M context training-free, matching Qwen2.5-14B-1M's RULER class (92.5 @ 1M), by porting Dual Chunk Attention (DCA, the Qwen 1M mechanism) into the llamafile graph. Runs on consumer GPUs (RTX 3090) β the path our users actually have β instead of the parked vLLM FA4-sm120 route (which needs an unfinished CuTe Blackwell kernel; see backup_models task #592). DCA composes with YaRN mscale for the final 2Γβ4Γ past the chunk grid.
Why llamafile is sufficient (feasibility verified 2026-06-10, read-only)
Gemma-4 26B-A4B attention is mixed-head (config + tensor-shape confirmed):
- 25 sliding layers @ head_dim=256 (window 1024, ΞΈ=1e4) β bounded by their window, need NO long-range handling.
- 5 global/full layers @ head_dim=512 (idx 5, 11, 17, 23, 29;
global_head_dim=512,num_global_key_value_heads=2,attention_k_eq_v=trueβ nov_proj, K=V;partial_rotary_factor 0.25β n_rot=128 of 512; ΞΈ=1e6,rope_type=proportional). These carry all long-range information β DCA touches ONLY these 5 layers. - No
attn_logit_softcapping(Gemma 3/4 dropped it; onlyfinal_logit_softcapping=30on the LM head) β the chunk merge is the plain no-softcap online-softmax.
Every primitive DCA needs already exists in vendors/sources/llamafile/llama.cpp (RULER-validated):
- Proportional rope β
src/models/gemma4-iswa.cpp:56-59feedsmodel.layers[il].rope_freqsasfreq_factorstoggml_rope_extfor!is_swalayers;rope_freqsloads atsrc/llama-model.cpp:2955. Per-layerfreq_base_l/freq_scale_l/n_rot_l(gemma4-iswa.cpp:47-49). - YaRN β
ggml_rope_ext(..., ext_factor, attn_factor, beta_fast, beta_slow)(gemma4-iswa.cpp:73,97)- hparams
n_ctx_orig_yarn/yarn_*+rope_scaling_type β {none,linear,yarn,longrope}.
- hparams
- hd=512 flash-attention β patch
0075-d512-turbo-vec(D-generic FA-VEC for the global layers). - LSE-emitting FA + exact online-softmax merge β patch
0070-rolling-kv:launch_fattnper-rowdst_lse = max + logf(rowsum)via theopencoti_fattn_dst_lseconsume-once channel +GGML_OP_STREAMING_FLASH_ATTN+streaming_combine_kernel. This is DCA's chunk-partial merge; generalizes from 2 regions (windowβtail) to N chunk-groups. - Training-free position-remap precedent β
grp_attn_n/grp_attn_w(LongLM Self-Extend),tools/completion/completion.cpp:511-517. Same CLASS as DCA. Caveat: completion-tool-only, so DCA hooks at the graphbuild_attnseam (serves the server opencoti drives). - Clean per-layer seam:
build_attn(inp_attn, wo, β¦, Qcur, Kcur, Vcur, β¦, f_attention_scale, il)(gemma4-iswa.cpp:102).
No blocking limitation. Nuances handled by design: extension config (YaRN factor / n_ctx_orig)
via GGUF metadata or CLI; Self-Extend is completion-only so we hook the graph; our A4B GGUFs already
carry rope_freqs (they serve at 256k today).
DCA algorithm (global layers only)
Split positions into chunks of size c (c < trained length; e.g. 65536). For each global layer,
attention is computed in position regimes merged by LSE:
- intra-chunk β queries attend keys in the SAME chunk at LOCAL positions
[0,c)(preserves the trained short-range rope behavior). - inter-chunk β queries attend EARLIER chunks at a clamped inter-chunk (chunk-index) position so relative positions stay inside the trained range.
- successive-chunk β the immediately-preceding chunk uses a continuous bridging position so the intra/inter seam doesn't jump. On Gemma-4 only the rotary 128 dims (partial_rotary 0.25) are remapped; the other 384 pass through. Each regime = a separate rope'd-Q Γ KV attention emitting LSE; the partials merge via the existing online-softmax combine. YaRN mscale (attn_factor) optionally rides on top for the final 2Γβ4Γ.
Patch 0078-gemma4-dca structure
Base for capture: live tree = 0001-0042 + 0070..0077 applied. Number 0078 (applies AFTER 0077).
A. Flags (additive, default-OFF β byte-identical when off)
common/arg.cpp + common/common.h + src/llama-cparams.h: --dca {off,on} (default off),
--dca-chunk-size N (default = n_ctx_train β inert: c β₯ seqlen collapses to a single intra
regime = plain attention), optional --dca-yarn-factor F. LLAMA_ARG_DCA*, LLAMA_EXAMPLE_SERVER.
New cparams: bool dca_enabled; uint32_t dca_chunk; float dca_yarn_factor;. OFF path grep-clean
byte-identical to pre-0078.
B. Graph hook (one surgical marker) β src/models/gemma4-iswa.cpp
For !hparams.is_swa(il) && cparams.dca_enabled ONLY, route attention through the new additive
builder instead of the single build_attn(...). Marker // opencoti F5 gemma4-dca. Sliding layers
and dca_enabled==false keep the unchanged build_attn β OFF byte-identical.
C. Additive builder β NEW src/models/gemma4-dca.cpp (+ decl in src/models/models.h)
build_attn_dca_gemma4(...): builds intra/successive/inter rope'd-Q variants (3Γ ggml_rope_ext
on inp_pos-derived remapped position tensors), runs 3 build_attn-style FA calls over the global
KV emitting dst_lse (reuse 0070's channel) with chunk masks, merges the 3 partials with a
streaming_combine-family reduce (extend the 2-region form to N-region). Keeps the in-tree hook to a
single marker (NEW file per UPSTREAM_SYNC Β§Additive).
D. Position inputs β additive llm_graph_input_dca
Mirrors llm_graph_input_mtp (0074) / position-window inputs (0070): holds intra/inter/succ position
vectors derived from inp_pos + dca_chunk. Registered in graph-input assembly; no upstream-source
edit beyond registration.
E. Acceptance gate β NEW .opencoti/dca-ruler-gate.sh
- OFF byte-identity:
--dca offgreedy decode byte-identical to the pre-0078 binary. - Below-one-chunk no-op: at ctx β€ 256k with
--dca-chunk-size β₯ ctx,--dca onRULER vt/niah ==--dca off(DCA must be a no-op whenc β₯ seqlen). Uses the RULER native runner. - Extension win: RULER vt/niah at 512k & 1M with
--dca onvs YaRN-only degradation β target the T87 1M class (β₯ Qwen2.5-14B-1M's 92.5@1M behavior on the global layers). Uses the mergeβserveβRULER-ladder driver. - Acceptance = logit-distribution / RULER-score equivalence, NOT greedy byte-equality past one chunk
(online-softmax is fp-non-associative β same standard as
0070).
F. README row + UPSTREAM_SYNC
Add the 0078-gemma4-dca row to vendors/patches/llamafile/README.md (## Current series) and
register the single // opencoti F5 gemma4-dca marker in docs/protocols/UPSTREAM_SYNC.md (same
mechanism as 0076/0077). Provenance: opencoti-original; algorithm from the DCA paper
(Qwen2.5-1M) + the deleted v0 vLLM dual_chunk_flash_attn.py reference (read, not transcribed).
Capture without reset (the live tree holds the only patch source)
The standard bun run build:llamafile:{check,apply,build} flow assumes a pristine submodule
(git apply --check/end-to-end apply), which the live tree is NOT (0001-0077 already applied) and we
must NOT reset it. Therefore:
- Clean-room build/gate: in a SEPARATE out-of-tree llamafile checkout (not the held submodule),
reset β bootstrap β apply 0001-0077 β apply 0078 edits β build (cosmocc + ggml-cuda DSO) β run gate E. The heldvendors/sources/llamafileis never touched. - Capture the diff against an out-of-tree base copy of the touched files (NOT
git applyfrom inside an in-tree baseline β that is a silent no-op, buglog bug-431; usediff -u base liveto produce the patch andpatch -p1to re-apply into a copy when verifying). - Verify round-trip:
0078-gemma4-dca.patchreverse-applies clean vs the post-0078 tree and forward-reproduces it byte-for-byte (0 diffs), both directions. - Land only the artifacts in the opencoti repo:
0078-gemma4-dca.patch, the README row, the UPSTREAM_SYNC entry,.opencoti/dca-ruler-gate.sh, this doc. The held submodule working tree stays exactly as the other session left it.
Cheaper baseline to A/B first
grp_attn (Self-Extend) already exists; A/B its RULER@512k for A4B as the bar DCA must beat. Blocker:
completion-tool-only β needs a tiny server-path grp_attn hook OR running the completion tool for
the probe. Document the gap vs full DCA before committing to the 0078 build.
Section-C merge: implementation decision (grounded 2026-06-10, read-only)
The graph seam (gemma4-iswa.cpp global block, !is_swa(il)): rope_ext(Qcur/Kcur, inp_pos, freq_factors=rope_freqs, n_rot_l, freq_base_l=1e6, ...) β build_attn(inp_attn, wo, β¦, Qcur, Kcur, Vcur, β¦, f_attention_scale, il). Hook here for dca_enabled && !is_swa.
0070 primitives available host-side: ggml_streaming_flash_attn(q,k,v,mask,scale,max_bias,softcap) (emits O+LSE), ggml_streaming_flash_attn_window(q,k_win,v_win,k_tail,v_tail,mask,β¦) (2-region FUSED FA+combine), ggml_flash_attn_ext_tail_partial(q,k,v,β¦) β un-normalized partial [2+DV, n_head, n_q, n_b] = (m, s, VKQ). There is NO standalone host-exposed N-way (O,lse) combine β the online-softmax merge is fused inside GGML_OP_STREAMING_FLASH_ATTN (fattn.cu streaming_combine_kernel).
DCA needs to merge 3 regime partials (intra/successive/inter). Two paths:
- C1 β graph-math merge (host-only, PREFERRED, no DSO rebuild): per regime, emit the un-normalized partial (m_i, s_i, O_iΒ·s_i); combine N partials with a small subgraph of EXISTING ggml ops:
m=max_i(m_i),w_i=exp(m_iβm),S=Ξ£ w_i s_i,O=Ξ£ w_i O_i s_i / S. All elementwise/reduce ops already in ggml β compiles into the host binary, executes on the existing fatggml-cuda.so 0.10.1(sm_86+sm_120). Build = cosmoccmakeonly. Risk: must get each regime's FA to emit the GPU partial to a graph tensor (verifyggml_streaming_flash_attnpartial-output mode is graph-addressable, not just the thread-local channel; the_tail_partialop is CPU-only β too slow at 512k, so the GPU streaming op's partial path is required). - C2 β new N-way combine kernel (DSO rebuild): add
ggml_streaming_combine_n(partials[])+ astreaming_combine_n_kernelgeneralizing the 2-region kernel β rebuildggml-cuda.soviacuda.sh. Cleaner/faster but heavier build + a CUDA-source edit (per UPSTREAM_SYNC, a NEW kernel file to keep the in-tree hook minimal).
Decision: implement C1 first (host-only build, fastest to a gated result); fall back to C2 only if the GPU partial isn't graph-addressable or numerics demand a fused kernel. Either way the 3 regime Qs come from 3 ggml_rope_ext on remapped inp_pos views (intra=local [0,c); inter=chunk-index clamp; succ=continuous bridge), remapping only the rotary 128 dims (partial_rotary 0.25); the other 384 pass through.
Build path is cosmocc, NOT cmake (confirmed: patch sources ggml-neo-pipeline/iqk/turbo/d512-vec are NOT in any CMakeLists.txt; native cmake --build link-fails on those symbols). Clean-room = out-of-tree copy of the held vendors/sources/llamafile tree (already has 0001-0077 applied to source); edit C1 there; bun run build:llamafile:make (host binary, reuses fat DSO); gate E with --dca on + --override-kv gemma4.context_length serve; capture 0078 by diff vs a frozen copy of the held tree. Held submodule never reset.
Section-C VERDICT (2026-06-10, op contract verified read-only) β C1 FALSIFIED β C2 required
Read the actual 0070 op definitions (vendors/patches/llamafile/0070-rolling-kv.patch). The "implement
C1 first" decision above is falsified by the op contract:
- The GPU op
ggml_streaming_flash_attnreturns normalized O only βne[4]={DV, n_head, n_q, n_batch}, F32 (patch L539). Its per-tile LSE lives in internal pool allocsO_tiles/lse_tiles(L1327-8) consumed by astatic __global__ streaming_combine_kernelinside fattn.cu (L1113, invoked L1859). LSE is never a graph tensor. β cannot call it 3Γ and merge (O,LSE) host-side. - The only op that emits the addressable un-normalized partial
[2+DV,n_head,n_q,n_b]=(M,S,VKQ),ggml_flash_attn_ext_tail_partial, is CPU-only (dispatched solely in ggml-cpu/ops.cpp L694/811; no CUDA case β CUDA dispatch L1895/1912 isSTREAMING_FLASH_ATTNonly) and decode-onlyn_q==1(its own header, L618-620). Useless for the 512k-token prefill where DCA matters; CPU scalar at 512k is intractable regardless. - Eager/materialized DCA (3 masked QK^T blocks combined by pure graph math, single softmax β which would be genuine C1, no DSO rebuild) needs the full O(nΒ²) score matrix: β1 TB/head @512k. Infeasible.
Therefore: the performant DCA path requires a CUDA-source edit β DSO rebuild (C2). There is no
host-only route to per-regime (O,LSE) at prefill scale. Build flips from cheap build:llamafile:make
(reuse fat DSO) to cuda.sh ggml-cuda.so rebuild (the multi-hour cosmocc CUDA path), done in the
out-of-tree clean-room (held submodule still never touched).
C2, minimal-footprint shape (reuses machinery that already exists internally): expose the existing per-tile partial + combine as graph-addressable β
- (a) a GPU op variant that runs FA over one regime and writes the un-normalized partial (M,S,VKQ) to a graph tensor (the streaming op already computes exactly this per tile before its internal combine β emit it instead of/in addition to normalized O), and
- (b) a host-exposed N-way
streaming_combine_n(partials[3])generalizingstreaming_combine_kernel(which already combines N tile-partials) so the 3 regime partials merge on-device. Per UPSTREAM_SYNC, new CUDA code lands in a NEW file; the in-tree hook stays a single marker. The 3 regime Qs still come from 3ggml_rope_exton remappedinp_posviews (intra=local [0,c); inter=chunk-index clamp; succ=continuous bridge), rotary-128 dims only (partial_rotary 0.25); other 384 pass through. Numerics validated against the existing op's internal combine (same LSE math).
MULTI-ARCH generalization (2026-06-10, user directive: "don't limit DCA to Gemma4 β same 1M extension on Qwen")
DCA is now an architecture-general training-free 1M extension, not a Gemma4 one-off. Patch renamed
0078-dca (was 0078-gemma4-dca). Verified the Qwen seam is identical to Gemma4's:
qwen2.cpp: ggml_rope_ext(Q/K, inp_pos, freq_factors=nullptr, n_rot=n_embd_head /*full rotary*/, rope_type, n_ctx_orig, freq_base, freq_scale, β¦) β build_attn(inp_attn, wo, β¦, Q,K,V, β¦, scale, il)
β same shape, differing only in freq_factors (Gemma4 global = rope_freqs; Qwen = null) and
n_rot (Gemma4 partial-128 of 512; Qwen full head_dim). So one generic helper serves all:
- Section C (core, arch-agnostic) β new
dca.{cpp,h}:llm_graph_input_dca(the 3-regime remapped position vectors, built once likeinp_pos) +llm_graph_context::build_attn_dca(inp_attn, inp_dca, wo, wo_b, Qcur_PREROPE, Kcur_PREROPE, Vcur, β¦, dca_params, rope_params, kq_scale, il). It applies the 3 regime ropes (intra/successive/inter) viaggml_rope_exton remapped positions, runs the partial-emit FA per regime, merges withstreaming_combine_n, then thewoprojection (mirrorsbuild_attn's tail).rope_paramscarries exactly the args each builder already passes toggml_rope_ext(n_rot, rope_type, n_ctx_orig, freq_base/scale, ext/attn_factor, beta_fast/slow, freq_factors) β handles Gemma4 partial-rotary AND Qwen full-rotary with no special-casing. - Section B (per-arch hooks, small) β in each builder, gate the full-attention layers through
build_attn_dcainstead ofrope_ext+build_attn: Gemma4is_dca_layer = !is_swa(il)(5 global only); Qwenis_dca_layer = true(all layers, no SWA). First-landing hooks:gemma4-iswa.cpp,qwen2.cpp(Qwen2.5-1M, the canonical DCA target),qwen3.cpp,qwen3moe.cpp;qwen35/qwen35moe/qwen2moeare one-marker each, added as needed. Marker// opencoti F5 dca. - Section D (CUDA, arch-agnostic) β partial-emitter op +
streaming_combine_n; operates on tensors, no arch knowledge. This is the C2 DSO-rebuild payload. - Gate E β RULER-VT @512k on BOTH A4B Q4_K_M AND a Qwen 1M model, vs the naive-ext bar (VT 0.36).
Clean-room standup (confirmed mechanics)
Build pipeline: bun --cwd packages/opencoti-llamafile script/build-pipeline.ts {reset,apply,make,cuda}.
apply = reset(git clean -fdx+checkout pin 6490e16) β bootstrap(download cosmocc + Mozilla-Ocho
make setup) β git apply 0001-0077. The held submodule has 8 uncommitted WIP files (cuda.sh,
llamafile.c/h, build mk, nested llama.cpp) β reset would WIPE them (buglog bug-431). So the
clean-room is a separate git clone /shared/dev/opencoti <dca-clone> (committed state only; held WIP
excluded by design), where applyβedit 0078βcuda runs freely. Capture 0078 by diffing the clone's
post-0078 source vs its post-0077 (pre-edit) source. Held tree never reset, never touched.
Section-C ENGINEERING DESIGN (2026-06-10, grounded in clone applied source) β the cache-rope problem
Reading llm_graph_context::build_attn (kv variant) exposed the crux: K is stored to the KV cache
already rope'd (model builder ropes Kcur β build_attn β mctx_cur->cpy_k(Kcur)), and attention
reads it back rope'd. DCA needs the SAME keys re-rope'd with DIFFERENT positions per regime
(intra=native pos, inter=chunk-clamped, succ=bridge) β a single cached rope can't provide that.
Decision: DCA layers cache K UN-ROPE'd and apply all rope at attention time, per regime, inside
build_attn_dca. Consequences:
- The per-arch hook (Section B) passes pre-rope Q AND pre-rope K to
build_attn_dca(not just re-routes the call). On Gemma4 global, pre-rope K =attn_k_norm(K_proj)(the tensor right beforeggml_rope_ext); V =rms_norm(K_proj)is already un-rope'd (k_eq_v) and unchanged. On Qwen, pre-rope K = the reshaped projection before itsggml_rope_ext. build_attn_dcastores pre-rope K + V to cache (cpy_k/cpy_v), then per regime rβ{intra,succ, inter}:Q_r=rope(Qcur_pre, pos_q_r),K_r=rope(get_k_raw, pos_k_r),partial_r = streaming_flash_attn_PARTIAL(Q_r, K_r, V, mask_r, kq_scale); thenO = streaming_combine_n([partial_intra, partial_succ, partial_inter]); thenwoprojection (mirrors build_attn tail:build_lora_mm(wo,Β·)+ optionalwo_b).- Rope-on-cached-raw-K is an ESTABLISHED pattern here:
llama_kv_cache::build_rope_shift(llama-kv-cache.cpp:3893, used by context-shift) re-ropes cached K via a position/k_rottensor β the structural template (DCA ropes a READ COPY with absolute regime positions, does NOT mutate the cache). llm_graph_input_dca(built once likeinp_pos, host-filled from batch positions + KV-cache cell positions) supplies, per regime:pos_q_r(len n_tokens),pos_k_r(len n_kv), andmask_r([n_kv Γ n_tokens] additive). The pos remaps + masks encode the DCA chunk math (chunk_size c =--dca-chunk-size, default β n_ctx_orig). intra = same-chunk causal, native pos; inter = q-chunk > k-chunk, k pos within-chunk + q pos clamped β€ pretrain window; succ = adjacent chunk bridge. rope usesrope_params(n_rot, rope_type, freq_base/scale, ext/attn_factor, beta_fast/slow, freq_factors) β Gemma4 partial-128 / Qwen full-rotary handled by the n_rot arg.
Toggle is launch-time only (cache contents differ: raw-K for DCA vs rope'd-K for non-DCA) β fine,
it's a serve flag. Wiring caveat: Gemma4 0076 shared-KV means some global layers reuse KV cache of earlier layers (has_kv(il) false) β DCA must rope-on-read consistently for the layer-group that
owns the cache; verify against the 0076 shared-kv mechanics when wiring Section B.
Implementation progress (2026-06-10) + Section-D simplification
Patch number 0078 confirmed (user, keep 0078). Build host = solidpc RTX 3090 (sm_86, CUDA 13.2).
Section-D shrinks to ONE new op + graph-math combine (no new combine kernel). Insight: if the new
FA op emits NORMALIZED O packed with per-row LSE as [DV+1] (reusing 0070's existing dst_lse
channel β the lse = m + logf(sum exp) math already lives in launch_fattn), the 3-regime merge is
pure existing-ggml graph math: M = max_r(lse_r) (binary max via a + relu(bβa)), w_r = exp(lse_rβM), O = Ξ£_r w_rΒ·O_r / Ξ£_r w_r (ggml_exp/mul/add/div, broadcasting w over DV). So the
DSO rebuild only adds a CUDA forward for the new op (FA + write lse), not a bespoke combine kernel.
DONE this session (clean-room /shared/dev/opencoti-dca, baseline nested 43ccc8a56):
- Section A (flags) β
--dca/--dca-chunk-size/--dca-yarn-factorthrough all 6 opencoti sites (arg.cpp, common.h, common.cpp, llama-context.cpp Γ2, llama-cparams.h, llama.h). Verified. Script:backup_models/scripts/dca/apply_section_a_flags.py. - Section D-host β
GGML_OP_FLASH_ATTN_EXT_LSE+ggml_flash_attn_ext_lse(q,k,v,mask,scale, max_bias,logit_softcap)β dst[DV+1, n_head, n_q, n_batch]([0,DV)=O, [DV]=lse). Registered in ggml.h enum+decl, ggml.c name/symbol arrays, both static_asserts (100β101), constructor. Script:backup_models/scripts/dca/apply_section_d_host.py.
REMAINING: D-cuda (CUDA forward for the new op: ggml_cuda_flash_attn_ext path + dst_lseβdst[DV]
slot; supports_op + scheduler-pin like the bug-259 STREAMING_FLASH_ATTN hook) β Section C
(dca.cpp/h: llm_graph_input_dca + build_attn_dca) β Section B (per-arch hooks) β cuda.sh DSO
rebuild β RULER-VT gate (A4B + Qwen) β capture 0078-dca.patch.
Section D-cuda DONE (2026-06-10)
ggml_cuda_flash_attn_ext_lse authored + wired (8 sites, apply_section_d_cuda.py):
- fattn.cu β the forward: O via an O-typed view of the packed dst β existing
ggml_cuda_flash_attn_ext(proven streaming-opggml_tensor o=*dst; o.op=FLASH_ATTN_EXTtrick); per-row lse via the existing staticstreaming_lse_kernelinto the trailingn_rows(softcap-aware, works for any n_q incl. prefill β avoids thedecode_lse/bug-263 finalize fragility). Asserts Q f32 / K f16. - fattn.cuh decl; ggml-cuda.cu compute_forward dispatch + supports_op (validates the O FA at ne[0]=DV, not the packed DV+1); ggml-backend.cpp bug-259 scheduler CUDA-pin; ggml-cpu Γ3 (compute_forward abort, n_tasks single-task, supports_op=false) β CUDA-only mirror of STREAMING_FLASH_ATTN.
Op fully complete (host + CUDA). Compile-verified later in the single cuda.sh DSO build (after C+B).
REMAINING: Section C (dca.cpp/h: llm_graph_input_dca + build_attn_dca with DCA position-remap +
graph-math combine β O view ne=[DV,H,nq,nb] @offset0, lse view ne=[1,H,nq,nb] @offset DV*n_rows) β
Section B (per-arch hooks) β cuda.sh DSO rebuild β RULER-VT gate β capture 0078-dca.patch.
Section C design (2026-06-10) β grounded against the clean-room seams
Read of the clean-room (43ccc8a56) settles the algorithm and the integration points.
Seams (verified):
- kv-variant
build_attn(llama-graph.cpp:2571) and iswa-variantbuild_attn(llama-graph.cpp:2841). Both:cpy_k/cpy_v(k_cur,β¦)store whatever K they're handed βget_k/get_v(ctx0,il)read-back βbuild_attn_mhaβbuild_lora_mm(wo)+wo_b. Gemma-4 globals ride the iswa path (build_attn_inp_kv_iswa,is_swa(il)==falseβ base mctx); Qwen rides the plain-kv path. βbuild_attn_dcaneeds both input-type overloads. - Host position source:
set_input_kq_mask(llama-kv-cache.cpp:3773) /set_input_pos_bucket(:3812) readv_cells[strm].pos_get(j)/cells.is_empty(j)per cached cell. Allm_graph_input_i::set_inputonly gets the ubatch β the per-cell fill must be a newllama_kv_cache[_context]::set_input_dca(mirrorsset_input_kq_mask), delegated to fromllm_graph_input_dca::set_input. - Rope contract (gemma4-iswa.cpp:73/97):
ggml_rope_ext(x, inp_pos, freq_factors, n_rot_l, rope_type, n_ctx_orig, freq_base_l, freq_scale_l, ext, attn, beta_fast, beta_slow)β Gemma-4 globals usen_rot_l=hparams.n_rot(il)(partial-128 on the hd512 global),freq_base_l=1e6. Qwen full-rotary usesn_rot = n_embd_head,freq_base=1e6/yarn.build_attn_dcareproduces this call three (Q) + one (K) times with regime position vectors instead ofinp_pos.
Algorithm β rope-K-ONCE, rope-Q-THRICE (ChunkLlama scheme). All three regimes share one key
assignment pos_k[j] = cellpos(j) mod c; only the query position differs:
| regime | pos_q[i] |
keep-mask (causal jβ€i, chunk =βpos/cβ) |
|---|---|---|
| intra | i mod c |
chunk(j) == chunk(i) |
| succ | (i mod c) + c |
chunk(j) == chunk(i) β 1 |
| inter | c (const) |
chunk(j) < chunk(i) β 1 |
The three keep-masks partition the causal lower-triangle exactly β the LSE-merge of the three
softmaxes equals full attention under DCA-remapped positions (no double-count, no gap). No q-k
distance exceeds the pretrain window: intra <c, succ β(0,2c), inter =cβokβ[1,c]. c =
dca_chunk_size or (auto) n_ctx_orig_yarn. YaRN mscale composes via the existing rope ext/attn
factors (dca_yarn_factor feeds cparams.yarn_*; the rope kernel itself is unchanged).
build_attn_dca(inp, wo, wo_b, Qpre, Kpre, Vcur, β¦, kq_scale, il) graph body:
cpy_k(Kpre)/cpy_v(Vcur)to cache (Section B hands pre-rope K + un-roped V).Kraw = get_k(ctx0,il);V = get_v(ctx0,il);Kdca = ggml_rope_ext(Kraw, inp_dca->pos_k, β¦)β one rope of the large cached K (raw cells, regime-invariant key positions).- For
r β {intra,succ,inter}:Qr = ggml_rope_ext(Qpre, inp_dca->pos_q[r], β¦);Pr = ggml_flash_attn_ext_lse(Qr, Kdca, V, inp_dca->mask[r], kq_scale, max_bias, softcap)β packed[DV+1, H, nq, nb]. O viewggml_view_4d(Pr, DV,H,nq,nb,β¦,0); lse viewggml_view_4d(Pr, 1,H,nq,nb,β¦, DV*nb0). - Combine (pure ggml):
M = a+relu(bβa)over the 3 lse;wr = ggml_exp(lse_r β M)(broadcast over DV);O = (Ξ£ wrΒ·Or) / (Ξ£ wr); reshape[n_embd, n_tokens];build_lora_mm(wo)+wo_b.
llm_graph_input_dca (new, dca.h): pos_k (I32 [n_kv]), pos_q[3] (I32 [n_tokens]), mask[3]
(F32βF16 cnv, [n_kv, GGML_PAD(n_tps,GGML_KQ_MASK_PAD), 1, n_stream] like build_attn_inp_kq_mask),
const llama_kv_cache_context * mctx, uint32_t c. set_input(ubatch) β
mctx->set_input_dca(pos_k, pos_q, mask, ubatch, c).
Files touched by Section C: new src/dca.cpp + src/dca.h (the two builders) and
llama-kv-cache.{cpp,h} (the set_input_dca host-fill β folded into C) and llama-graph.h
(the build_attn_dca decls + llm_graph_input_dca). dca.cpp compiles against the already-present
host ggml_flash_attn_ext_lse (D-host); the CUDA forward (D-cuda) need not exist until the DSO
build. Sub-blocks: C1 = dca.h + llm_graph_input_dca + set_input_dca host-fill (this block);
C2 = build_attn_dca graph bodies (both overloads).
Section C2a (host-fill) DONE (2026-06-10)
dca.h (C1) + the host-fill half of C2 landed in the clean-room. Builds independently of the
build_attn_dca graph bodies (next block) and of D-cuda (host ggml_flash_attn_ext_lse already
present from D-host).
src/dca.cpp(new) βdca_resolve_chunk_size(cparams.dca_chunk_size or auto = n_ctx_orig_yarn / n_ctx_train),llm_graph_input_dca::set_input(delegates tomctx->set_input_dca),::can_reuse(false β pos/masks are position-specific), andllm_graph_context::build_attn_inp_dca(mctx_kv)(allocates pos_k I32[n_kv], 3Γ pos_q I32[n_tokens], 3Γ mask F32[n_kv,n_tokens,1,1] + F16 cnv; single-stream, mirrorsbuild_attn_inp_kq_mask).src/llama-kv-cache.cppβllama_kv_cache::set_input_dca(readsv_cells[0]per-cell positions βpos_k=cellpos%c, 3Γ pos_q, and the 3 partition masks;n_stream==1assert likeset_input_pos_bucket; causal + same-seq + nonempty band test) + thellama_kv_cache_contextper-batch wrapper.src/llama-kv-cache.hβset_input_dcadecl in both classes (Γ2).src/llama-graph.hβbuild_attn_inp_dcamethod decl +class llm_graph_input_dca;fwd-decl.
Apply script backup_models/scripts/dca/apply_section_c_hostfill.py (5 anchored edits, all OK).
Verified: kv-cache.cpp Γ2, kv-cache.h Γ2, graph.h Γ2, dca.cpp def Γ1, braces balanced.
β Build-wiring TODO for the cuda.sh/make block (#598): confirm the cosmocc Makefile globs
src/*.cpp (so the new src/dca.cpp compiles) β else add it to the file list explicitly, or
build_attn_inp_dca link-errors.
REMAINING: Section C2b (build_attn_dca two overloads β rope cached raw-K once with pos_k +
rope Q thrice + 3Γ ggml_flash_attn_ext_lse under the partition masks + LSE graph-math combine +
wo/wo_b; declared in llama-graph.h alongside this block's decls). Before authoring C2b, read
get_k's returned cache-K layout (llama-kv-cache.cpp:2204) + build_rope_shift's caller
(~:4000-4030) to nail the rope-on-cached-K axis (positions vary on the cell axis). β Section B
(per-arch hooks) β cuda.sh DSO rebuild β RULER-VT gate β capture 0078-dca.patch.
Section C2b (build_attn_dca bodies) DONE (2026-06-10) β Section C COMPLETE
The rope-on-cached-K axis is settled by get_k (llama-kv-cache.cpp:2305): it returns
[n_embd_head, n_head_kv, n_kv, 1] β cells on ne[2] β so ggml_rope_ext(get_k, pos_k, β¦) with
pos_k length n_kv indexes the cell axis exactly as inp_pos indexes live tokens. K is roped
ONCE; Q thrice; both pre-permute (matching the model rope), then permuted into the flash-attn layout.
src/dca.cppβbuild_attn_dca_core(rope cached raw-K once; read+permute V once; per regime rope Q +ggml_flash_attn_ext_lseundermask_cnv[r]; extract O-view[DV,H,NQ,1]@0+ lse-view[1,H,NQ,1]@DVΒ·nb0, bothggml_cont; combineM=a+relu(bβa),w=ggml_exp(lseβM),O=Ξ£wΒ·O/Ξ£w;reshape_2dβbuild_lora_mm(wo)+wo_b) + the two public overloads (iswa: store toinp->mctx->get_base(), asserts!is_swa; plain-kv:inp->mctx; both guardk_cur/v_curfor Gemma-4 shared-KV layers).src/dca.hβdca_ropestruct (per-layer freq_base/freq_scale/n_rot/freq_factors).src/llama-graph.hβ 2build_attn_dcaoverloads +build_attn_dca_coredecls +dca_ropefwd-decl. Apply scriptapply_section_c2b_decls.py.
Empty-regime safety (verified, no code needed): a chunk-0 query's succ/inter regimes have an
all--inf mask row β FA O=0 and streaming_lse_kernel (fattn.cu:693 lse = (l>0)?β¦:-INFINITY)
emits -inf (the l<=0/NaN guard already there) β w=exp(-infβM)=0, dropping the regime cleanly.
Intra is never empty (diagonal), so M is always finite.
Two runtime caveats for the gate (#598):
f16 KV requiredβ LIFTED by #444 (DCA all-KV C1, 2026-06-18).build_attn_dca_coreno longer asserts f16;dca_lift_to_f16dequant-on-lifts a quantized/bf16/turbo cache to a transient f16 for the f16-only fused kernel (the stored cache stays quantized β the long-ctx memory win). Scalar quants (q8_0/q4_0/q4_1/q5_0/q5_1) hopq8βf32βf16because CUDA CPY has no direct scalar-quantβf16 kernel (that pair CPU-spills); f16 no-op, bf16/turbo cast direct. Host-only (no.cuchange). Gatedreal_frac=0vs f16-DCA on Qwen3-8B-Q8 at multi-chunk ctx (.opencoti/m444-dca-allkv-gate.sh). #445 (C2/C3) extends the gate to the full matrix β q8_0, q5_1, q5_0, q4_0, bf16 + asymmetric q8_0-K/q4_0-V ALL PASS (.opencoti/m445-dca-scalar-matrix-gate.sh): per typereal_frac(<t>-DCA vs f16-DCA) == real_frac(<t>-noDCA) == 0.0, so DCA adds zero argmax error beyond the type's own quant loss. (Prefill note: noDCA-quant FA prefill is type-specific β q4_0/bf16 have a fast batched tile-FA kernel3.5k tok/s, q8_0/q5_0/q5_1 fall to the decode-VEC path ~12β42 tok/s; DCA's f16-lift prefills uniformly ~1.5k tok/s β a win for the slow types.) q8-DCA decode β0.47Γ f16-DCA, and that 2Γ is characterized (not a regression to chase away): it is GPU-resident (CPU-spill would be <5 tps) and NOT cuda-graph loss (3 ms/tok) does not explain it. The single-pass directGGML_CUDA_DISABLE_GRAPHS=1changes neither path β the fused DCA op uses no graph). The cost is the dequant-on-lift itself, DOMINATED by thequantβf32CPY kernel's<<<ne, 1>>>one-thread-per-CUDA-block launch geometry (cpy.cu, ~1/32 warp utilization vs the 256-thread scalar cpy), with the f32 two-pass hop secondary; raw cast bandwidth alone (quantβf16CPY kernel (proper thread geometry, no f32 intermediate) recovers it β C-series perf follow-on at #448. So-ctk q8_0 -ctv q8_0is now valid with--dca on. The 0078 patch re-capture is batched at #448 (umbrella C6); the live source is banked.opencoti/dca/m444-dca.cpp.banked.- FA precision defaults β unlike
build_attn_mha(which forcesGGML_PREC_F32viaggml_flash_attn_ext_set_prec, an op-specific call that would assert on_LSE), the lse op runs at default prec. If RULER shows precision drift at 1M, force F32 on the O-view in D-cuda'sggml_cuda_flash_attn_ext_lse(set the prec slot before dispatching the inner FA).
Verified: dca.cpp 3 defs + braces 26/26; graph.h 3 decls + dca_rope fwd; ruff clean.
Section C COMPLETE (C1 header + C2a host-fill + C2b bodies). Compiles against host
ggml_flash_attn_ext_lse (D-host); CUDA forward (D-cuda) needed only at the DSO build.
REMAINING: Section B (per-arch hooks: gemma4-iswa global layers + qwen2/3/3moe all layers β gate
on cparams.dca_enabled, pass PRE-rope Q+K, build build_attn_inp_dca(base) once, fill dca_rope)
β cuda.sh DSO rebuild (confirm src/dca.cpp globbed) β RULER-VT gate β capture 0078-dca.patch.
Section B (gemma4) DONE (2026-06-10)
src/models/gemma4-iswa.cpp now routes the 5 GLOBAL (!is_swa) layers through build_attn_dca
when cparams.dca_enabled; SWA layers + the dca-disabled path are byte-unchanged. 7 anchored edits
(apply_section_b_gemma.py):
#include "dca.h".- before the layer loop:
llm_graph_input_dca * inp_dca = cparams.dca_enabled ? build_attn_inp_dca(inp_attn->mctx->get_base()) : nullptr;(built once on the base/global context). - per layer:
const bool use_dca = cparams.dca_enabled && !hparams.is_swa(il);. - Q-rope + K-rope wrapped in
if (!use_dca) {β¦}β DCA layers cache PRE-rope Q+K (rope happens per regime inside build_attn_dca). Vcur stays the rms-normed un-roped projection. - both
build_attn(β¦)call sites (has_kv + shared-KV reuse-KV branch) gain anif (use_dca)arm callingbuild_attn_dca(inp_attn, inp_dca, wo, nullptr, Qcur, [Kcur|null], [Vcur|null], {freq_base_l, freq_scale_l, n_rot_l, freq_factors}, f_attention_scale, il).
DCA reduces to identity for n_ctx β€ c (all positions in chunk 0 β intra-only, succ/inter empty,
distances < c β native rope), so enabling --dca never regresses short-context serving. Verified:
2 build_attn_dca calls, 1 inp builder, use_dca 5Γ, braces 27/27, ruff clean.
REMAINING: Section B (qwen2/qwen3/qwen3moe β all layers full-attention, use_dca = cparams.dca_enabled, same PRE-rope Q+K + build_attn_inp_dca(static_cast<β¦kv_cache_context*>(mctx))
on the plain-kv overload) β cuda.sh DSO rebuild (confirm src/dca.cpp globbed) β RULER-VT gate
(Gemma-4 A4B first, f16 KV) β capture 0078-dca.patch.
Section B (qwen) DONE (2026-06-10) β Section B COMPLETE β ALL SOURCE AUTHORED
qwen2.cpp / qwen3.cpp / qwen3moe.cpp route all layers through build_attn_dca when
cparams.dca_enabled (Qwen = the canonical training-free 1M arch; every layer is full attention).
The Q/K-rope + build_attn blocks are byte-identical across the three files, so one shared anchor
set (apply_section_b_qwen.py, 5 edits Γ3) applies to each: #include "dca.h"; use_dca = cparams.dca_enabled + inp_dca = build_attn_inp_dca(inp_attn->mctx) (plain-kv context, no
get_base); Q/K rope wrapped in if (!use_dca); the build_attn site gains an if (use_dca) arm
calling build_attn_dca(..., model.layers[il].wo, model.layers[il].bo, Qcur, Kcur, Vcur, {freq_base, freq_scale, n_rot, nullptr}, 1/βhead, il) (wo_b = bo carried; qwen3/3moe wo_s
post-scale untouched). Verified: each file 1 dca-call, 1 inp builder, use_dca 5Γ, braces balanced,
ruff clean.
ALL 0078-dca SOURCE AUTHORED β A (flags) + D (LSE op host+CUDA) + C (input + build_attn_dca) +
B (gemma4 globals + qwen2/3/3moe all layers). Nothing compiled yet β the single cuda.sh DSO build
(#598) compiles A+C+D+B together. New files: src/dca.{h,cpp}. Apply scripts (8) in
backup_models/scripts/dca/.
REMAINING (#598, the build+gate+land block):
- Build wiring β confirm the cosmocc Makefile globs
src/*.cpp(sosrc/dca.cppcompiles); add it explicitly if not. Thenbun --cwd packages/opencoti-llamafile script/build-pipeline.ts make+β¦ cuda(the multi-hourggml-cuda.soDSO rebuild, sm_86). Fix any compile errors surfaced (first real compile of A/C/D/B). - RULER-VT gate β serve A4B Q4_K_M (or bf16) with
--dca on --override-kv gemma4.context_length=int:1048576, f16 KV (NOT-ctk q8_0β DCA core asserts f16), default prec. RULER-VT @ β₯256k vs the naive-extension bar (VT=0.36 from T87.ext). Then a Qwen 1M model. - Capture β
git diff 43ccc8a56in the clean-room β0078-dca.patch; write patch + README row- UPSTREAM_SYNC entry +
.opencoti/dca-ruler-gate.shinto the HELD opencoti repo (top-level tracked only; submodule never touched); round-tripapplyverify.
- UPSTREAM_SYNC entry +