Conversation
KDA SM121 QSA integration updateThe final PR now contains one SM121 packed-QSA attention kernel, integrated
The net PR diff therefore adds exactly one Provenance and kernel result
Every replay row passes both the pinned production-output check and an After removing the generic implementation, I also swept the shapes not present I then widened the benchmark scratch and tested both TP topologies at
The production limit is now the largest tested batch, 128. TP1's worst-case One-DGX-Spark end-to-end A/BHardware: one NVIDIA GB10 / SM121 DGX Spark, CUDA 13.0, PyTorch 2.13. Model: python3 -m sglang.bench_serving \
--backend sglang-oai \
--model qwen3.8-flash-next \
--dataset-name random \
--random-input-len 8192 \
--random-output-len 256 \
--random-range-ratio 0 \
--num-prompts 12 \
--max-concurrency ${CONCURRENCY} \
--request-rate inf \
--seed 1234 \
--flush-cache \
--disable-tqdm
The concurrency-4 TPOT movement is a small regression/noise point; total End-to-end accuracy A/BI used the first 50 official GSM8K test examples, five-shot prompting, Chat API, python3 -m sglang.test.run_eval \
--host 127.0.0.1 --port 8892 \
--model qwen3.8-flash-next \
--eval-name gsm8k --api chat \
--num-examples 50 --num-threads 4 --num-shots 5 \
--max-tokens 2048 --temperature 0 \
--thinking-mode qwen-3 \
--gsm8k-data-path gsm8k-test.jsonl
The same example failed in both reports. I also checked the sensitivity of a The original correctness validation also passes 20/20 sequential requests, Validation after single-kernel refactorAll pre-commit hooks pass, including Black, isort, Ruff, codespell, and the Server-side speculative configurationThe benchmark command above is the client command only. The server was explicitly launched with the checkpoint's embedded MTP/NEXTN path: --speculative-algorithm EAGLE \
--speculative-draft-model-path /persistent/qwen38-model \
--speculative-num-steps 3 \
--speculative-eagle-topk 1 \
--speculative-num-draft-tokens 4This is EAGLE/NEXTN MTP, not SGLang's separate |
Two-DGX-Spark / TP2 follow-upI completed the deferred two-Spark validation on two NVIDIA GB10 / SM121 Server-side speculative configurationThe serving benchmark command below is only the benchmark client. The server --speculative-algorithm EAGLE \
--speculative-draft-model-path /persistent/qwen38-model \
--speculative-num-steps 3 \
--speculative-eagle-topk 1 \
--speculative-num-draft-tokens 4This is EAGLE/NEXTN MTP, not SGLang's separate Correctness
Matched 8K decode traceI captured ten decode forwards per implementation with the same 8192-token
The QSA saving is 13.348 ms over ten forwards, or about 1.335 ms per decode The trace also explains why whole-server TP2 numbers need care: NCCL AllReduce Low-concurrency serving resultEvery serving round completed 12/12 requests with the same 45,946 input tokens
The two KDA rounds ran on the same already-warm server but still moved by
The one-DGX-Spark three-round E2E result in the previous comment remains the |
|
Independent validation on one DGX Spark (GB10, sm_121, TP=1), on top of the day-0 image with the single-Spark recipe (NVFP4 routed experts, dense path in FP8, exact FP8 PLE table mmap'd from NVMe, NEXTN 3/1/4, 262,144 context): Kernel in isolation, at the model's real QSA decode shape (24 query heads / 2 KV heads / head dim 256 — the differential cases in this PR stop at head dim 192), against a PyTorch fp32 reference, BF16 and FP16, packed lengths 1–2051, batch 1–7: max abs error 0.001; CUDA-graph replay with changed device-side End to end,
No token id 0 anywhere, Scripts and logs: https://github.com/hashd1ve/qwen38-flash-next-one-dgx-spark (patch 2 replaced with this PR's fallback, README documents the correction). |
|
Field data from a single DGX Spark (GB10), in case it helps the review. Our installer for this box (hasso5703/dgx-spark-qwen38, v1.5.2 and later) ships the Triton |
78c5024
into
sgl-project:qwen4-main-squashed
Motivation
Follow-up to #36806; fixes the remaining SM121 / GB10 part of #36537.
QSA decode needs different paths on SM120 and SM121:
and 210k reproductions all returned 32/32 token id 0 (
!) while the serverremained healthy and returned HTTP 200.
implementation does not compile for QSA's packed one-query shape on GB10
(
expects coord and shape of view are weakly congruent).Disabling FlashInfer autotune only makes the incorrect SM121 kernel start; it
does not fix its numerics.
Changes
contract on SM121: BF16, D=256, 12:1 GQA, TP1 24Q/2KV or TP2 12Q/1KV,
one query per sequence,
1 <= bs <= 128, and selected KV capacity <=2055.generic SM121 attention kernel in this PR; unsupported calls fail with a
descriptive contract error.
FA2/FA4 selection unchanged on other architectures.
structure from [Kernel] Add KDA NVFP4 GEMM for Qwen3.x on SM120 #36865.
validated batch coverage, and repeated atomic-state tests.
The kernel reads live sequence lengths on device, so captured graphs can replay
with changed
cu_seqlenswithout host readback.Agent workflow
Humanize provided the iterative implementation and review workflow used for
this change. The Kernel Design Agent ran through KDA-1.5 with Codex and Kimi K3
and produced the winning SM121 QSA kernel. This PR fixes SM121 QSA correctness
and integrates that single optimized Triton kernel. Humanize and the Kernel
Design Agent had distinct roles: Humanize structured the workflow, while the
Kernel Design Agent produced the kernel selected for integration.
Optimized kernel
The original correct Triton implementation launched one CTA per query head, so
the 12 query heads sharing one KV head repeatedly loaded the same K/V rows. The
optimized kernel groups those 12 heads into one CTA, uses BF16 tensor-core QK/PV
products with FP32 online-softmax state, and splits long KV rows across CTAs.
The final split performs a stable FP32 merge and resets its device counter in
the same launch.
Provenance:
at
414ce456e14ae8546f77d9356d2c4d955c5bb7f1b4181149c8884ddb4f9977f88abfea4393a2add3a2c9255699f7e13b981dbc1a976b024b3b00e909The packaged kernel passes 15/15 real replays against both the pinned
production output and an independent FP32 reference (
relative-L2 <= 2e-3),with exactly one CUDA activity per invocation. Its all/large/small geomean over
the original correct Triton implementation is 2.0702x / 1.6951x / 2.3653x.
The final source also passed 150,000 consecutive launches with every counter
reset to zero.
An additional GB10 sweep covers both TP topologies, every batch size from 1 to
16, and short plus saturated selected-KV rows: 64/64 passed, maximum
relative L2
0.002422, and speedup1.41x-5.09xover the original Tritonimplementation.
The follow-up extended-batch sweep covers both TP topologies, batch sizes
17/24/32/48/64/96/128, and short, medium, plus saturated KV: 42/42 passed,
maximum relative L2
0.002410,4.48xgeomean speedup, and1.58xminimumspeedup. No case regressed. The worst-case TP1 scratch allocation at the
largest qualified batch is 32.3 MiB.
These are isolated-kernel measurements against the original correct Triton
implementation. End-to-end serving remains intentionally measured at low
concurrency because a single GB10 cannot sustain medium/high-concurrency model
serving without changing the workload.
End-to-end performance and accuracy
Hardware: one NVIDIA GB10 / SM121 DGX Spark, CUDA 13.0, PyTorch 2.13.
Model:
RadixArk/Qwen3.8-Flash-Next-NVFP4TP1 with ModelOpt NVFP4,FlashInfer CUTLASS FP4/MoE, exact FP8 PLE from NVMe, 262,144 context, and NEXTN
(3 steps, top-k 1, 4 draft tokens). The benchmark compared the original
correct Triton implementation with the final KDA kernel under otherwise
identical server flags.
Three-round low-concurrency A/B, 12/12 successful requests per round and the
same 45,946 input plus 1,667 output tokens:
Accuracy A/B uses the first 50 official GSM8K test examples, five-shot Chat API
prompting, Qwen thinking, greedy decoding, concurrency 4, and a 2048-token
output limit:
The original correctness validation also passes 20/20 sequential requests,
4/4 concurrent requests, structured tool parsing, and exact NIAH retrieval at
120k, 190k, and 210k tokens with zero token-id-0 output.
Full commands, TPOT/ITL results, replay tables, and the output-limit sensitivity
check are in this validation comment.
Validation
pre-commit run --files ...: passcompileall: passgit diff --check: passpytest -q test/registered/kernels/test_qsa.py test/registered/kernels/test_kda_qsa_sm121.py -s:73 passed on SM121 after deleting the old implementation
cu_seqlens: passThe Base/Extra/AMD workflow failures below are the repository rebase gate, not
test failures in this change: CI currently requires
main@1ec20fd, while thisPR intentionally targets
qwen4-main-squashed, so the test jobs were skipped.CI States
Latest PR Test (Base): ❌ Run #33226754199
Latest PR Test (Extra): ❌ Run #33226754138
Latest PR Test (AMD ROCm 7.2): ❌ Run #33226754194