Summary
#606's zero-host-read THD execute derives the packed token extents from a host-side buffer heuristic (t_q = min(q_buf.numel() // q_ts, o_buf.numel() // o_ts), same for KV). Two independent problems follow, one breaking non-packed views, one showing the kernel is extent-sensitive in a way no host heuristic can satisfy. Found while restacking the torch-ops work (#517/#554) on #608; SM100 (merged) and #608's SM120 path (buf.numel() // ts as well) both carry it.
Bug 1 — numel() // token_stride under-claims non-packed views
A K/V slice of a kv-interleaved [T, 2, H, D] buffer (the torch.nn.attention.varlen fused-projection layout, #526's headline case) holds T tokens but only T*H*D of the record's elements, so the derived extent halves. Same for any declared-stride gap view. Result: TMA extents cut off half the tokens — silently wrong O.
Repro (fails on develop, FROST route; backend route passes):
cd test/python && CUDNN_FRONTEND_ENABLE_FROST_ENGINES=1 pytest test_mhas_v2.py::test_repro --repro \
"{'data_type': 'torch.float16', 'diag_align': 'cudnn.diagonal_alignment.TOP_LEFT', 'batches': 2, 'h_q': 8, 'h_k': 8, 'h_v': 8, 'd_qk': 128, 'd_v': 128, 's_q': 256, 's_kv': 256, 'seq_len_q': [192, 256], 'seq_len_kv': [192, 256], 'is_ragged': True, 'is_padding': True, 'is_infer': True, 'with_ragged_token_gap': True, 'rng_geom_seed': 1, 'rng_data_seed': 2}"
→ 41.1% O mismatches served by frost:sdpa_fwd_prefill_sm100_d128. (The always-on stride fuzzing from #516 catches this — the ragged sweeps are partially red on develop depending on the seed's gap draws and buffer binding style.)
A storage-derived exact-addressable capacity ((storage_elems_from_offset - row_footprint) // ts + 1) fixes every view case (verified: repro 41% → 0, kv-interleave probes bit-exact) — but breaks base-buffer bindings, because of bug 2.
Bug 2 — the kernel's unit decode is extent-sensitive; "over-claim is safe" does not hold
Forcing t_q for a failing sweep config (seq_len_q=[17,174,665,911], real total 1767, harness buffer capacity 1792, CGA_TILE_M=256):
| forced t_q |
result |
| 1767 (exact) |
pass |
| 1792 (= 7×256 boundary) |
pass |
| 1793 |
fail, ~50% O mismatches |
| 1794 |
fail |
| 1856 (64-aligned!) |
fail |
Empirical law: corruption whenever ceil(t_q / CGA_TILE_M) > ceil(real_total / CGA_TILE_M) — the extent feeds the unit/tile decode (or something equivalent), so an over-claimed extent that crosses a tile boundary shifts real tiles onto wrong (batch, row) coordinates. The in-tree suites stay green only because the harness allocates packed_token_capacity (64-rounded) buffers, and a 64-rounding can never cross a 256 boundary.
Why no host-side formula can fix this
The adapter must choose t_q ∈ [real_total, real_total rounded up to the SAME tile count] — but the real total is device-only by #552's own design. numel//ts breaks views; exact-addressable capacity breaks any binding with slack past a tile boundary. The fix has to be kernel-side: make the unit decode (and anything else consuming the token extent) read the device metadata (cu[n_batch]) instead of the descriptor extent, so the extent can be a plain safe upper bound. Alternatively the envelope/decode contract needs to tolerate extra dead tile rows.
Affected
Happy to pair on this — I have the probes, the forced-t_q knob diff, and the storage-capacity patch staged.
Summary
#606's zero-host-read THD execute derives the packed token extents from a host-side buffer heuristic (
t_q = min(q_buf.numel() // q_ts, o_buf.numel() // o_ts), same for KV). Two independent problems follow, one breaking non-packed views, one showing the kernel is extent-sensitive in a way no host heuristic can satisfy. Found while restacking the torch-ops work (#517/#554) on #608; SM100 (merged) and #608's SM120 path (buf.numel() // tsas well) both carry it.Bug 1 —
numel() // token_strideunder-claims non-packed viewsA K/V slice of a kv-interleaved
[T, 2, H, D]buffer (thetorch.nn.attention.varlenfused-projection layout, #526's headline case) holdsTtokens but onlyT*H*Dof the record's elements, so the derived extent halves. Same for any declared-stride gap view. Result: TMA extents cut off half the tokens — silently wrong O.Repro (fails on develop, FROST route; backend route passes):
→ 41.1% O mismatches served by
frost:sdpa_fwd_prefill_sm100_d128. (The always-on stride fuzzing from #516 catches this — the ragged sweeps are partially red on develop depending on the seed's gap draws and buffer binding style.)A storage-derived exact-addressable capacity (
(storage_elems_from_offset - row_footprint) // ts + 1) fixes every view case (verified: repro 41% → 0, kv-interleave probes bit-exact) — but breaks base-buffer bindings, because of bug 2.Bug 2 — the kernel's unit decode is extent-sensitive; "over-claim is safe" does not hold
Forcing
t_qfor a failing sweep config (seq_len_q=[17,174,665,911], real total 1767, harness buffer capacity 1792, CGA_TILE_M=256):Empirical law: corruption whenever
ceil(t_q / CGA_TILE_M) > ceil(real_total / CGA_TILE_M)— the extent feeds the unit/tile decode (or something equivalent), so an over-claimed extent that crosses a tile boundary shifts real tiles onto wrong (batch, row) coordinates. The in-tree suites stay green only because the harness allocatespacked_token_capacity(64-rounded) buffers, and a 64-rounding can never cross a 256 boundary.Why no host-side formula can fix this
The adapter must choose
t_q ∈ [real_total, real_total rounded up to the SAME tile count]— but the real total is device-only by #552's own design.numel//tsbreaks views; exact-addressable capacity breaks any binding with slack past a tile boundary. The fix has to be kernel-side: make the unit decode (and anything else consuming the token extent) read the device metadata (cu[n_batch]) instead of the descriptor extent, so the extent can be a plain safe upper bound. Alternatively the envelope/decode contract needs to tolerate extra dead tile rows.Affected
_execute_thdcapacity sites inapi_dsl.py.return buf.numel() // ts, and the token-major LSE cap).Happy to pair on this — I have the probes, the forced-t_q knob diff, and the storage-capacity patch staged.