Repository navigation
Conversation
…nd six shuffles per block (STRATA_QSA_ROWS=1, opt-in, bitwise); RTX 2080 Ti 101 -> 55 us a call at T=4, decode +3.2/+0.1% on a 131k layer split In a 131k decode block_scores_multi_kernel costs ~20 us more per call for every row of the verify window: not the keys (read once for all the queries) but the shared-memory and shuffle pipes, 4 x LDS.128 of the query slices and 20 shuffles per (block, query). block_scores_rows_kernel<NQ> keeps the NQ <= 4 queries' slices in registers and reduces the four heads' lane products with a scatter that keeps warp_sum's pairings (xor 16 and 8 leave one head per lane, then 4, 2, 1): every addition adds the same two operands of the same level, so scores and top-k ids are bitwise the multi kernel's. qsa_rows_bench measures the window's QSA kernels row by row and, with --rows, checks the parity (16 cases per card, 0 differ) and prints both kernels' microseconds: 2080 Ti 47/57/78/101 -> 36/38/49/55 us at T 1-4, 3060 73/109/152/194 -> 63/76/98/130. docs/QSAROWS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@Niko1221 Companion to #2058, independent of it. STRATA_QSA_ROWS=1 computes the decode window's QSA block scores (up to 4 queries) with the queries' slices in registers and six shuffles per block instead of twenty, keeping warp_sum's pairings so scores and top-k ids are bit-exact (qsa_rows_bench --rows, memcmp, 16 cases on sm_75 and sm_86). On the 2080 Ti the call goes from 101 to 55 us at T=4; end to end on our forced 131k bench +3.2% / +0.1% over two B arms, text unchanged. The prompt path and HIP are untouched (#1825's territory). Ported and re-checked on v0.1.43. Off by default; glad to refine whatever you would like changed. |
|
Thanks. Ported as an opt-in (STRATA_QSA_ROWS=1), text identical in our gate. On an RTX 3060 and an RTX A4000 it is level with the default (0.997 and 1.003 at 30K context), so the gain you measured is specific to the 2080 Ti. We keep it off by default. |
|
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).
Summary
STRATA_QSA_ROWS=1(opt-in, off by default) computes the verify window's QSA block scores (decode, up to 4 queries)with a kernel that keeps the queries' slices in registers and reduces the four heads with six shuffles per block instead
of twenty. Scores and top-k ids are bit for bit the multi kernel's (
qsa_rows_bench --rows,memcmp, 16 cases percard). CUDA only; the prompt path (#1825's territory) and HIP are not touched.
Why
In a 131k decode the QSA kernel that grows most with the window's rows is
block_scores_multi_kernel: ~20 us more percall for every row of the window on both an RTX 2080 Ti and an RTX 3060 (nsys, 8 QSA layers on the second card of a
layer split). The keys are already read once for all the queries; the cost per row is in the shared-memory and
shuffle pipes - per (key block, query) 4 x
LDS.128of the query slices and 5 shuffles per head (20 per block andquery), at 32,769 blocks ~15-20 us of issue per query.
What changed
src/kernels/cuda/qsa_select.cu:block_scores_rows_kernel<NQ>(NQ = 1..4): the NQ queries' slices (4 heads x 4floats per lane) in registers for the whole kernel (44 / 63 / 78 / 94 registers, no stack); the four heads' lane
products reduced with a scatter that keeps
warp_sum's pairings (xor 16 and 8 leave one head per lane, then 4, 2, 1)and gathered on lane 0 in head order. Tail block and the
+1e9as before.qsa_block_scorestakes it for thecalls without
active_blockswith up to 4 queries whenSTRATA_QSA_ROWS=1; otherwise, or beyond 4 queries, themulti kernel runs as before.
include/strata/kernels/qsa_select.hpp: therowsentry.src/kernels/qsa_rows_bench.cpp(EXCLUDE_FROM_ALL): what the T rows of a verification window cost in a QSA layer'sdecode kernels at a long context (block scores, top-k, attention over each row's selection, indexer append;
synthetic data at the real geometry, int8 pools, no model);
--rowsruns the new kernel against the multi kernel,scores and top-k ids bit for bit at T = 1..4 at 131k and at a short context with a full tail block, and prints both
kernels' microseconds.
docs/QSAROWS.md.Bit for bit
Every addition in the new reduction adds the same two operands of the same
warp_sumlevel (float addition commutes),the product expression is the same text in the same file, the relus are summed in head order.
qsa_rows_bench --rows:8 cases per card (T 1-4 x two contexts), 0 differ, on sm_75 and sm_86. In the engine the greedy text and the drafter's
acceptance are unchanged.
Measurements
Hardware: 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 pack, 131k context,
--max-context 262144 --kv int8.qsa_block_scores, us per call at 131k (both kernels read the same pooled keys):STRATA_QSA_ROWS=1STRATA_QSA_ROWS=1In the engine (nsys): per window the second card saves 0.09 ms at T=1 and 0.37 ms at T=4 (8 QSA layers), the first
0.04 / 0.25 ms (4 layers). End to end, deterministic 131k bench (forced tokens and window sizes, 1024 decode tokens,
three interleaved runs lever on / off / on): +3.2% and +0.1% decode tokens/s in the two B arms, text identical.
Together with the companion experts lever (
STRATA_EXPDEC=1, separate PR): +2.9%.Ported and validated on v0.1.43 (micro-bench bit-exact on both cards; our full stack on 0.1.43 matches our 0.1.42
daily on the forced 131k bench).
Risks / limits
STRATA_QSA_ROWSmust be exactly1. Only the decode calls with <= 4 queries and noactive_blockschange; everything else runs the kernels it ran before.
if that card matters more.
Scope. The gain comes from VRAM-resident routed experts / decode QSA scores on Turing/Ampere setups where these kernels are a large share of the verify window. On rigs where most routed experts are off-GPU (e.g. 4x RTX 5080 16 GB, see the test in #2058) the window is dominated by stage hand-offs and host experts, and the levers measure neutral.