A native exact-attention engine built around streaming online softmax and a trace-driven hierarchical compiler.
StreamAttn owns its attention kernels. Its main serving goal is exact inference over the full logical KV cache; FlashInfer and FlashAttention are comparison baselines, not dependencies of the native path. Reduced-work routes remain a separate, explicitly calibrated research branch and fail closed to exact attention when their policy contract does not match.
The common foundation is single-pass streaming attention with online softmax: K/V tiles are consumed once, numerically stable running statistics are updated on the fly, and the full attention matrix is never materialized.
Project status: research engine with promoted H100 routes, guarded contiguous A100 D64 routes plus one cross-provider D128 cell, a complete A100 paged-D128 routing profile, and partial H100/B200 phase databases. StreamAttn has apples-to-apples exact decode wins over FlashInfer on promoted Hopper and Ampere cells, plus a measured model-level Qwen decode win on a validated request tier. The A100 paged-D128 profile still selects exact external fallback. StreamAttn is not yet a universal replacement for FlashInfer, FlashAttention, or a full serving runtime.
Fast exact kernels answer this question:
How efficiently can the GPU compute all requested attention work?
StreamAttn also asks:
What is the cheapest native attention route that is valid for this request?
That produces three serving modes plus an explicit adaptive research route:
| Mode | Work performed | Semantics | Current use |
|---|---|---|---|
exact_native |
All KV tokens | Exact attention, within numerical tolerance | Default and fail-closed route |
seed_only_native |
A small sink/middle/recent seed set | Approximate; only for a packaged, validated policy cell | Explicit opt-in and calibrated serving |
verified_auto |
Seed-only when policy invariants match, otherwise exact | Policy-verified, fail-closed routing | Default planning mode; live generic verification is still research |
| query-selected paged | Sink/recent atoms plus query-ranked middle atoms | Exact online softmax over a runtime-selected subset | Explicit StreamAttnEngine.plan_query_selected_paged(...) research route |
StreamAttn is therefore not just another sparse mask. The engine owns the kernel, policy artifact, fixed-buffer plan, route decision, and exact fallback.
The engine is organized around the attention work, not around one model or one kernel. Public execution currently lowers through three explicit layers:
AttentionProblem
semantic guarantee, Q/KV geometry, dtype, mask, cache kind
AttentionTilePlan
logical KV source + the tiles that are legal to execute
AttentionBackendPlan
architecture-specific kernel, splits, and workspace
This gives exact and reduced-work attention one semantic contract:
exact contiguous -> all logical tiles, contiguous mapping
exact paged -> all logical tiles, page-table mapping
validated fixed -> calibrated logical tile subset
adaptive -> runtime-selected logical tile subset (research)
sliding window -> bounded logical tile range (planned)
The runtime executes contiguous selected schedules and contiguous or paged
exact schedules. Selected paged work compiles into a device CSR schedule and
page-native PackedRoute64 metadata without copying K/V. H100 now executes
those records directly with the same transposed WGMMA and online-softmax
mainloop used by exact paged decode. The same planner now describes exact
decode, prefill, and differentiable training calls. Future adaptive,
compressed, and device backends therefore do not need a second semantic API
or a second online-softmax model. See the universal tile
planner and the selected paged
route ABI.
The promoted SM90 kernels compute full-context GQA decode and use online softmax plus exact split-state merging. Contiguous and page-64 results below use FlashInfer 0.6.12; page-16 was re-gated against FlashInfer 0.6.17 on H100:
| Shape family | Measured region | StreamAttn speedup | Status |
|---|---|---|---|
| Contiguous D64, GQA group 8 | A100 40GB; B1-B8; 16K-64K KV | 1.067x-1.477x |
Promoted per cell |
| Contiguous D64, GQA group 4 | A100 40GB; B4/32K KV | 1.070x |
Promoted per cell |
| Contiguous D128, GQA group 8 | A100 SXM4 40GB/80GB; B4/16K KV | 1.006x worst paired extension trial; 1.010x-1.014x production-plan medians |
Promoted discrete cell |
| D64, GQA group 8 | 7 cells; B2-B8; 16K-64K KV | 1.025x-1.432x |
Promoted per cell |
| D64, GQA group 4 | 14 cells; B1-B16; 16K-64K KV | 1.027x-1.449x |
Promoted per cell |
| D128, GQA group 4 | 6 cells; B4-B16; 16K-64K KV | 1.002x-1.012x |
Promoted per cell |
| Paged D64, GQA group 8 | HND/page-64; B1-B8; 16K-64K KV | 1.21x-2.24x paired median |
Promoted per cell |
| Paged D64, GQA group 8 | HND/page-16 full rows; B1-B8; 16K-64K capacity | 1.21x-2.07x paired median |
Promoted per cell |
| Paged D64, GQA group 8 | HND/page-16 ragged rows; same capacity matrix | 1.17x worst paired trial; 2.04x median cell |
Promoted per cell |
| Paged D128, GQA group 8 | HND/page-16; B1-B8; 16K-64K; full and ragged | 1.075x worst paired trial; 1.75x median auto-gate cell |
Promoted per cell |
| Paged D128, GQA group 8 | NHD/page-16; B1-B8; 16K-64K; full and ragged | 1.058x worst paired trial; 1.283x median auto-gate cell |
Promoted per cell |
| Paged D128, GQA group 4 | HND/page-16; B1-B8; 16K-64K; full and ragged | 1.017x worst paired trial; 1.34x median cell |
Promoted per cell |
| Paged D128, GQA group 8 | A100/HND and NHD/page-16; B1-B8, 16K-64K exploratory matrix | 6/12 discovery-process wins per layout; strict B1/32K/HND 0.949x |
Segmented exact merge is correct; fast-SXM route remains external fallback |
| Paged D128, GQA group 8 | B200/NHD/page-16; six B1-B8, 32K/64K full-row cells | 1.144x-1.441x initial confirmation; 1.122x worst paired trial |
Promoted per cell |
The exact backend uses transposed WGMMA so that long context occupies the hardware-friendly matrix dimension:
context tokens -> WGMMA M
query heads -> WGMMA N
head dimension -> WGMMA K reduction
See the measured phase diagrams for the actual promoted cells:
- D64/G8 H100 phase diagram
- D64/G4 H100 phase diagram
- D128/G4 H100 phase diagram
- Paged D64/D128 H100 phase diagram
- Paged exact SM80/SM90/SM100 architecture phase
- SM80 segmented exact merge and falsification boundary
- Contiguous D64 A100 phase diagram
- Contiguous D128 A100 register-resident pipeline
- Native B200 exact backend and promotion boundary
The promoted A100 D64 path is a separate architecture-native family. It reads
standard [B,Hq,D] queries and writes [B,Hq,D] output directly, stages K/V
with cp.async, assigns four producer warps per CTA, and merges exact online-
softmax states hierarchically. Its production plan preallocates all workspace;
the B4/G8/32K allocation-free canary measured 63.155 us against FlashInfer
0.6.13 at 73.020 us, with both paths at 1.22e-4 BF16 max error. The
ThunderKittens headers are optional; set STREAMATTN_TK_ROOT to a tree
containing include/kittens.cuh, otherwise the dispatcher fails closed to an
existing exact path.
The promoted A100 D128 cell uses a different shared-memory lifetime. Four
producer warps load each current K/V pair into registers, asynchronously replace
the shared slots with the next pair while QK, online softmax, and PV execute, and
reuse K storage for the final partial output. The real ExactDecodePlan.run()
path passed 15/15 paired trials at B4/G8/16K on both A100 SXM4 40GB and 80GB.
All other A100 D128 cells still fail closed to exact fallback.
The H100 selected-paged backend consumes PackedRoute64 records directly from
page-16 NHD or HND caches. One producer CTA evaluates one selected 64-token
record, applies per-page Q-head and token masks before softmax, and emits an
exact online-softmax partial state. A static row merge produces the final
output. K/V data is never gathered or repacked.
Measured against the fastest tested FlashInfer exact decode backend at NHD/page-16, BF16, D128/G8, 32K:
| Route | B1 | B4 | B8 | Paired evidence |
|---|---|---|---|---|
| 384 selected tokens | 2.67x |
5.16x |
8.25x |
Independent confirmation; 45/45 wins |
| 2,048 selected tokens | 2.76x |
5.08x |
7.18x |
Independent confirmation; 45/45 wins |
| 8,192 selected tokens | 2.06x |
2.84x |
2.32x |
Initial phase; 21/21 wins |
| 16,384 selected tokens | 1.69x |
1.36x |
1.36x |
Initial phase; 21/21 wins |
| Full 32K control | unstable | 0.78x |
0.75x |
Route to the exact split scheduler |
All 15 phase cells matched an independent FP32 selected-token reference. A
Q-head-private 384-token schedule with only 0.545 GQA union efficiency also
won all 27/27 paired trials (2.44x, 5.21x, and 8.20x at B1/B4/B8).
These are kernel/runtime results for a precomputed selected schedule.
StreamAttn also has a no-sync dynamic route compiler for mutable GPU Q-head
CSR atoms. It builds a bounded on-chip atom/head membership map, compacts the
GQA union with warp ballots, resolves live page IDs, and launches the selected
WGMMA executor without a host route-count readback. At the same 32K D128/G8
shape, route preparation fell from 1.532-3.003 ms in the generic Torch
lowering to 0.01098-0.01362 ms on GPU.
Including dynamic preparation and execution, all 18 B1/B4/B8 x S384/S2048 x
shared/alternating/disjoint cells were correct and won paired per-call trials
against FlashInfer exact (1.112x-5.276x). A 400-call amortized measurement
won 15/18 cells; every S384 cell won, while three low-batch S2048 corners remain
exact-fallback territory. See the dynamic H100 route-compiler
phase.
The next phase connects a real GPU query selector directly to that mutable CSR. Persistent per-64-token support keys are scored against the live query; a fixed-width top-k kernel emits score-ranked Q-head atoms; the membership compiler canonicalizes their GQA union without a sort or host readback. The complete measurement includes selection, route lowering, page resolution, attention, and merge:
| Support sketch | B1 | B4 | B8 | Selection-quality signal |
|---|---|---|---|---|
| P1/P2/P4 centroid + extremes, S384 | 0.55x-0.57x |
1.12x-1.14x |
1.69x-1.70x |
P4 synthetic block-max recall: 15%-21% |
| P8 centroid + extremes, S384 | not promoted | 0.997x |
1.535x |
synthetic block-max recall: 33%-36% |
All 13 measured cells matched the independently lowered selected-token
reference. Every P1/P2/P4 B4/B8 cell won the seven paired block-timed trials;
B1 lost because the roughly 0.05 ms selector floor dominates. P8 buys more
oracle recall but consumes the B4 margin, so adaptive sketch width is required
rather than one global selector. Top-norm support keys were measured and
rejected: they did not improve recall and were slower. See the query-selected
H100 phase.
The runtime also supports a two-stage selector:
P4 support scan -> top-32 candidates -> exact 64-token block-max QK
-> final four middle atoms -> selected WGMMA attention
This path scans compact P4 metadata over 32K and exactly refines only 2,048
candidate tokens per Q head. At B8, an independent 15-trial confirmation won
15/15 paired trials against FlashInfer exact (1.056x median, 1.029x
worst), but the preceding phase won only 8/9 (0.985x worst). It therefore
remains a narrow experimental boundary. At B16, refine-8/16/32 all won 9/9;
refine-32 reached 1.619x paired median and 1.544x worst. All eight phase
cells matched the selected-token reference. Exact refinement improves the
ranking inside the proxy candidate set; it does not make the selected route
equivalent to full-context exact attention.
These query-selected results are systems evidence, not a model-safety promotion. Attention is exact over the selected atoms, but arbitrary runtime selection can change model outputs. Existing real-Qwen analysis shows that support sketches improve coverage while adversarial late-layer routes still need exact fallback or a stronger verifier. The measured cache is fixed at 32K; a growing production cache must finalize/update the support metadata when each new 64-token atom closes.
StreamAttn now has a reference frontier for a harder question: can selected
exact blocks plus a compact tail estimator preserve the post-o_proj output
without scanning the omitted KV tail? It merges exact online-softmax block
states with moment estimates or sampled control-variate corrections and keeps
physical routes shared within each true-GQA KV group.
Initial H100 captures were deliberately negative-to-mixed. Output-aware block
selection improves hard drop, while moment completion, fixed residual banks,
and stochastic ratio correction do not generalize reliably. The follow-up
predictability gate now uses the exact factorization
o = o_A + sigmoid(log(Z_U/Z_A)) * (o_U - o_A). Omitted normalization mass is
highly predictable, but the vector-valued innovation is not reliably
low-rank across prompts. Qwen L14/L26/L27 failed promotion. Mistral L0 retained
a 30.23% mean unseen-prompt error reduction, but its worst p95 row regressed
by 12.6%. A nested exact-canary follow-up ranked those failures from only
runtime-observable features: it accepted 18/64 unseen-prompt rows
(28.125%), accepted zero regressions, and achieved 0.942 risk AUC. The
worst accepted row still improved over hard drop (0.975x error). This is a
semantic canary pass, not a backend promotion: selection still uses the exact
QK oracle and predictor/summary maintenance cost is not yet positive. See the frontier
study and the
conditional predictability gate.
For calibrated Qwen-family cells, the seed-only backend reads a small set of
sink, middle, and recent KV blocks. A representative 32K policy uses 384 seed
tokens, or 1.17% of the full context. In true GQA, duplicating those reads
across query heads is still inexpensive when:
G * seed_tokens / kv_len << 1
For the original Qwen route, that ratio is about 8.2% of exact KV traffic.
The extra head-private work creates enough independent CTAs to occupy the GPU
while avoiding most of the exact QK, softmax, and PV work.
Measured complete-model results on H100:
| Route | Scope | Speedup | Distribution result | Status |
|---|---|---|---|---|
| Qwen2.5-3B fast path | 32K, B8, validated request suite, 32 decode steps | 1.193x |
Zero top-1/sample changes; KL max 9.96e-05 |
Candidate |
Qwen2.5-3B verified_auto |
32K, B8, validated suite, 128 decode steps | 1.157x |
Zero top-1/sample changes; strict gates pass | Research candidate; offline canary |
These rows compare complete model decode against the dense Hugging Face model, not just selected attention calls. Adversarial stress and unknown request tiers remain exact. The 128-step verifier currently uses an offline-calibrated trigger schedule, so it is evidence for the design rather than a general live verifier.
- StreamAttn is not universally faster than FlashInfer on every exact shape.
- Seed-only speedups are not exact-kernel speedups; they come from validated work avoidance.
- A100 promotion is limited to contiguous head-major BF16 D64 G4/G8 cells and
the discrete contiguous D128 B4/G8/16K cell. Tested D128 32K, G4, and B8 cells
remain on exact fallback. Native HND/NHD page-16 D128/G8 is correct, but its
strict HND gate resolves
to
0.060416 msversus a0.057344 msFlashInfer FA2 floor, so the complete seven-cell paged-D128 database still emits exact external fallbacks. No A100 FP8 claim has been promoted. - B200 promotion is narrow: BF16, direct NHD page-16, D128/G8, full fixed rows, and six measured B/N cells only. B1/64K and B8/64K did not clear the paired gate and remain on exact fallback. This is not a universal Blackwell claim.
- H100 paged exact promotion covers measured D64/G8 and D128/G4/G8 HND cells plus D128/G8 NHD cells at 16K/32K/64K. Page-16 supports exact variable-length rows; page-64 is D64/G8-only and still requires full fixed-length rows.
- The repository does not currently claim a direct universal win over FlashAttention training kernels.
StreamAttn requires Python 3.10+ and PyTorch. Triton is optional for CPU use but required for the native CUDA paths.
git clone https://github.com/MagellaX/StreamAttn.git
cd StreamAttn
# Development install
python -m pip install -e ".[dev]"
# Native Triton kernels on supported Linux/x86-64 systems
python -m pip install -e ".[triton]"
# Optional Hugging Face helpers
python -m pip install -e ".[hf]"The package is currently a portable py3-none-any wheel. GPU kernels are
compiled for the installed device at runtime, so separate A100/H100/B200 Python
wheels are not needed.
Decode tensors use [batch, sequence, heads, head_dim]. For autoregressive
decode the query sequence is normally one token.
import torch
import stream_attention as stream_attn
device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.bfloat16 if device == "cuda" else torch.float32
q = torch.randn(4, 1, 16, 64, device=device, dtype=dtype)
k_cache = torch.randn(4, 32768, 2, 64, device=device, dtype=dtype)
v_cache = torch.randn_like(k_cache)
output, info = stream_attn.decode(
q,
k_cache,
v_cache,
mode="exact_native",
)
print(output.shape)
print(info.backend_used)On an unsupported native CUDA shape, the exact path uses the safe exact implementation available in the installed environment. Promoted serving cells are always explicit; StreamAttn does not infer a performance claim from a successful launch.
Paged decode accepts physical NHD or HND pages and a per-request block table. The native kernels resolve logical tokens to physical pages inside the online-softmax loop; they do not gather pages into a contiguous cache. The promoted H100 page-16 specializations accept HND, plus direct NHD for D128/G8. Page-64 maps HND directly to one transposed-GQA WGMMA tile. Page-16 loads four physical pages directly into the same 64-token shared tile without a gather buffer; NHD changes only the producer's token stride, not the WGMMA consumer.
import torch
import stream_attention as stream_attn
q = torch.randn(4, 1, 16, 64, device="cuda", dtype=torch.bfloat16)
k_pages = torch.randn(8192, 2, 16, 64, device="cuda", dtype=torch.bfloat16)
v_pages = torch.randn_like(k_pages)
page_table = torch.arange(
8192, device="cuda", dtype=torch.int32
).view(4, 2048)
sequence_lengths = torch.full(
(4,), 32768, device="cuda", dtype=torch.int32
)
cache = stream_attn.PagedKVCache(
key=k_pages,
value=v_pages,
page_table=page_table,
sequence_lengths=sequence_lengths,
layout="HND",
)
plan = stream_attn.StreamAttnEngine().plan(
q,
cache,
mode="exact_native",
)
output, info = plan.run()The page table may be updated in place between steps while preserving its
validated shape and bounds. The promoted page-16 WGMMA plan accepts positive
per-request lengths, masks the final 64-token compute tile exactly, and ignores
inactive -1 table slots. Page-64 WGMMA still requires full planned lengths;
unsupported shapes use the generic exact paged backend. Both paths are
allocation-free after planning.
The same page-16 API also promotes D128 BF16 cells with GQA group sizes four and eight. D128 reuses each shared-memory stage for V only after its K tile has been consumed, keeping the two-phase pipeline inside Hopper's shared-memory budget without gathering pages.
Stable serving loops should validate shapes and policy once, then reuse the same Q/K/V and output buffers:
import torch
from stream_attention import StreamAttnEngine
q = torch.randn(4, 1, 14, 64, device="cuda", dtype=torch.float16)
k_cache = torch.randn(4, 32768, 2, 64, device="cuda", dtype=torch.float16)
v_cache = torch.randn_like(k_cache)
engine = StreamAttnEngine(
policy_name="qwen25_05b_l8_32k_seed_only_batched",
model_id="Qwen/Qwen2.5-0.5B-Instruct",
layer_id=8,
)
plan = engine.plan(
q,
k_cache,
v_cache,
mode="verified_auto",
)
# Update q/k_cache/v_cache contents in place between decode steps.
output, info = plan.run()
print(info.backend_used, plan.reason)verified_auto selects seed-only only when model, layer, dtype, batch, KV
bucket, GQA shape, device, and policy constraints match. Otherwise it executes
exact attention. seed_only_native is the strict explicit mode and raises when
the requested seed route cannot be planned.
The public engine surface covers all three attention phases. Prefill and training use exact all-tile schedules and the fused online-softmax forward/backward when the native Triton path supports the call. Unsupported devices or features use PyTorch SDPA without changing the public tensor layout:
import torch
import stream_attention as stream_attn
q = torch.randn(2, 1024, 8, 64, device="cuda", dtype=torch.float16,
requires_grad=True)
k = torch.randn(2, 1024, 2, 64, device="cuda", dtype=torch.float16,
requires_grad=True)
v = torch.randn_like(k)
prefill_output, prefill_info = stream_attn.prefill(
q.detach(), k.detach(), v.detach(), causal=True, return_info=True
)
output = stream_attn.train(q, k, v, causal=True)
output.square().mean().backward()Both calls use [batch, sequence, heads, head_dim] tensors and lower through
AttentionProblem -> AttentionTilePlan -> AttentionBackendPlan. The native
CUDA path accepts compact GQA K/V tensors: each query head maps to its KV head
inside the forward and backward kernels, so native execution does not
materialize repeated KV heads. CPU and unsupported-shape fallback explicitly
report torch_sdpa_gqa_expanded when they must expand GQA for SDPA.
The underlying Triton path supports boolean/additive masks, deterministic
Philox dropout, ALiBi, and a streaming backward pass. Training calls with a
feature combination that is not natively lowered use the exact SDPA fallback.
stream_attn.train(...) computes differentiable attention; optimizer and model
training-loop ownership remain with the caller. H100/B200 correctness,
backward derivation, and the first performance phase diagram are recorded in
unified prefill and training
attention. The compact lowering is
a correctness/generalization milestone, not yet a promoted performance path:
its Q-head-owned programs reload shared K/V for every GQA query head and its
backward atomically merges those contributions. FlashAttention-class SDPA is
still faster across the measured prefill/training cells.
An experimental KV-group-owned forward floor now flattens multiple query heads
into one program's row tile and reuses compact K/V while maintaining independent
FP32 online-softmax states. It improves the first native forward by up to
4.85x on H100 and 2.72x on B200, but its best measured paired result is
still 0.89x of Flash SDPA. It is therefore not auto-routed. See the
grouped-GQA prefill floor.
A native Hopper follow-up replaced the Triton dot-product floor with natural
m64n64 WGMMA and tested both one and two consumer warpgroups sharing K/V.
All 12 H100 G4/G8 D128 cells were exact, but the two-consumer schedule reached
only 0.408x-0.551x of graph-captured Flash SDPA and was limited to one CTA/SM
by 223 registers per thread and 85,120 bytes of dynamic shared memory. It is a
recorded negative canary, not a production route. See the
SM90 grouped WGMMA study.
The execution-state follow-up found one reusable mechanism and closed three
topologies. Register/shared PV improved the serial attention epoch by
1.177x-1.494x over shared/shared PV. A fair producer-consumer TMA epoch,
however, reached only 0.810x-0.962x of the lean vectorized serial path; a
same-CTA two-consumer version spilled and reached 0.723x. Two-CTA TMA
multicast preserved 0.948x-0.978x of independent load throughput, but its
complete attention epoch still reached only 0.522x-0.712x of serial RS.
StreamAttn therefore retains RS-PV and the multicast transport primitive while
rejecting these producer-heavy attention schedules. See the SM90 RS-PV
execution-state study.
The resulting complete 128-thread consumer-owned kernel is the first positive
Hopper grouped-prefill result. It combines double-buffered cp.async K loads,
shared/shared QK WGMMA, exact FP32 online softmax, register/shared PV WGMMA, and
direct output/LSE writes. The compiled kernel uses 168 registers per thread,
65,536 bytes of dynamic shared memory, zero local memory, and allows three
CTAs/SM. All 30 tested H100 B1/B2/B4, G4/G8, S512-S8192 cells passed output and
sampled-LSE correctness. Eleven cells passed the strict paired performance gate:
B1 at G4 S4K/S8K and G8 S2K/S4K/S8K; B2 at G4/G8 S4K/S8K; and B4 at G4/G8
S8K. Their median speedups over graph-captured Flash SDPA range from 1.02x to
1.18x, while the new dataflow is roughly 1.69x-2.15x faster than the prior
complete shared/shared PV canary. These are phase-compiler candidates, not yet
public auto-routes; short and medium losing cells remain on exact fallback. See
SM90 consumer-owned RS-PV grouped
prefill.
For Blackwell, a separate architecture-native exact forward keeps compact GQA
K/V in BSHD layout and uses TMA,
tcgen05 MMA, TMEM accumulators, streaming online softmax, query-tile causal
truncation, and row masking on the diagonal tile. The original eager-only
comparison against forced PyTorch Flash SDPA measured:
| Batch / sequence | StreamAttn | Flash SDPA | Paired speedup |
|---|---|---|---|
| B1 / S64 | 0.00619 ms |
0.01020 ms |
1.65x |
| B1 / S128 | 0.00619 ms |
0.01072 ms |
1.73x |
| B1 / S256 | 0.01127 ms |
0.01384 ms |
1.22x |
| B1 / S384 | 0.01642 ms |
0.01853 ms |
1.13x |
| B2 / S64 | 0.00618 ms |
0.01037 ms |
1.68x |
That comparison includes the allocation/framework cost of eager SDPA. The new
strict phase-compiler calibration also tests allocation-free fixed-address CUDA
graph replay. On the four manifest cells B1/S256, B1/S384, B1/S512, and B2/S128,
the fastest TGV tile reached 0.902x, 0.869x, 0.636x, and 0.987x of the
fastest correct graph baseline. The compiler therefore keeps all four on an
external exact fallback and retains the native losses as optimization targets.
See native SM100 GQA prefill for the
kernel derivation and the strict calibration
for the stronger baseline result.
StreamAttn no longer treats isolated promotion dictionaries as the final engine
architecture. The first universal exact compiler contract is committed in
benchmarks/manifests/universal_exact_v1.yaml.
It freezes 30 valid cells instead of constructing an artificial Cartesian
product:
12 real workload cells
10 architecture and scheduler boundary cells
8 feature-interaction cells
SM80 + SM90 + SM100
decode + prefill + training
FP16 + BF16
D64 + D128 + D256
contiguous + paged, NHD + HND
The manifest publishes trace, stratified, and boundary weights; eligible
baselines; numerical tolerances; and compiler acceptance criteria. The physical
IR in stream_attention/exact_compiler.py records ownership, algebra
orientation, tile geometry, split strategy, load/MMA engine, accumulator space,
pipeline, scheduler, cluster, softmax, merge, and epilogue. Runtime B/M/N
remain in AttentionProblem so one compiled binary can cover many cells.
Guarantees are deliberately distinct:
exact full-context exact attention
schedule_exact exact arithmetic over an explicitly selected schedule
distribution_verified approximation validated at model-output level
Current implementations are registered as candidate families, including the
promoted SM90 decode and SM100 prefill kernels, the SM80 cp.async decode
kernel, generic native Triton, and an explicitly non-native external fallback.
The manifest exposes a native feature gap: deterministic-dropout training
currently requires an exact PyTorch math fallback.
This is compiler infrastructure, not a new overall performance claim. Inspect
the frozen surface with:
python benchmarks/inspect_universal_exact_manifest.pySee Universal Exact Phase Compiler v1 for the invariants and next compiler stages.
The next compiler layer is also available. GPU profilers write immutable
BackendEvidence records containing the requested and resolved backend,
environment fingerprint, correctness result, timing distribution, confidence,
workspace, supported range, and timed-allocation count. The phase compiler then:
requires an explicit outcome for every eligible baseline
prefers the fastest correct allocation-free baseline, then a correct allocating fallback
chooses native only when the fastest correct native candidate beats the baseline
otherwise emits an explicit external fallback and retains the native loss
retains failed, unsupported, slower, and losing measurements
computes regret against the fastest valid native-or-external route
writes SHA-indexed phase_db/sm80.json, sm90.json, and sm100.json
The SM80 database now resolves all seven declared cells with complete baseline
telemetry and zero routing regret. None is promoted native: D128 paged decode is
the closest at 0.949x of FlashInfer, while causal/noncausal prefill and
training remain larger kernel-family gaps. Deterministic dropout is exactly
resolved by PyTorch math SDPA, but its eager autograd path allocates, so the
architecture database correctly remains below compiler-v1 acceptance.
A baseline that was never attempted makes the cell unresolved; it cannot be
silently omitted. Current deterministic-dropout training gaps are emitted as
external_fallback, while an unmeasured native family is emitted as
native_unmeasured. Compile strict evidence with:
python benchmarks/compile_universal_exact_phase_db.py \
artifacts/exact/evidence.json \
--output-dir phase_dbSee Exact Phase Database v1 for the evidence schema and acceptance semantics. The first partial calibration is now compiled: four SM90 cells resolve to three native routes and one fallback; four SM100 cells resolve to external fallbacks against graph-captured baselines. The remaining cells stay visibly unresolved, so the repository still does not claim the 30-cell performance target. See the H100/B200 calibration report.
The next compiler contract models complete serving batches instead of extending
v1 into a larger cell list. AttentionBatchV2 represents heterogeneous request
phases, per-request Q/KV lengths, page tables, shared prefixes, speculative
trees, exact attention semantics, and graph/workspace constraints. Its workload
manifest composes immutable serving traces, stratified semantic coverage, and
generated regime boundaries.
The v2 compiler separates two decisions:
macro plan
unified persistent vs split phase vs query-length cohorts
physical lowering
architecture-native ownership, QK/PV operand paths,
producer/barrier topology, overlap, tiles, splits, and output mode
Calibration and holdout records receive stable hash-based assignments, so corpus growth cannot move tuned rows into the final evaluation set. Exact baseline resolution is also explicit: semantic compatibility is checked first, then only correctness-passed measurements at the matching backend revision and workload fingerprint can compete on latency.
The first SM90 v2 experiment now contains two exact candidate families for the
previously uncovered M=2-64 regime. Across 72 BF16 contiguous-HND H100 canary
cells, both passed the sampled numerical checks; choosing the faster family per cell measured a 1.342x
geometric mean over graph-captured Flash SDPA and won 53/72 paired cells. The
transposed family owns very small M, while 64-row query/GQA packing takes over
as KV reuse matters. M=64 remains below parity, and that initial canary timed
only Flash SDPA, so this is directional kernel and
compiler evidence rather than a promoted universal route.
The micro-prefill audit adds irregular query/KV lengths, larger batches and head counts, independent FP32 output/LSE checks, mutable-input CUDA graph replay, and separate producer/merge timing. External backends run in isolated workers with paired native controls, so conflicting FA3 imports cannot remove a competitor from the comparison. Balanced split intervals also fix a trailing out-of-bounds preload in the experimental natural family.
A wider 128-row candidate passed its first H100 numerical checks but was slower:
at B1/M64/N4K/G8/D128/C16, it took 49.46 us serial or 51.99 us with overlap,
versus 31.22 us for R64 and 19.94 us for Flash SDPA. It is not promoted.
The follow-up single-output-state R64 temporal schedule also passed its
sampled checks but lost at all three pipeline-depth/concurrency anchors. The
original R64 remains the control. The R128 dependency diagnostic recovered its
extra overlap penalty without fixing the larger widening loss. See the
experiment and evidence.
The isolated four-case baseline audit also resolves a stronger target:
standalone FA3 took 15.37 us at M64/D128 versus 31.10 us for the retained
R64 control in that worker. See the baseline audit.
The earlier 1.342x figure remains a per-cell oracle choice against Flash SDPA,
not a measured public dispatcher result or a win over every exact backend.
Both retained families now also run native FP16 and explicit-position causal attention. Two independent H100 runs passed 84/84 full-matrix cases and a 24/24-case replay, checking output and LSE against FP32 before and after graph-buffer mutations. This includes reordered keys, large logical positions, empty visibility rows, B1/B2, and both D64/D128. It is a functional expansion, not another speedup claim. See the contract and evidence.
The same two families now read paged, ragged KV directly, in either HND or NHD page-16 layout. Query lengths and KV lengths vary independently within a batch; graph replay can change page IDs, lengths and logical positions without gathering or repacking KV. The corrected H100 matrix passed 144/144 cases, plus 48/48 in an independent replay, including poisoned padding, shared prefix pages and empty requests. This closes a storage/semantics gap, not the M64 performance gap. Public dispatch is unchanged. See the paged plan and verification record.
The next test measured whole mixed-ragged batches, including query-layout and page-metadata conversion. All 48 full-run cases and 24 independent replay cases passed output/LSE checks, but performance did not generalize: even choosing the best native family per case reached only 0.23x with padded queries and 0.16x with packed queries against the fastest tested FlashInfer FA2/FA3 backend. These are losses, not speedups. One heterogeneous launch had 148 empty-work CTAs out of 256. An experimental compact task scheduler now assigns splits to real request lengths, retaining full exact attention. On the 48-case H100 matrix it improves the natural control by 2.18x padded / 2.15x packed, but still reaches only 0.486x / 0.334x against FlashInfer. An independent 24-case replay passed and reproduced both the improvement and the remaining loss. It is not a promoted route. The next causal execution experiment removes position loads and unnecessary interior-tile mask work under a validated append-position contract. All 24 H100 cases passed. The interior path improves the compact causal control by 1.86x padded / 1.80x packed, but still reaches only 0.703x / 0.471x against FlashInfer. An independent 24-case H100 replay passed and reproduced 1.867x / 1.807x over control, while still trailing FlashInfer overall. It computes full exact attention. Producer/merge attribution, packed output scheduling and holdout routing remain integration work. Existing promoted decode routes are unchanged. See the complete comparison.
Kernel research also tested delaying softmax denominator reduction until the
end of each split. The exact R64 ablation improved the B1/M64/N16K anchor by
1.100x, but regressed B2/M64/N4K to 0.987x versus its paired native control.
It remains experimental, with no dispatcher change. The
research notes connect this result to
upstream code and the completed six-launch hardware-counter probe. That probe
found unchanged register/shared-memory allocation and too few ready warps,
pointing the next M64 investigation toward source-level load dependencies.
The source-correlated follow-up now locates the strongest short-K signal at
scalar Q staging: one store waiting on its input accounts for 76-77% of
long-scoreboard samples in two short-K anchors, versus 53% at long K.
These are sampled stalls, not runtime percentages or a promised speedup.
The next bounded kernel test is vectorized Q-to-shared staging, keeping the
retained online-softmax state and split schedule unchanged. See the
mixed-batch comparison and source attribution.
The architecture-basis harness now expands six H100 serving anchors into 84 operation-floor cases and records required Nsight Compute counters plus build and device fingerprints. Inspect it with:
python benchmarks/inspect_architecture_basis_suite.pyThe first performance milestone remains a no-external-fallback H100 vertical
slice covering M=1, M=2-8, M=9-64, M>=65, and mixed ragged serving with
low holdout routing regret. See Universal Inference v2
or inspect the contract with:
python benchmarks/inspect_universal_inference_v2.pyThe native engine deliberately separates model-specific work from attention:
request
-> model adapter projects Q/K/V and applies RoPE
-> adapter appends K/V to its cache
-> StreamAttn validates or reuses a fixed-buffer plan
-> exact_native: stream every KV tile
-> seed_only_native: stream the validated seed blocks
-> verified_auto: choose seed only on a matching policy cell
-> online softmax produces [B, 1, Hq, D]
-> model adapter applies output projection
-> sampler chooses the next token
Planning is kept outside the steady-state loop. The hot path reuses workspaces, seed schedules, output buffers, and native cache views instead of rebuilding Python metadata on every token.
For each query row, StreamAttn carries a running maximum m, normalizer l,
and weighted value numerator n. When a new score tile arrives:
m_new = max(m, max(scores_tile))
alpha = exp(m - m_new)
p = exp(scores_tile - m_new)
l = alpha * l + sum(p)
n = alpha * n + p @ V_tile
m = m_new
output = n / l
This is numerically stable, requires linear auxiliary memory, and composes across split tiles. Exact mode applies it to every KV tile. Seed-only mode uses the same normalization over the policy-selected KV set.
Packaged policy cells live in
stream_attention/policies/registry.json.
Each cell records the model and layer, tensor space, dtype, KV bucket, minimum
batch, head geometry, seed schedule, safety gates, and measured performance.
A layer that passes in isolation is not automatically safe in a multi-layer route. Route bundles are evaluated with teacher-forced replay, greedy rollout, coupled sampling, and adversarial stress prompts. Failed or unknown cells are not silently promoted.
The dynamic-selector research follows the same rule: query-aware block selection is interesting only if its selection overhead, model-level safety, and net decode latency all pass. Research utilities are not part of the default serving path.
The lightweight package CLIs exercise the general fused attention module:
stream-attention-benchmark \
--seq 512 1024 2048 4096 \
--batch 1 --heads 8 --dim 64 --warmup 10 --iters 50
stream-attention-test \
--seq 1024 --batch 2 --heads 8 --dim 64 --dtype fp16For native decode research, start with the profiler help instead of assuming a default shape:
python benchmarks/profile_transposed_wgmma_exact_qk.py --help
python benchmarks/profile_paged_exact_decode.py --help
python benchmarks/profile_seed_only_route_bundle_decode.py --help
python benchmarks/profile_seed_kernel_mode_autotune.py --help
python benchmarks/inspect_universal_exact_manifest.py
python benchmarks/compile_universal_exact_phase_db.py --helpA publishable performance result should record:
- GPU model, CUDA, driver, PyTorch, Triton, and baseline versions
- batch, KV length, Q/KV heads, head dimension, dtype, and cache layout
- warmup, repetitions, timing method, and clock/power conditions
- numerical tolerance or model-distribution gate
- paired raw timings, not speedup alone
FlashInfer is the exact decode reference used by the promoted H100 phase diagrams. PyTorch SDPA is the general correctness fallback and training reference. FlashAttention-class implementations remain external references, not hidden StreamAttn dependencies.
| Area | Current support |
|---|---|
| Python | 3.10+ |
| PyTorch | 2.1+ |
| CPU | Correctness and SDPA fallback |
| Native GPU evidence | NVIDIA H100 / SM90 and B200 / SM100; promoted A100 / SM80 contiguous D64 cells, one cross-provider contiguous D128 cell, plus complete paged-D128 routing evidence |
| Exact decode | Contiguous BF16 KV; guarded D64/D128 GQA cells plus generic exact fallback |
| Paged exact decode | Direct NHD/HND exact fallback; promoted H100 shape cells plus six B200 NHD/page-16 D128/G8 full-row cells |
| Reduced-work decode | Packaged Qwen-family 32K cells; request-tier and route-bundle restrictions apply |
| Prefill/forward/backward | Public exact MHA/GQA prefill(...) and train(...) plans; promoted B200 BF16 Hq16/Hkv2/D128 causal prefill cells; compact Triton online-softmax path with masks, dropout, ALiBi, and autograd; exact SDPA fallback |
| Distributed research | Ring and Star attention prototypes |
| Experimental hardware | A100 has promoted contiguous D64 and B4/G8/16K D128 cp.async + MMA exact decode; paged D128 still falls back externally |
| Not yet promoted | H100 WGMMA prefill, remaining A100 D128 shapes plus prefill/backward, other B200 prefill/decode shapes, ragged page-64 WGMMA, FP8 selected cache, second model family |
stream_attention/
engine.py public decode, prefill, and training engine
functional.py planned exact prefill/training execution
exact_compiler.py workload, schedule, and resource compiler IR
phase_database.py strict evidence resolution and phase-table compiler
decode.py native modes, planning, and fail-closed service
backends/sm80/ promoted contiguous D64/D128 and experimental paged-D128 Ampere exact kernels
backends/sm90/ promoted Hopper exact kernels and dispatch
backends/sm100/ promoted Blackwell exact backend and headers
kernels/ Triton/CUDA attention kernels
policies/ calibrated policy cells and route bundles
core/ general forward/backward attention modules
integration/ model integration helpers
benchmarks/ profilers, manifests, compilers, and evidence tools
docs/ phase diagrams and research decisions
examples/ minimal usage and integration examples
tests/ CPU, policy, API, and CUDA-gated tests
The detailed experiment history is intentionally kept in docs/ rather than
the README. Start with:
- Documentation index
- Qwen2.5-3B route evidence
- Dynamic selector findings
- D128 pipeline ablation
- Paged exact decode
- Universal Exact Phase Compiler v1
- Exact Phase Database v1
- Literature and backend decision ledger
Read CONTRIBUTING.md before opening a pull request. The required CI result covers policy integrity, Python 3.10/3.11 CPU tests, package validation, and GPU-source contracts. CUDA-source changes also trigger an offline SM90 compile check on a standard hosted runner; contributors are not expected to pay for GPU CI.
Actual-device performance claims still require a reproducible hardware artifact. The contributor harness and evidence requirements are documented in GPU CI and wheels.
Useful local checks:
python -m pytest -q
python benchmarks/check_gpu_source_contract.py
python -m build
python benchmarks/check_wheel_contents.py dist/*.whlThe project has proved that StreamAttn-owned exact kernels can beat strong baselines on guarded Hopper and Blackwell cells. The next objective is broad, reproducible exact coverage rather than another isolated promotion:
- Complete the remaining SM90 and SM100 manifest cells with the same strict evidence contract now used by the complete seven-cell SM80 database.
- Connect compiled
ptxas/occupancy reports to the SM80/SM90/SM100 resource legality models, then add analytical roofline pruning and active exploration near uncertain phase boundaries. - Expand B200 prefill through the compiler across G4/G8/G16, D64/D128/D256, FP16/BF16, causal/noncausal, and the short-M to long-M transition.
- Independently replay the 11 winning cells from the completed 30-cell H100 consumer-owned RS-PV prefill screen, then insert only replicated winners into the exact phase database and guarded public dispatch. Expand that family across query-head counts, GQA groups, D64/D256, FP16, noncausal attention, and ragged lengths; keep every unmeasured or losing cell on exact fallback.
- Split native backward into query-owned dQ and KV-group-owned dK/dV families with deterministic partial reductions instead of global GQA atomics.
- Extend the register-resident A100 D128 producer beyond the promoted B4/G8/16K cell. Strict 32K, G4, and B8 tests rejected the current schedule, so the next step is a different work decomposition rather than more buffer or merge-split permutations; then build distinct prefill and backward schedules.
- Resume adaptive/selected work above the exact compiler. Unknown or failed guarantees must return to StreamAttn exact execution.
The public engine API is now:
stream_attn.decode(...)
stream_attn.prefill(...)
stream_attn.train(...)with native exact, seed-only, adaptive, and verified routes behind one engine. Decode has the broadest optimized backend portfolio today. Prefill and training now execute exact native MHA and compact GQA, while the grouped-KV architecture-specific performance backends are built.
Apache-2.0. See LICENSE.