Repository navigation
QSA decode attention: PR #540's two-cells-per-step chunk kernel on every CUDA card and a bounded merge (STRATA_ATTN_DAILY=1, opt-in, bit-exact) - #2075
Conversation
…el on every CUDA card and a bounded merge (STRATA_ATTN_DAILY=1, opt-in, bit-exact); parity harness attn_chunk_kernel_pre75 (PR Niko1221#540 by sskver: two cells per step with a 12-shuffle reduction, cell-major probabilities, V loaded four at a time) is compiled in every CUDA build, not only with STRATA_EXPERIMENTAL_SM60, and STRATA_ATTN_DAILY=1 selects it on any card for the decode attention (single query and batch: verify window and MTP drafter) together with attn_merge_v2_kernel (Hardin22), a merge that skips the chunks the chunk kernel marks empty. Bit for bit with the default kernels by construction: reduce12 adds the same pairs as warp_sum's butterfly at every level, the V cells fold in the same order with the same fmaf, the masked cells stay out; the merge does the same fmaf in the same order. Shared memory 15,872 B like the default kernel (spt shares sq's storage). STRATA_ATTN_MERGE_V2=0/1 and STRATA_ATTN_PRE75=0 switch the two halves separately. HIP unchanged. qsa_merge_daily_parity (tests): memcmp of both kernels against the default ones on four KV formats, widths at the chunk borders and non-resident pages; --bench times the chunk kernels back to back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rita' 1168/0 e bench Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Hardware: 2x RTX 3090 24 GB (NVLink bridge), Ryzen 9 3950X (AVX2, no AVX-512), 121 GB RAM, PCIe 4.0 x8 per card. Qwen3.8-Flash-Next unsloth UD-Q4_K_XL, What we compared: the same stack build with Answers: word-for-word identical with the flag on, against a stock v0.1.43.1 reference — our exactness gate is 10 greedy prompts, a 20K long gate, an image prompt and a 10-question verifiable probe; all clean. Decode (flashbench medians, greedy; the flag-on arm also had #1937's
That is +4–7 % greedy at every context. Sampled rows: 118.4 / 124.1 / 110.9 / 109.2 → 124.5 / 123.2 / 119.3 / 110.6 (+5 % at 1K and 32K, flat at 8K). Second box, different class (IQ3_XXS, |
…e pushed to fork svgop/Strata branch master (no force, SHAs preserved); identity fixed to GitHub attribution; API-key-in-history flagged (loopback-only, left); upstream PR plan banked (P1-P7 tiers, Niko1221#2075 coordination)
|
Thanks. Ported as an opt-in (STRATA_ATTN_DAILY=1). Text is identical to the default in our gate on sm_86 and on the Pascal build. Decode at a 30K context: +3.2% on an RTX 3060 (5 of 5 pairs), +0.7% on an RTX A4000. We keep it off by default for now because one tester saw a changed answer on a 5060 Ti; if you or they can send that prompt we will look. |
…'s two-cells-per-step chunk kernel on every CUDA card (STRATA_ATTN_DAILY=1) + Hardin22 bounded/batched merge; bit-exact by construction, parity harness run on our 5090: 1172 cases x 4 KV formats, 0 differ; ABAB 3v3 ADOPTED: M1 +6.0 / pair +7.0 / conc +5.3 vs same-hour ctl (all clear the +4% bar; first simultaneous all-lane adoption)
|
The 5060 Ti tester is us — that row is ours from 10-14. Happy to hand over the details, and the switch is already in our The box. 2× RTX 5060 Ti 16 GB (sm_120, layer split, second card at PCIe x8), Ryzen 7 3700X (Zen 2, no AVX-512), What we ran. The same stack built with The result. With the flag on,
What we can send you. The exact And an offer, because 0.1.45 makes it clean. Now that the switch is upstream, we can run the confounder out of it: One question while we are at it: the bounded merge skips empty chunks — is the threshold that decides that — Andy (q8atnight), 2× RTX 3090 (NVLink, peer tier) + 2× RTX 5060 Ti (layer split) |
|
Thanks for the pull request. Your change is already in If part of your work did not make it in and you want it considered, open a new pull request on top of |
Title
Issue: none (an opt-in speed change, bit-exact).
Summary
STRATA_ATTN_DAILY=1(opt-in, off by default) runs the QSA layers' decode attention - the verify window's and the MTPdrafter's, single query and batch - through PR #540's chunk kernel (
attn_chunk_kernel_pre75: two cells per stepwith a 12-shuffle reduction, cell-major probabilities, V loaded four at a time) on every CUDA card, and merges the
chunks with
attn_merge_v2_kernel, a merge that skips the chunks the chunk kernel marked empty. Upstream compiles thepre75 kernel only with
STRATA_EXPERIMENTAL_SM60and picks it below sm_75; here it is compiled in every CUDA buildand selected by the variable. The output is bit for bit the default kernels' (see below). HIP is untouched.
Why
The default
attn_chunk_kernelreduces each cell with 5warp_sumshuffles per head (60 per cell pair); the pre75body does two cells per step with
reduce12(16 shuffles) and reads the V rows four at a time. nsys on an RTX 3060(stage 0 of a layer split, 131K context):
attn_chunk_kernel99.8 us a call against 46.4 us with the pre75body; the same ratio on an RTX 2080 Ti. The decode attention is ~8% of the per-row cost of a window at 131K on these
cards, so the end-to-end gain is small but free.
What changed
src/kernels/cuda/qsa_decode_attn.cu:attn_chunk_kernel_pre75<M, NC, ...>compiled in every CUDA build;daily_attn()readsSTRATA_ATTN_DAILY; the kernel choiceSTRATA_ATTN_CHUNK_SEL(M, PRE)takes it on any cardwhen set (below sm_75 in an experimental build as before).
attn_merge_v2_kernelwith the chunk-empty marks;STRATA_ATTN_MERGE_V2=0|1forces the merge alone,STRATA_ATTN_PRE75=0turns the chunk kernel off (A/B).sptsharessq's shared memory, so the kernel uses 15,872 B like the default one (68-78 registers against 37-41,256 threads a block).
include/strata/kernels/qsa_decode_attn.hpp: the selection helpers.src/kernels/qsa_merge_daily_parity.cpp(tests): memcmp of the chunk kernel and the merge against upstream's onfour KV formats, widths at the chunk borders and non-resident pages;
--benchtimes the two chunk kernels back toback. Registered as ctest
qsa_merge_daily_parity_defaultand_daily.CMakeLists.txt: the harness.Bit for bit
reduce12adds at every level the same two pairs aswarp_sum's butterfly (xor 16, 8, 4, 2, 1; float additioncommutes), the V cells fold in the same cell order with the same
fmaf, the masked cells stay excluded; the merge v2does the same
fmafin the same order and skips exactly the chunks the chunk kernel marks empty.qsa_merge_daily_parityon an RTX 2080 Ti (v0.1.43 build, tests on): 1,168 cases, 0 differ (fp16 290, int8 291, q4_0 294, k8v4 293; 21,190,308 nonzero output values), withSTRATA_ATTN_DAILYunset and=1. In the engine the greedy text and the drafter's acceptance are unchanged (deterministic131K bench, forced tokens and windows).
Measurements
RTX 2080 Ti 22 GB (sm_75) + RTX 3060 12 GB (sm_86), Windows 11, CUDA 12.6, layer split, Qwen3.8-Flash-Next IQ3_XXS,
131K context,
--kv int8.qsa_merge_daily_parity --benchon the RTX 2080 Ti (CUDA events, 200 calls per arm, B-A-B: Daily kernel, upstreamkernel, Daily kernel again; int8 KV, 32,768-cell capacity, window of n_q queries):
fp16, q4_0 and k8v4 KV show the same ratios (0.57-0.63 for the chunk kernel, 0.24-0.51 for the merge). In the engine
(nsys, RTX 3060, 131K context)
attn_chunk_kernelwent from 99.8 us to 46.4 us a call.End to end it is part of a stack that matches its reference within noise; the attention alone is ~8% of the per-row
cost, so no separate end-to-end claim is made here.
Built and started on v0.1.43 with
STRATA_ATTN_DAILY=1(RTX 2080 Ti + RTX 3060 layer split, Windows): the engine serves as before, same answer.Risks / limits
Opt-in: nothing changes with the variable unset. The kernel body is PR #540's (sskver) and the merge is Hardin22's
attn_merge_v2_kernel, both carried in this fork since 0.1.40 and credited in the source. #1888 (split attention onthe int8 mma path, sm_80+) is a different kernel and not bit-exact; the two do not overlap (this one serves Turing).
Part of a series from a public patch registry (
stack/in the fork imanu86/Strata-2080Ti).