项目文件夹

文件
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

240 行
8.1 KiB
Python

"""Correctness tests for the split-KV EAGLE-verify attention kernel.
``verify_splitkv_fwd`` is a drop-in for ``extend_attention_fwd`` on the topk=1
causal (target-verify) path. These tests check:
(a) numerical parity with ``extend_attention_fwd`` on the pure-causal path
(the operative case at topk=1), across head dims / GQA ratios / prefix
lengths / extend lengths / KV scales;
(b) ``can_handle()`` rejects cases the kernel cannot serve bit-equivalently
(non-causal, sinks, sliding-window, logit-cap, ragged extend), so the
backend falls back to ``extend_attention_fwd``.
The topk>1 case is gated off in the backend (TritonAttnBackend enables this path
only when ``self.topk == 1``), since the kernel ignores the tree custom_mask;
that gate is exercised end-to-end by the nightly ROCm spec accuracy test.
GPU + Triton required. Runs on the CUDA PR lane and the AMD MI35x lane.
"""
import unittest
import torch
from sglang.kernels.ops.attention.extend_attention import (
extend_attention_fwd,
)
from sglang.kernels.ops.attention.verify_splitkv import (
can_handle,
verify_splitkv_fwd,
)
from sglang.test.ci.ci_register import register_amd_ci, register_cuda_ci
from sglang.test.test_utils import CustomTestCase
register_cuda_ci(est_time=30, stage="base-b", runner_config="1-gpu-small")
register_amd_ci(est_time=30, suite="stage-b-test-1-gpu-small-amd-mi35x")
# Split-KV accumulates the prefix in parallel splits and merges via log-sum-exp;
# it differs from the single-pass extend kernel only by reduction order. On-GPU
# (gfx950) the max abs diff across these shapes was ~2e-3 (rising to ~6e-2 only
# at much longer ctx); 2e-2 keeps a ~10x margin over the observed noise.
ATOL = 2e-2
RTOL = 1e-2
def _build_verify_inputs(
prefix_lens, l_ext, h_q, h_kv, head_dim, v_head_dim, dtype, device
):
"""Build a verify-shaped problem: a constant extend length ``l_ext`` per
sequence, with the prefix cache addressed contiguously by ``kv_indices``.
Returns the positional args shared by extend_attention_fwd / verify_splitkv_fwd.
"""
B = len(prefix_lens)
prefix_lens_t = torch.tensor(prefix_lens, dtype=torch.int32, device=device)
total_prefix = int(prefix_lens_t.sum())
# Prefix KV cache laid out contiguously; kv_indices is just arange over it.
# kv_indices is int64 in production (TritonAttnBackend allocates int64) -- match it.
k_buffer = torch.randn(total_prefix, h_kv, head_dim, dtype=dtype, device=device)
v_buffer = torch.randn(total_prefix, h_kv, v_head_dim, dtype=dtype, device=device)
kv_indptr = torch.zeros(B + 1, dtype=torch.int32, device=device)
kv_indptr[1:] = torch.cumsum(prefix_lens_t, 0)
kv_indices = torch.arange(total_prefix, dtype=torch.int64, device=device)
# Draft (extend) tensors: constant l_ext rows per sequence.
n_ext = B * l_ext
q_extend = torch.randn(n_ext, h_q, head_dim, dtype=dtype, device=device)
k_extend = torch.randn(n_ext, h_kv, head_dim, dtype=dtype, device=device)
v_extend = torch.randn(n_ext, h_kv, v_head_dim, dtype=dtype, device=device)
qo_indptr = torch.arange(0, n_ext + 1, l_ext, dtype=torch.int32, device=device)
return (
q_extend,
k_extend,
v_extend,
k_buffer,
v_buffer,
qo_indptr,
kv_indptr,
kv_indices,
l_ext,
)
@unittest.skipIf(not torch.cuda.is_available(), "GPU required")
class TestVerifySplitKV(CustomTestCase):
def _run_parity(
self,
prefix_lens,
l_ext=4,
h_q=16,
h_kv=2,
head_dim=256,
v_head_dim=256,
k_scale=1.0,
v_scale=1.0,
dtype=torch.bfloat16,
):
device = "cuda"
q, k, v, kb, vb, qo, kvp, kvi, mle = _build_verify_inputs(
prefix_lens, l_ext, h_q, h_kv, head_dim, v_head_dim, dtype, device
)
sm_scale = 1.0 / (head_dim**0.5)
# Reference: extend_attention_fwd, pure causal (custom_mask=None) -- the
# topk=1 operative case, with the same KV scales.
o_ref = torch.empty(q.shape[0], h_q, v_head_dim, dtype=dtype, device=device)
extend_attention_fwd(
q,
k,
v,
o_ref,
kb,
vb,
qo,
kvp,
kvi,
None,
True,
None,
mle,
k_scale,
v_scale,
sm_scale=sm_scale,
)
o_split = torch.empty_like(o_ref)
ran = verify_splitkv_fwd(
q,
k,
v,
o_split,
kb,
vb,
qo,
kvp,
kvi,
None,
True,
None,
mle,
k_scale,
v_scale,
sm_scale=sm_scale,
)
self.assertTrue(ran, "verify_splitkv_fwd must handle the topk=1 causal case")
torch.testing.assert_close(o_split, o_ref, atol=ATOL, rtol=RTOL)
def test_numerics_head_dim_256(self):
# head_dim=256 is the validated Qwen3 value (the tuned block config).
for prefix_lens in ([512, 512, 512], [768, 1536, 3072], [4096, 8192]):
with self.subTest(prefix_lens=prefix_lens):
self._run_parity(prefix_lens)
def test_numerics_head_dim_128(self):
# A head_dim without a tuned block entry must still be correct (default).
self._run_parity([1024, 2048], head_dim=128, v_head_dim=128)
def test_numerics_gqa_ratios(self):
# Sweep GQA group sizes incl. MQA (h_kv=1); the kv_group_num arithmetic
# in the kernel must be correct across ratios.
for h_q, h_kv in ((16, 1), (8, 1), (8, 2), (8, 4), (8, 8)):
with self.subTest(h_q=h_q, h_kv=h_kv):
self._run_parity([1024, 2048], h_q=h_q, h_kv=h_kv)
def test_numerics_extend_len_variants(self):
for l_ext in (1, 2, 4, 8):
with self.subTest(l_ext=l_ext):
self._run_parity([1024, 1024], l_ext=l_ext)
def test_numerics_with_kv_scales(self):
# Exercise the k_scale/v_scale dequant-multiplier path (same multipliers
# the fp8 KV-cache path applies); both kernels must apply them identically.
self._run_parity([1024, 2048], k_scale=0.5, v_scale=0.25)
# --- fallback: can_handle() must reject what the kernel can't serve --------
# (topk>1 is gated off in the backend, not here -- can_handle never inspects
# the tree custom_mask; see verify_splitkv.can_handle docstring.)
def _inputs(self):
return _build_verify_inputs(
[512, 512], 4, 16, 2, 256, 256, torch.bfloat16, "cuda"
)
def test_fallback_non_causal(self):
q, k, v, kb, vb, qo, kvp, kvi, mle = self._inputs()
self.assertFalse(
can_handle(q, k, v, kb, vb, qo, kvp, kvi, None, False, None, mle)
)
def test_fallback_exotic_features(self):
q, k, v, kb, vb, qo, kvp, kvi, mle = self._inputs()
self.assertFalse(
can_handle(
q,
k,
v,
kb,
vb,
qo,
kvp,
kvi,
None,
True,
None,
mle,
sinks=torch.zeros(16, device="cuda"),
)
)
self.assertFalse(
can_handle(
q,
k,
v,
kb,
vb,
qo,
kvp,
kvi,
None,
True,
None,
mle,
sliding_window_size=128,
)
)
self.assertFalse(
can_handle(
q, k, v, kb, vb, qo, kvp, kvi, None, True, None, mle, logit_cap=30.0
)
)
def test_fallback_ragged_extend(self):
# q rows (bs*l_ext) inconsistent with the claimed max_len_extend -> reject.
q, k, v, kb, vb, qo, kvp, kvi, mle = self._inputs()
self.assertFalse(
can_handle(q, k, v, kb, vb, qo, kvp, kvi, None, True, None, mle + 1)
)
if __name__ == "__main__":
unittest.main()