Repository navigation
feat(attention): ArcFlash — Arc's own attention kernel, rung 0 - #107
Conversation
… rung 0
Jish: "I won't tolerate FA2 as the default. Its gotta be FA4->MLA, our
system, working on all models" / "V4 Must use FA4" / "Long prompts should
be fixed."
Names the system per TAXONOMY.md's rule that no subsystem is left without
an absolute parent: Arc -> ArcInfer -> ArcAttention -> **ArcFlash**, with
ArcFlash/{Plan,Fold,Tile} shipped and ArcFlash/Cute named as the home for
the fused CuTeDSL d=512 kernel that does not exist yet. "ArcAttention/Flash"
already meant the capability envelope for Dao's FA2/FA3 -- a wrapper around
someone else's kernel -- so ours needed its own name rather than a collision.
Rung 0 removes the two allocations that made long prompts fail rather than
merely slow, at the two sites that performed the GQA expansion:
* backends/sinks.rs -- every DeepSeek-V4 layer, since head_dim 512 is
outside the fused sinks kernel's {64,80,96,112,128,192,256}.
* run_attention_noflash -- repeat_kv now runs *inside* the cuBLASLt arm
instead of ahead of all three paths.
ArcFlash/Fold expresses the GQA/MQA expansion as a reshape. repeat_kv maps
x[b,kv,s,d] -> y[b, kv*n_rep + rep, s, d], i.e. heads are kv-major, so a
contiguous q[B,H,Tq,D] reshapes to [B,Hkv,g*Tq,D] with no data movement and
both GEMM operands then carry batch B*Hkv. Verified against the pinned
candle: reshape is a view when contiguous, and broadcast_matmul is NOT an
alternative because candle concretises the broadcast operand. The trick is
already in-tree at t_q == 1 (absorbed_mqa_decode); this generalises it.
ArcFlash/Tile bounds the score matrix to one query tile under a byte budget
(ARC_FLASH_TILE_BYTES, default 32 MiB). Tiling query rows is exact, not an
approximation: each output row is an independent softmax, so no online
rescaling is involved and sinks -- a per-head constant in each row's
denominator -- are untouched.
ARITHMETIC, not measured: V4 prefill at B=1 H=64 D=512 T=1400 bf16 goes
from ~653 MiB to ~78 MiB of attention allocations per layer, ~8.3x. Pinned
by a test that also refuses to pass if the shape does not actually tile.
D18: note() logs "ArcAttention: first dispatch on <path>" once per path --
present in the arm that uses it, absent in the arm that does not. Tests
assert both directions. The test instrument is a cfg(test) thread-local,
not the process-wide atomics, because cargo test runs test fns in parallel
and a control arm would otherwise read other tests' dispatches.
Four mutations applied and all four caught, including one (sink dropped
from the denominator) caught by three pre-existing V4 tests as well as by
ArcFlash's own -- so this path is not tested only by its author.
386 mistralrs-core lib tests green. No GPU number is claimed;
arc-tools/arcflash/rung0_gpu_validate.sh is staged for main to run, and it
gates on compiling the CUDA-cfg'd Rust that a macOS check cannot reach.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Code Metrics Report━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Language Files Lines Code Comments Blanks ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ C Header 5 305 210 52 43 CSS 2 1181 1036 34 111 CUDA 72 24645 17702 4215 2728 Dockerfile 1 39 22 8 9 JavaScript 16 3546 2676 482 388 Jinja2 7 694 656 5 33 JSON 74 4600 4597 0 3 Makefile 1 6 5 0 1 Metal Shading Lan| 33 12224 9431 1142 1651 PowerShell 1 300 227 30 43 Python 143 14830 12217 797 1816 Shell 24 5924 4071 1457 396 Plain Text 4 3801 0 2479 1322 TOML 33 1485 1292 43 150 YAML 3 25 23 2 0 ───────────────────────────────────────────────────────────────────────────────── HTML 4 2687 2604 43 40 |- CSS 2 543 479 37 27 |- JavaScript 1 1233 1215 12 6 (Total) 4463 4298 92 73 ───────────────────────────────────────────────────────────────────────────────── Jupyter Notebooks 4 122 83 23 16 |- Markdown 1 60 30 22 8 |- Python 1 122 113 1 8 (Total) 304 226 46 32 ───────────────────────────────────────────────────────────────────────────────── Markdown 194 38699 0 29715 8984 |- BASH 71 1632 1192 324 116 |- C 3 17 17 0 0 |- CUDA 2 84 56 16 12 |- JSON 18 708 708 0 0 |- PowerShell 1 1 1 0 0 |- Python 23 1008 787 113 108 |- Rust 65 2048 1713 77 258 |- TOML 6 207 164 0 43 |- YAML 4 38 33 5 0 (Total) 44442 4671 30250 9521 ───────────────────────────────────────────────────────────────────────────────── Rust 663 313742 271458 14550 27734 |- Markdown 478 24544 471 21171 2902 (Total) 338286 271929 35721 30636 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Total 1284 461100 335289 76855 48956 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
|
Measurement methodology for ArcFlash's before/after, and the number that prices it. From tonight's profiler run on the H200 (PR #113,
Marginal cost of one more sequence in a decode step is 19.4 ms, and Please take the before/after the same way, so the two numbers are comparable:
Cells, spans and the exact numbers above are in PR #113. |
|
Your name-collision finding is fixed at the interface — PR #120, You were right to void the run, and right that the diagnosis didn't match: your What changed:
Recommended guard, replacing the let attn = profile.resolve_in("decode", "mla_attn")?; // never the prefill copy
assert_eq!(attn.verdict(), Verdict::Measured); // says WHICH zero if not
assert_eq!(attn.calls / decode_steps, 43); // engagement: one per layerI did not make the report prefer the decode node. Preferring one is still Also in #120: the device-timer fix onto Good call holding the rebuild until your current run finishes. The two-binaries |
…used # Conflicts: # mistralrs-core/src/attention/mod.rs
The name
Per
TAXONOMY.md's rule that no subsystem is left without an absolute parent:ArcAttention/Flashwas already taken and means the wrong thing — it is the capability envelope for Dao's FA2/FA3, a wrapper around someone else's kernel. Reusing "Flash" for ours would guarantee the two get conflated in exactly the claims that matter.ArcFlash/Cuteis named so rungs 3–6 have a home; no code claims it exists.What rung 0 does
Removes the two allocations that made long prompts fail rather than merely slow, at the two sites that performed the GQA expansion:
backends/sinks.rs— every DeepSeek-V4 layer, since head_dim 512 is outside the fused sinks kernel's{64,80,96,112,128,192,256}.run_attention_noflash—repeat_kvnow runs inside the cuBLASLt arm instead of ahead of all three paths.ArcFlash/Fold expresses the expansion as a reshape.
repeat_kvmapsx[b,kv,s,d] → y[b, kv*n_rep + rep, s, d]— heads are kv-major — so a contiguousq[B,H,Tq,D]reshapes to[B,Hkv,g*Tq,D]with no data movement, and both GEMM operands then carry batchB*Hkv. Both facts checked against the pinned candle (aeonmindai/candle@c3bb5bf), not recalled:reshapeis a view when contiguous, andbroadcast_matmulis not an alternative because candle concretises the broadcast operand (its own// TODO: Avoid concretising the broadcasted matrixes). The trick is already in-tree att_q == 1(absorbed_mqa_decode); this generalises it to anyt_qand any GQA ratio.ArcFlash/Tile bounds the score matrix to one query tile (
ARC_FLASH_TILE_BYTES, default 32 MiB). Tiling query rows is exact, not an approximation: each output row is an independent softmax, so there is no online rescaling, and sinks — a per-head constant in each row's denominator — are untouched.Numbers, labelled
ARITHMETIC (not measured). One layer at V4 prefill,
B=1 H=64 D=512 T=1400 bf16:≈8.3×, pinned by a test that also refuses to pass if the shape does not actually tile.
MEASURED (CPU only — D14): 386
mistralrs-corelib tests green, including the 17 pre-existingdsv4_attentiontests, which now execute through ArcFlash.NOT MEASURED: every GPU number. No wall-clock, VRAM or tok/s claim is made here.
D18 — engagement asserted, both directions
note()logsArcAttention: first dispatch on <path>once per path: present in the arm that uses it, absent in the arm that does not. The test instrument is a#[cfg(test)]thread-local rather than the process-wide atomics, becausecargo testruns test fns in parallel and a control arm would otherwise read other tests' dispatches — that was a real failure during development, not a hypothetical.Mutations — four applied, four caught
fold_matches_repeat_kv_across_gqa_ratios(diff 1.5)query_tiling_is_exact_and_the_mask_follows_the_tileThe third matters most: the existing V4 suite genuinely covers this path, so ArcFlash is not tested only by its own author's tests.
What this does NOT do
candle-flash-attn-v3has two specific defects — NULLtile_count_semaphoreon dense causal, and a window clamp that rewritescausalto full attention on varlen causal (Fix causal attention in candle-flash-attn-v3: NULL tile_count_semaphore crash (dense) + silently non-causal varlen huggingface/candle#3606). Both live inaeonmindai/candle, a different repository, so they cannot be fixed from this branch.fa3_preferred()is already the single switch.For main to run
arc-tools/arcflash/rung0_gpu_validate.sh— gates on compiling the CUDA-cfg'd Rust that a macOScargo checkcannot reach, then measures ~200-word and ~1055-word prompts and checks D18 in both directions. NeedsARC_V4_MODELandARC_GQA_MODEL.Surfaced, not shipped
dsv4_attention.rsbuildsk_catandv_catwith two identicalTensor::catcalls despiteV == Kbeing a V4 invariant — a full redundant copy of the union per layer per step.chunked_attentionnarrows a rank-4 mask on dim 2 unconditionally; a mask that is size-1 on the query axis would be mis-selected. ArcFlash'snarrow_mask_rowsguards this; the older helper does not.