Repository navigation
Conversation
The cuBLAS indexer scorer (FP16 torch.mm with FP32 accumulation and a
Triton epilogue) and the exact lexicographic top-k were gated on compute
capability 7.0, so Turing stages scored with the paged Triton kernel: in a
184k-token Flash-Next PP4 prefill that kernel took 20.0 and 30.1 s on the
two Quadro RTX 8000 stages while it never ran on the Tesla V100 stages.
Gate the single-request, multi-request and top-k routes on the SM70 family
like the DeepSeek-V4 indexer does; the native top-k op is built for sm_70
and runs on sm_75. The exact-index test now also runs on Turing.
Tests:
pytest tests/models/qwen4_exp/test_qsa_ops.py
tests/models/qwen4_exp/test_qsa_indexer_request_split.py
tests/config/test_sm70_provider_lifecycle.py
Quadro RTX 8000: 63 passed; Tesla V100: 63 passed
Co-authored-by: Claude
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GJxVXkjSHhfq2D71DoYSK7
Signed-off-by: Peuqui <43776522+Peuqui@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
The QSA indexer of Qwen3.8-Flash-Next has a cuBLAS scorer (FP16
torch.mmwith FP32 accumulation and a Triton epilogue) and an exact lexicographic top-k (the native_C_qsa_sm70op). Both are gated on compute capability 7.0, so Turing stages score with the paged Triton kernel_qsa_mqa_paged_kerneland select with the persistent top-k. In an nsys capture of a 184k-token Flash-Next PP4 prefill (two Quadro RTX 8000 and two Tesla V100 stages),_qsa_mqa_paged_kerneltook 20.0 s and 30.1 s on the two RTX 8000 stages and never ran on the V100 stages.This PR gates the single-request cuBLAS route, the multi-request cuBLAS route and the exact top-k on the SM70 family, as the DeepSeek-V4 indexer does. Turing stages thereby also get the deterministic tie rule of the exact selector (#394), which V100 stages already use. The native top-k op is built for sm_70 and runs unchanged on sm_75. The exact-index test now also runs on Turing.
Not a duplicate: gh pr list --repo 1CatAI/1Cat-vLLM --state all --search "QSA indexer Turing", "lexicographic topk", "qsa_indexer_cublas", "is_device_capability_family QSA" and "Turing QSA" find no PR that changes these gates; #394 (merged) introduced the exact selector because
persistent_topkcan pick a different block set when scores tie at the cutoff, #1171 (merged) reduced its work for long contexts, #469 (merged) widened the QSA launch profile to pre-Ampere. The open PRs touching vllm/models/qwen4_exp/nvidia/ops/qsa.py (#523, #828, #903, #1023, #1167, #1176, #1192, #1194, #1204-#1206, #1210, #1211) do not change these three gates, and this PR adds no merge conflict to any open PR (git merge-tree against each PR head; the ones that conflict do so with main already).AI assistance was used for this change. I reviewed every line and ran the tests and measurements below.
Test Plan
Kernel benchmark on a Quadro RTX 8000:
qsa_select_paged_tokensfor the last 1,616-row prefill chunk of a single request (4 indexer heads, head dim 128, compress ratio 4, top-k 2,048, contiguous cache pages), with the three gates as on main (paged Triton scorer, persistent top-k) against this PR (cuBLAS scorer, exact top-k), median of 20 calls, and the share of rows whose selected token set is identical.Serving on our fork (main 6f3557c plus our commits): the same A/B as #1228 (fork commit ee261cc = this change and #1228 on top of fork commit 9a41a8e), Qwen3.8-Flash-Next-180B-A4B NVFP4 with MTP in PP4 and TP2xPP2 over two Quadro RTX 8000 and two Tesla V100, boots fix cold, base, fix, base, fix; the cold boot and the first long request after each boot are not counted.
Path coverage
qsa_cublas_min_rows, or the multi-request splitAcceleration and benchmark contract (required for performance changes)
Test Result
On a Quadro RTX 8000 (main 6f3557c plus this PR): 234 passed, 38 skipped, 5 failed. Main without this PR: 224 passed, 48 skipped, 5 failed; ten tests that skip on Turing on main now run there. On a Tesla V100: 272 passed, 5 failed with and without this PR.
The five failures are the same on both GPUs with and without this PR: tests/kernels/test_top_k_per_row.py::test_persistent_topk_stress ("CUDA top-k contains values smaller than non-top-k" for a row of 106,861 scores with k 2,048;
persistent_topkis the kernel Turing used for QSA before this PR, where it selects 512 blocks, a case this test does not cover) and four cases in tests/models/qwen4_exp/test_qsa_reference.py whose metadata-builder fakes lack is_dummy_batch, reads_sharded_group or input_size. pre-commit and mypy-3.10 pass.Kernel benchmark, ms per call for the last 1,616-row chunk, gates as on main -> this PR: 29,000 tokens 80.94 -> 2.28, 184,000 tokens 505.38 -> 10.86; the selected token sets are identical in all rows. This is the most expensive chunk of each prompt; the serving numbers below cover whole prefills.
Serving, measured together with [Perf][GDN] Run the FlashQLA TileLang prefill kernel on Turing #1228 (both act on the RTX 8000 stages), time to first token, fix (two boots) against base (two boots): TP2xPP2 ~29k tokens 14.8 s against 17.6-17.7 s, 184,134 tokens 126.3-129.2 s against 178.9-194.1 s, 249,950 tokens 157.0-162.4 s against 253.3-275.7 s; PP4 ~29k tokens 10.2-10.6 s against 11.6 s (its long-context times vary with the page cache of the PLE disk tier in both arms). A separate decode A/B with 20 sampled code answers per boot (TP2xPP2, two boots per arm) gave 77.3 and 76.9 tok/s against 77.0 and 76.9 tok/s, 51.0 ms median step time in all four boots, acceptance length 3.93 against 3.91.
Outputs: greedy text differs between boots in both arms, as it does on main with fresh compile caches. A hallucination probe (a non-existent person, temperature 1.0, 20 draws per arm) was handled equally often correctly with and without the two PRs (PP4 13 and 14 of 20, TP2xPP2 18 and 19 of 20).
🤖 Generated with Claude Code
https://claude.ai/code/session_01GJxVXkjSHhfq2D71DoYSK7