[DSA] Integrate Q8KV8 FP8 Sparse MLA Prefill into the DSA Backend (DeepSeek-V3.2) (#30514)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Xiaoyu Zhang <1182563586@qq.com>
This commit is contained in:
Ho-Ren (Jack) Chuang
2026-07-19 11:58:16 +08:00
committed by GitHub
co-authored by Claude Opus 4.8 Xiaoyu Zhang
parent cce5fe7696
commit b8ec544946
10 changed files with 801 additions and 95 deletions
@@ -9,7 +9,7 @@ import torch
from sglang.srt.utils import is_sm90_supported
from sglang.test.ci.ci_register import register_cuda_ci
register_cuda_ci(est_time=120, stage="base-b-kernel-unit", runner_config="1-gpu-large")
register_cuda_ci(est_time=240, stage="base-b-kernel-unit", runner_config="1-gpu-large")
DTYPE_FP8 = torch.float8_e4m3fn
@@ -417,5 +417,190 @@ def test_sparse_mla_q8kv8_prefill_rejects_bad_buffers():
_call(d_v=256)
# ---------------------------------------------------------------------------
# End-to-end-discovered corner-case gates.
#
# Everything ABOVE (matches_reference / corner_cases / precision /
# no_alias_between_calls / caller_owned_buffers / rejects_bad_buffers) is the
# original unit suite: small, all-valid (or topk_length-bounded) shapes checked
# against a reference that REPRODUCES the kernel's own clamp semantics. That
# suite is blind to three bug classes that only surface under real
# DeepSeek-V3.2 serving; the gates below reproduce them as standalone kernel
# tests:
#
# 1. masked -1-sentinel SEMANTICS on few-valid rows (ctx << topk): pad slots
# must contribute NOTHING to the softmax denominator. This needs a MASKED
# (-inf) fp32 reference -- a reference that mimics the kernel's own clamp
# is blind to the bug.
# 2. s_q ENVELOPE to 6144: first-band NaNs from an is_kv_valid data race that
# only appears past s_q=2048 (never exercised above).
# 3. LARGE S_KV (65536) / large index values: gathered multi-request buffers
# reach tens of thousands of rows in e2e; the suite above used s_kv<=1024.
#
# These use h=128 (the real DeepSeek head count) and large s_q/s_kv, so they are
# heavier than the suite above; same SM90 skipif. They also DOCUMENT that the
# kernel is run-to-run nondeterministic at the fp8 noise floor, so they compare
# against an fp32 reference (never bitwise / self-consistency).
# ---------------------------------------------------------------------------
_D_FULL = 576 # nope(512) + rope(64): the real DeepSeek MLA absorbed q/kv width
def _ref_masked_blocked(q, kv, indices, sm_scale, d_v, row_start, row_end):
"""fp32 reference with PROPER -1 masking (pad slots -> -inf), computed over a
block of query rows [row_start, row_end) to bound peak memory. Unlike
``_torch_sparse_attention_ref`` (which bounds validity via topk_length and so
reproduces the kernel's clamp), this masks every -1 index out of the softmax,
making it sensitive to the denominator-pollution bug."""
q_f = q.float()
kv_f = kv.float()[:, 0, :]
idx_block = indices[row_start:row_end, 0, :].long()
gathered = kv_f[idx_block.clamp(min=0)]
scores = torch.einsum("qhd,qkd->qhk", q_f[row_start:row_end], gathered) * sm_scale
scores = scores.masked_fill((idx_block < 0)[:, None, :], float("-inf"))
probs = torch.softmax(scores, dim=-1)
return torch.einsum("qhk,qkd->qhd", probs, gathered[:, :, :d_v])
@pytest.mark.skipif(
not _sm90_available(), reason="Q8KV8 sparse prefill requires SM90 CUDA"
)
@pytest.mark.parametrize("s_q", [2048, 4096])
def test_sparse_mla_q8kv8_prefill_masked_sentinels(s_q: int):
"""NEW gate (bug class 1): causal -1 structure (row i has min(1+i, topk)
valid slots, the rest -1). The kernel must mask pad slots out of the softmax
denominator. Checked against a MASKED (-inf) fp32 reference; a reference
that reproduced the kernel's clamp would be blind to this.
Gate: per-band cos > 0.97 AND magnitude ratio > 0.9
(the denominator-pollution bug crushes magnitude 50-2000x, unmistakable even
under fp8 noise)."""
from sglang.jit_kernel.sparse_mla_q8kv8_prefill_sm90 import (
sparse_mla_q8kv8_prefill_fwd,
)
h, topk, band, n = 128, 2048, 512, 4608
s_kv = n + topk
g = torch.Generator(device="cuda").manual_seed(11)
q = torch.randn((s_q, h, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
kv = torch.zeros((s_kv, H_KV, _D_FULL), dtype=DTYPE_FP8, device="cuda")
kv[:n] = torch.randn((n, H_KV, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
idx = torch.full((s_q, H_KV, topk), -1, dtype=torch.int32, device="cuda")
slot = torch.arange(topk, device="cuda")
valid = torch.clamp(1 + torch.arange(s_q, device="cuda"), max=topk)
rnd = torch.randint(
0, n, (s_q, topk), dtype=torch.int32, device="cuda", generator=g
)
idx[:, 0, :] = torch.where(
slot[None, :] < valid[:, None], rnd, torch.full_like(rnd, -1)
)
one = torch.ones(1, dtype=torch.float32, device="cuda")
sm_scale = 1.0 / math.sqrt(_D_FULL)
out, _, _ = sparse_mla_q8kv8_prefill_fwd(
q=q, kv=kv, indices=idx, sm_scale=sm_scale, q_scale=one, kv_scale=one, d_v=D_V
)
torch.cuda.synchronize()
worst_cos, worst_mag = 1.0, 1.0
for s in range(0, s_q, band):
e = min(s + band, s_q)
ref = _ref_masked_blocked(q, kv, idx, sm_scale, D_V, s, e)
ob = out[s:e].float()
cos = torch.nn.functional.cosine_similarity(
ob.reshape(-1), ref.reshape(-1), dim=0
).item()
mag = (ob.norm() / ref.norm().clamp(min=1e-9)).item()
worst_cos = min(worst_cos, cos)
if mag < 1.0:
worst_mag = min(worst_mag, mag)
del ref, ob
torch.cuda.empty_cache()
print(
f"\n masked-sentinels s_q={s_q}: worst cos={worst_cos:.4f} "
f"worst |out|/|ref|={worst_mag:.3f}"
)
assert worst_cos > 0.97, f"cos {worst_cos:.4f} <= 0.97 (denominator pollution?)"
assert worst_mag > 0.9, f"mag {worst_mag:.3f} <= 0.9 (denominator pollution?)"
@pytest.mark.skipif(
not _sm90_available(), reason="Q8KV8 sparse prefill requires SM90 CUDA"
)
@pytest.mark.parametrize("s_q", [2048, 4096, 6144])
def test_sparse_mla_q8kv8_prefill_sq_envelope(s_q: int):
"""NEW gate (bug class 2): all-valid correctness across the s_q envelope.
s_q=6144 previously produced first-band NaNs (an is_kv_valid data race that
only appears past s_q=2048)."""
from sglang.jit_kernel.sparse_mla_q8kv8_prefill_sm90 import (
sparse_mla_q8kv8_prefill_fwd,
)
h, topk, s_kv, band = 128, 2048, 8192, 1024
g = torch.Generator(device="cuda").manual_seed(7)
q = torch.randn((s_q, h, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
kv = torch.randn((s_kv, H_KV, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
idx = torch.randint(
0, s_kv, (s_q, H_KV, topk), dtype=torch.int32, device="cuda", generator=g
)
one = torch.ones(1, dtype=torch.float32, device="cuda")
sm_scale = 1.0 / math.sqrt(_D_FULL)
out, _, _ = sparse_mla_q8kv8_prefill_fwd(
q=q, kv=kv, indices=idx, sm_scale=sm_scale, q_scale=one, kv_scale=one, d_v=D_V
)
torch.cuda.synchronize()
has_nan = torch.isnan(out.float()).any().item()
worst_cos = 1.0
for s in range(0, s_q, band):
e = min(s + band, s_q)
ref = _ref_masked_blocked(q, kv, idx, sm_scale, D_V, s, e)
cos = torch.nn.functional.cosine_similarity(
out[s:e].float().reshape(-1), ref.reshape(-1), dim=0
).item()
worst_cos = min(worst_cos, cos)
del ref
torch.cuda.empty_cache()
print(f"\n s_q-envelope s_q={s_q}: nan={has_nan} worst cos={worst_cos:.4f}")
assert not has_nan, f"NaN in output at s_q={s_q} (is_kv_valid race)"
assert worst_cos > 0.99, f"cos {worst_cos:.4f} <= 0.99"
@pytest.mark.skipif(
not _sm90_available(), reason="Q8KV8 sparse prefill requires SM90 CUDA"
)
def test_sparse_mla_q8kv8_prefill_large_skv():
"""NEW gate (bug class 3): large gathered buffers / large index values
(s_kv=65536, indices in [33000, 65536)). E2E multi-request gather buffers
reach tens of thousands of rows; the suite above used s_kv<=1024."""
from sglang.jit_kernel.sparse_mla_q8kv8_prefill_sm90 import (
sparse_mla_q8kv8_prefill_fwd,
)
h, topk, s_kv, s_q = 128, 2048, 65536, 2048
g = torch.Generator(device="cuda").manual_seed(13)
q = torch.randn((s_q, h, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
kv = torch.randn((s_kv, H_KV, _D_FULL), device="cuda", generator=g).to(DTYPE_FP8)
idx = torch.randint(
33000, s_kv, (s_q, H_KV, topk), dtype=torch.int32, device="cuda", generator=g
)
one = torch.ones(1, dtype=torch.float32, device="cuda")
sm_scale = 1.0 / math.sqrt(_D_FULL)
out, _, _ = sparse_mla_q8kv8_prefill_fwd(
q=q, kv=kv, indices=idx, sm_scale=sm_scale, q_scale=one, kv_scale=one, d_v=D_V
)
torch.cuda.synchronize()
ref = _ref_masked_blocked(q, kv, idx, sm_scale, D_V, 0, 1024)
cos = torch.nn.functional.cosine_similarity(
out[:1024].float().reshape(-1), ref.reshape(-1), dim=0
).item()
print(f"\n large-S_KV={s_kv}: band-0 cos={cos:.4f}")
assert cos > 0.99, f"cos {cos:.4f} <= 0.99"
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-v", "-s"]))