Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions docs/fe-oss-apis/gated_attention_block.md
Original file line number Diff line number Diff line change
Expand Up @@ -1107,8 +1107,19 @@ the FROST GEMM stages -- the slab GEMM, the out projection and its split-K reduc
(their templates' own constant), so a `use_pdl=False` chain still holds three programmatic launches. `blk.use_pdl` is the resolved switch,
`blk.use_pdl_requested` the declaration (`None` = auto), `blk.pdl_stages` / `blk.use_pdl_effective` count the switched stages only, and
`serving_envelope().decode.pdl_default` says what auto resolves to on a part before anything is declared (`False` wherever the form is not
served -- another part, an unserved dtype -- and under the block-sparse mode; the per-step reading is `decode.pdl_default and
decode.route(s_q, batch).pdl_capable`, a prefill-route step launching plain). Measured on a 212-SM cc 10.7
served -- another part, an unserved dtype; the per-step reading is `decode.pdl_default and
decode.route(s_q, batch).pdl_capable`, a prefill-route step launching plain). **The block-sparse decode mode takes the switch too**
(a `QsaSpec` geometry over bf16 / f16 pools): under `use_pdl=True` the sparse core launches with the attribute and carries its
`griddepcontrol` sites (every role's wait before its first read of a predecessor's output -- the slab, the pools, the block list, the
lengths, the table -- and no explicit release: the CTA exit triggers the dependent grid at the core's completion, the placement measured
on the cc 10.7 class, where a release at the core's prologue left the split combine's CTAs resident through the core's whole run and
cost 3.2-4.4 us per step at `B <= 4`) and its split combine takes the pair, bitwise the plain chain eagerly
and under capture (the first execute of a fresh switched declaration, captured with no warm-up, replays bitwise the eager plain chain);
`blk.pdl_stages` then names `sdpa_sparse` (the `sdpa` kind) beside the norm + RoPE pass, the write-through and the separate gate. Its
AUTO reading stays `False` (`SPARSE_DECODE_PDL_DEFAULT_CCS`, empty: a part enters it only with a measurement meeting the flip bar of
>= 1.0 us and >= 5 % per step at B 1 x 8K and B 1 x 32K; the 212-SM cc 10.7 class read +2.1 % / 0.80 us and +4.1 % / 1.54 us there,
+2.6 % geomean over the B <= 4 cells and no cell slower -- a gain below the bar, taken through the explicit `use_pdl=True`), and `use_pdl=True` with `thd=True` on a `QsaSpec` geometry is a typed decline (the packed form reads the setup
launch's metadata above every role wait). Measured on a 212-SM cc 10.7
part: 1.1-1.5 us per decode step at B 1 (B 1 x KV 4K +5.0 %, 32K +4.0 %, 128K +2.5 %; +2.8 % geomean over the B 1 .. 4 cells), flat within
the control pair where the tile dominates; with the write-through folded in, B 1 x KV 4K 32.3 -> 29.3 us (+10.2 %) against the plain
seven-launch chain. The fused kernel the stage runs is a declaration fact:
Expand Down Expand Up @@ -1201,7 +1212,7 @@ under every value, measured or not -- so a replaying stack whose optimum differs
| `decode_route_policy` (declaration) | `None` (= `"single_unit"`) or `"token_units"` | the route policy (the table above / the adapter's token-unit route): a performance-only knob, the same function under either; `DecodeRoute.policy` reads it back, `DecodeRoute.batch` the batch the default policy's prefill-route fill (`DECODE_PREFILL_ROUTE_MIN_CTAS`) was read at |
| `fuse_norm_rope_small_m` (declaration) | `None` (= the lowering at `B x S_q <= 128`, unless `fuse_cache_write=True` asks for the fork's write-through arm), `True` (the fused fork as declared) or `False` (the lowering, explicit; with `fuse_cache_write=True` a typed decline) | whether the fused norm + RoPE projection runs at decode row counts when `fuse_norm_rope=True`: a performance-only knob; `blk.fuse_norm_rope_effective` reads back what runs; refused with `fuse_norm_rope=False` and off the dense DECODE form |
| `decode_q_tile_max` (declaration) | `None` (= the whole table `(16, 32, 64)`) or a width of it (`32` = the route before the 64-column tile landed) | the width cap on the decode tile's single-unit table: a performance-only knob, the same function under every width; `DecodeRoute.q_tile_max` reads it back and the compiled width is pinned against the route at `compile()`; a cap held below the width an unpacked step needs is a typed decline naming it |
| `use_pdl` (declaration) | `None` (default = auto: `True` on the DECODE form's decode-tile routes for the bf16 / f16 block on the parts of `DECODE_PDL_DEFAULT_CCS` -- cc 10.7, the measured part --, `False` everywhere else), `True` or `False` (explicit, honoured on every part) | programmatic dependent launch over the chain: a performance-only knob (bitwise the plain chain, eagerly and under capture), bf16 / f16 only (an explicit `True` is a typed decline with `quant`, the e4m3 KV cache (`kv_cache_dtype=torch.float8_e4m3fn`) or a `QsaSpec`; auto reads `False` there and never `True` where the explicit `True` is refused -- pools in the activation dtype, `kv_cache_dtype=None` or that dtype, are the bf16 / f16 block). PER STAGE: the norm + RoPE pass, the separate cache write, the separate sigmoid gate and the decode tile with its split combine take it; the paged prefill tile of the prefill route carries no sites and launches plain (the link serializes, correct by PDL's semantics), so auto stays `False` on that route; the FROST GEMM stages launch with the attribute regardless. `blk.use_pdl` is the resolved switch, `blk.use_pdl_requested` the declaration, `blk.pdl_stages` / `blk.use_pdl_effective` read back what launched with the attribute, `DecodeRoute.pdl_capable` says it per route, `serving_envelope().decode.pdl_stages` / `.pdl_default` (the latter for a served dense form; the per-step reading is `decode.pdl_default and decode.route(s_q, batch).pdl_capable`) and `.extend.pdl_stages` per form |
| `use_pdl` (declaration) | `None` (default = auto: `True` on the DECODE form's decode-tile routes for the bf16 / f16 block on the parts of `DECODE_PDL_DEFAULT_CCS` -- cc 10.7, the measured part --, `False` everywhere else), `True` or `False` (explicit, honoured on every part) | programmatic dependent launch over the chain: a performance-only knob (bitwise the plain chain, eagerly and under capture), bf16 / f16 only (an explicit `True` is a typed decline with `quant`, the e4m3 KV cache (`kv_cache_dtype=torch.float8_e4m3fn`), and with `thd=True` on a `QsaSpec` geometry; auto reads `False` there and never `True` where the explicit `True` is refused -- pools in the activation dtype, `kv_cache_dtype=None` or that dtype, are the bf16 / f16 block). PER STAGE: the norm + RoPE pass, the separate cache write, the separate sigmoid gate and the decode tile with its split combine take it -- or, on a `QsaSpec` geometry, the block-sparse core with its split combine (`sdpa_sparse`; served since 2026-10-21, auto `False` there until measured: `SPARSE_DECODE_PDL_DEFAULT_CCS`); the paged prefill tile of the prefill route carries no sites and launches plain (the link serializes, correct by PDL's semantics), so auto stays `False` on that route; the FROST GEMM stages launch with the attribute regardless. `blk.use_pdl` is the resolved switch, `blk.use_pdl_requested` the declaration, `blk.pdl_stages` / `blk.use_pdl_effective` read back what launched with the attribute, `DecodeRoute.pdl_capable` says it per route, `serving_envelope().decode.pdl_stages` / `.pdl_default` (the latter for a served form: `DECODE_PDL_DEFAULT_CCS` on the dense form, `SPARSE_DECODE_PDL_DEFAULT_CCS` -- empty until measured -- under the block-sparse mode; the per-step reading is `decode.pdl_default and decode.route(s_q, batch).pdl_capable`) and `.extend.pdl_stages` per form |
| `fuse_cache_write_small_m` (declaration) | `None` (default = auto: the paged write-through folded into the norm + RoPE launch at `B x S_q < CACHE_WRITE_SMALL_M_DEFAULT_MAX_ROWS = 128` rows or at `S_q = 1`, the separate launch at 128+ rows with `S_q > 1` -- the measured rule -- and under an explicit `fuse_cache_write=False`, the separate launch asked for by name), `True` (folded in; a typed decline where the arm is not served; the strongest request, followed beside `fuse_cache_write=False` too) or `False` (the separate launch) | where the paged write-through runs on the DECODE form's UNFUSED chain (the lowered `fuse_norm_rope=True` declaration or `fuse_norm_rope=False`): bf16 / f16, no `quant`, no indexer band, 16-bit pools, the TMA norm + RoPE kernel; a performance-only knob (the pools and the slab bitwise either way, one launch fewer); `blk.cache_write_in_norm_rope` reads back what runs, the stage list loses `"cache_write"` under the arm |
| `block_table` (execute) | `[B, max_pages]` int32 at the declared strides; `0` = the NULL block of a padded entry | REQUIRED; page ids are device data |
| `kv_lens` (execute) | `[B]` int32 contiguous: the LOGICAL KV length of every sequence INCLUDING the step's tokens; `0` = a padded entry | REQUIRED; bound to the SDPA's KV side ONLY (`seq_kv_lens = kv_lens`, `seq_q_lens = None`: every Q row of the step is live) |
Expand Down Expand Up @@ -1306,8 +1317,9 @@ the counts, the ids, the compressed-slot report). The envelope publishes the fa
under the indexer (the e4m3 pools wait for the sparse core's in-kernel dequant arm: `indexer_e4m3_pool`). Typed declines by
row name (`decode.declines`, each the text the declaration raises): `indexer_query_rows`, `indexer_page_size`,
`indexer_e4m3_cache` (the paged scorer's e4m3 read arm), `indexer_e4m3_pool`, `indexer_shared_list`,
`fuse_prepare_rope_tables_unfused`, `indexer_f16`, `indexer_head_dim`, `indexer_thd`; `use_pdl=True` on the sparse chain keeps
the existing decline (the step threads the switch it is handed and is handed `False`). **Limitation:** there is no FROST writer
`fuse_prepare_rope_tables_unfused`, `indexer_f16`, `indexer_head_dim`, `indexer_thd`; `use_pdl=True` under the indexer keeps
a typed decline by name (the caller-list sparse chain serves the switch; the indexer's step threads the switch it is handed and is
handed `False` until its own switched chain is measured). **Limitation:** there is no FROST writer
of the paged compressed-key cache at PREFILL yet -- the prefill form writes `index_k_compressed` densely (`[B, >= floor(S / 4),
128]`); a serving stack scatters those rows into the pages through its table and primes the ring with the prompt's last `cap`
raw keys (the band's `index_k_raw` rows or the slab's band), exactly as the multi-step cell of the end-to-end module does.
Expand Down
Loading
Loading