You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(vt): reshape_and_cache indexes paged KV cache by tensor strides
Fixes the stride-handling defect in e231196 (M1.6 Task 2). ReshapeAndCache
derived block/page strides from k_cache.shape and required whole-cache
IsContiguous(), which is wrong for our committed layout: get_kv_cache_shape
returns one (num_blocks, 2, block_size, H, D) allocation and K/V are its two
dim-1 unbind slices — rank-4 STRIDED views with block stride 2*bs*H*D (not
bs*H*D), never contiguous. Feeding the real slices either threw on the guard
or (with a shape-derived block_stride = half the real stride) silently wrote
block b into interleaved K/V memory, clobbering the other slice.
Mirror pinned csrc/libtorch_stable/cache_kernels.cu @ e24d1b24: source
block/page strides from key_cache.stride(0/1) and the token stride from
key.stride(0) (host ~L797-801; kernel ~L337-347). Each cache slice is indexed
with ITS OWN strides.
- cpu_cache.cpp / cuda_cache.cu: dst = block*stride[0] + offset*stride[1],
src = token*stride[0]; per-token page stays one dense memcpy/run given the
head-contiguous NHD slice (pinned is_contiguous_heads fast path).
- ops.cpp: relax the guard — no cache contiguity; require only elem stride 1,
head-contiguous page (stride[2]==head_size), and contiguous k/v/slot_mapping.
- tests: add strided-unbind-slice CPU tests (drive the exact missed case;
failed/threw before, pass after) + a build-guarded CUDA strided-parity test
(dgx-pending). Existing contiguous tests still pass (contiguous cache is the
stride[0]==bs*H*D special case).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/superpowers/plans/2026-07-03-m1.6-paged-attention.md
+5-2Lines changed: 5 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,10 +21,13 @@
21
21
Read `/home/mudler/_git/vllm/vllm/v1/attention/backend.py` (VERIFY current API). Port `CommonAttentionMetadata` (the exact T0 field set), `AttentionBackend` (ABC: get_impl_cls/get_builder_cls/get_kv_cache_shape), `AttentionImpl` (`forward(layer, q, k, v, kv_cache, attn_metadata, output, ...)`), `AttentionMetadataBuilder` (`build(common_attn_metadata) -> backend metadata`). Behavioral interface + a metadata builder that turns the M1.5 step-inputs (query_start_loc/seq_lens/slot_mapping/block_table) into the backend metadata. Unit tests: build CommonAttentionMetadata from step-inputs, the max_query_len/max_seq_len derivation, get_kv_cache_shape.
Read the pinned reshape_and_cache (csrc/cache_kernels or the CPU backend's cache write) + the KV cache tensor layout (`get_kv_cache_shape` for the full-attn spec). Port `vt::reshape_and_cache(k, v, k_cache, v_cache, slot_mapping)` — write new K/V into the paged cache at the slot ids. CPU + CUDA. Match the exact paged layout (block-major [num_blocks, block_size, num_kv_heads, head_size] or the upstream shape). Pinned-oracle golden. Unit tests: writing tokens to slots, reading them back at the right block/offset; CUDA vs CPU.
24
+
Port `vt::reshape_and_cache(k, v, k_cache, v_cache, slot_mapping)` — write new K/V into the paged cache at the slot ids. CPU + CUDA.
25
+
**LAYOUT (BINDING, from Task 1 + review): Task 1 committed the flash NHD shape `get_kv_cache_shape = (num_blocks, 2, block_size, num_kv_heads, head_size)`.** So `k_cache`/`v_cache` are the two dim-1 slices, each `[num_blocks, block_size, num_kv_heads, head_size]`; a slot id maps to `block = slot / block_size, offset = slot % block_size`, and the write goes to `[block, offset, kv_head, :]`. **TRAP TO AVOID:** the pinned `cpu_attn.py` uses a DIFFERENT (HND) internal layout `(num_blocks, num_kv_heads, block_size, 2*head_size)` — DO NOT port cpu_attn's cache-indexing/view arithmetic. Take cpu_attn (or flash_attn) only for the write SEMANTICS; index against the NHD shape Task 1 allocates. Crossing the two layouts silently corrupts every output.
26
+
**Golden strategy (review): compose the reference from math, not backend cache bytes** — a reshape_and_cache "golden" is just: after writing, reading slot s back from the NHD cache yields the input k/v for that token. Unit-test WRITE→READ round-trip directly (host, layout-consistent); no external oracle needed. CUDA vs CPU parity for the kernel.
Port the correctness-grade paged attention: `vt::paged_attention(out, q, k_cache, v_cache, block_table, seq_lens, query_start_loc, scale, ...)` — for each query token, causal GQA softmax over the K/V read from the paged blocks (block_table → block ids → cache slots) up to seq_len. This generalizes M0.9's dense `vt::Attention` to the paged/varlen/batched case. CPU reference + CUDA (correctness-grade block-per-(query,head), the FlashInfer perf kernel is M2.4). Pinned-oracle golden (dump from the pinned CPU attention backend for a small batched case). Validate against M0.9's dense attention on the single-sequence case (must agree). Unit tests + parity golden CPU+CUDA on dgx.
29
+
Port the correctness-grade paged attention: `vt::paged_attention(out, q, k_cache, v_cache, block_table, seq_lens, query_start_loc, scale, ...)` — for each query token, causal GQA softmax over the K/V read from the paged blocks (`block_table` → block ids; a token at absolute position p reads block `block_table[req, p/block_size]`, offset `p%block_size` in the **NHD** cache from Task 2) up to seq_len. This generalizes M0.9's dense `vt::Attention` to the paged/varlen/batched case. CPU reference + CUDA (correctness-grade block-per-(query,head); FlashInfer perf kernel is M2.4). **READ against the NHD layout Task 2 writes (same trap: not cpu_attn's HND arithmetic).**
30
+
**Golden strategy (review): COMPOSE the reference math (M0.9-style), do NOT dump backend cache bytes.** The attention OUTPUT is layout-agnostic: build the golden as per-token causal GQA softmax over gathered K/V (the same reference approach as M0.9's `dense_attention` golden). **Anchor: on the single-sequence contiguous case, paged_attention MUST agree bit-for-tolerance with M0.9's dense `vt::Attention`** — assert this directly (it's the strongest correctness check + needs no new oracle). Then a small batched varlen case (2 reqs: prefill + decode) via composed reference. Unit tests + CUDA-vs-CPU parity on dgx.
Read `/home/mudler/_git/vllm/vllm/v1/attention/backends/gdn_attn.py::GDNAttentionMetadata`. Port the metadata that segments a batched step into GDN prefill (chunked-scan) vs decode (recurrence) vs spec segments — num_prefills/num_decodes, the has_initial_state masks, the segment offsets — so the M0.7 GDN ops (GdnPrefill/GdnDecode) can be driven by a batched SchedulerOutput. This is the hybrid-model glue: the metadata builder splits the batch's GDN-layer work. Behavioral (no new GDN kernels — reuse M0.7). Unit tests: a batched step with 1 prefill + 1 decode request produces the right GDN segmentation.
0 commit comments