Skip to content

perf(qsa): score prefill rows in tiles of 16 query rows per program - #98

Open
gdevenyi wants to merge 1 commit into
5080/49-decode-fixfrom
5080/52-qsa-score-rows
Open

gdevenyi wants to merge 1 commit into
5080/49-decode-fixfrom
5080/52-qsa-score-rows

Conversation

@gdevenyi

Copy link
Copy Markdown
Owner

Prefill QSA indexer scoring handles 16 query rows of one request per program, with no head padding. Tiles are cut at request boundaries. Decode and graph capture keep the old kernel. Stacked on #97.

Results (2 interleaved rounds, production flags)

base new
score kernel per 4K chunk at 249K 196-200 ms 38 ms
cold TTFT 249K 85.52 / 85.58 s 83.48 / 83.44 s (-2.4%)
cold TTFT 127K 43.23 / 43.19 s 42.85 / 42.81 s (-0.9%)
decode copybench 64K 20.92 / 20.87 ms/step 20.89 / 20.91

The gain is small because late prefill chunks are bound by the expert H2D copies: the copy stream is busy about 1270 of every 1340 ms. It should grow once prefill is no longer copy-bound.

Exactness

  • tests/kernels/test_qsa_score_rows.py, 13 GPU cases: scores are bitwise equal as int32 bits and qsa_block_topk selects identical blocks. A negative control (a different head-sum order) fails the test, so it does detect order changes.
  • attn_gpu_check.py: 36/36.
  • Cold greedy fingerprints are identical across 4 starts.
  • Cold-nonce differences: new vs base 2.75/60, base vs base 3.0/60. This is the existing cross-start noise.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Td2gieja9Da2rPTN17Z846

The prefill indexer score ran one query row per program and padded the 4
index heads to a 16-wide dot, so every row re-read all visible keys and 3/4
of the tensor-core work was padding. qsa_mqa_paged_rows gives each program
16 rows of one request (a host-built tile map cut at the cu_seqlens request
boundaries) and does one [BLOCK_N, 16] dot per head, summing the heads in
the one-row kernel's order, so every score is bitwise the old one. Decode
(graph-captured) keeps the one-row kernel.

Microbench, one 4096-row chunk at 249K context: 18.5 -> 3.2 ms per layer,
no spills (134 regs).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Td2gieja9Da2rPTN17Z846
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant