Repository navigation
[Fix] Don't write conv state from the fused KDA verify kernel - #39524
Conversation
…tate-race # Conflicts: # python/sglang/kernels/ops/attention/fla/fused_kda_conv_recurrent_verify.py # test/registered/kernels/test_fused_kda_conv_recurrent_verify.py
|
/rerun-test test/registered/kernels/test_fused_kda_conv_recurrent_verify.py |
|
|
Results for 🚀 |
|
Results for 🚀 |
|
/rerun-test test/registered/kernels/test_fused_kda_conv_recurrent_verify.py test/registered/e2e/models/test_kimi_linear_models.py test/registered/e2e/models_large/test_ling_2_6_flash.py |
|
Results for 🚀 🚀 🚀 🚀 |
…oject#39524) Co-authored-by: mmangkad <mohammad.angkad@radixark.ai> (cherry picked from commit e332e1b)
…nomy The ported sgl-project#39524 regression test landed at test/registered/kernels/ root (upstream's pre-sgl-project#40294 path), which the fork's registered-test checker rejects: kernel tests must live under test/registered/kernels/{ops,benchmark}/ <group>/ and use a *-kernel-* suite. Upstream moved it in sgl-project#40294 and switched its suite to base-b-kernel-unit; apply the same here so the regression test actually runs in the kernel CI lane.
The sgl-project#39524 rewrite dropped the ROCm defaults, so GLM TP4 verify ran at four warps and BV=4: 2.8x slower than the unfused pair at B=8 T=6 and no longer bit-exact. Default ROCm to one warp and use BV=16 from B=3 at the GLM shapes, as before the rewrite. MI355X, T=6 B=8: 80.8 -> 22.0 us (unfused 29.4 us); output and intermediate SSM bit-exact at all 12 measured shapes.
Upstream sgl-project#39524 dropped the inline-asm v_mul_f32 conv product, so LLVM contracts the fp32 conv products into FMAs on ROCm. That breaks bit-exactness against the unfused conv path for fp32 conv weights and slows B8/B16. Re-add _conv_product behind ROUND_CONV_PRODUCTS for HIP with fp32 conv weights.
The 2-ulp rtol and 1e-6 atol date from 2026-09-15, when this branch still compared with torch.equal; upstream sgl-project#39524 later set one bf16 ulp (rtol=2**-7, atol=1e-7), and the merge kept the looser form for every case. This PR changes nothing in the kernel's CUDA path (product rounding, BV16 and the one-warp default are HIP-only), and every case, including the new GLM shapes, passes at main's tolerance on gfx950. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Motivation
fused_kda_conv_gating_verifyrolled the conv state back intoconv_stateat the end of the kernel. Every V tile loads that same Q/K conv history at entry, but onlyi_v == 0writes it, so a tile scheduled in a later wave reads what the owner already overwrote.The writeback is also dead: verify is speculative, and the commit scatter sets
conv_statefrom the selected intermediate window.accept_lensis at least 1, solast_correct_step_indicesis never negative for a real request and the scatter always overwrites.So the stores are removed rather than guarded.
conv_stateand the SSM state are read-only in verify.Modifications
tl.store(cs_base, ...)at the end offused_kda_conv_gating_verify_kernelconv_statemust come back untouched; output must not vary with CTA schedulingReached only with
SGLANG_OPT_FUSED_KDA_VERIFY=1(default off), on the KDA Triton verify path attopk == 1.How the race shows
H=1 with HV=16, so 16 V tiles share one Q/K history. Same inputs, against the unfused pair:
Removing the stores makes both configurations identical. The residual ~1 ulp is reduction-order difference and is unaffected by the fix.
Accuracy Tests
Ling-3.0-flash BF16, 4x GB300 TP4, NEXTN, fused verify on. Full GSM8K, thinking on,
temperature=1.0,top_p=0.95,max_tokens=8192, 1 repeat.Unchanged — the gap is inside the ~0.55pp 1-sigma band at n=1319. The race is below eval resolution when the grid fits one wave.
Speed Tests and Profiling
Same server, 8192 in / 1024 out at concurrency 1, 64 warmup,
--flush-cache, 3 runs per arm. Accept length 3.01 on all six.+3.22%, arms disjoint. The kernel does strictly less work with the stores gone.
Checklist
pre-commitcleantest_fused_kda_conv_recurrent_verify.py; all 9 fail against the unfixed kernelCI States
Latest PR Test (Base): ❌ Run #35569381582
Latest PR Test (Extra): ❌ Run #35569381392
Latest PR Test (AMD ROCm 10): ❌ Run #35569381525