Files
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

388 lines
14 KiB
Python

from typing import Optional, Tuple, Union
import torch
from sglang.srt.layers.attention.hybrid_linear_attn_backend import MambaAttnBackendBase
from sglang.srt.layers.attention.linear.kernels.kda_triton import TritonKDAKernel
from sglang.srt.layers.attention.linear.utils import (
LinearAttnKernelBackend,
get_linear_attn_decode_backend,
get_linear_attn_prefill_backend,
)
from sglang.srt.layers.attention.mamba.causal_conv1d_triton import (
causal_conv1d_fn,
causal_conv1d_update,
)
from sglang.srt.layers.radix_linear_attention import RadixLinearAttention
from sglang.srt.utils import is_cpu, is_cuda, is_npu
from sglang.srt.utils.common import rank0_log
# KDA always uses the triton causal_conv1d_fn (no CUDA override).
# Only causal_conv1d_update needs platform-specific overrides for decode.
if is_npu():
from sgl_kernel_npu.mamba.causal_conv1d import causal_conv1d_update_npu
causal_conv1d_update = causal_conv1d_update_npu
elif is_cpu():
from sgl_kernel.mamba import causal_conv1d_update_cpu
causal_conv1d_update = causal_conv1d_update_cpu
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
from sglang.srt.model_executor.model_runner import ModelRunner
class KDAKernelDispatcher:
"""Dispatches KDA kernel calls to the appropriate backend per mode."""
def __init__(
self,
decode_backend: LinearAttnKernelBackend,
prefill_backend: LinearAttnKernelBackend,
):
triton_kernel = TritonKDAKernel()
if decode_backend.is_triton():
self.decode_kernel = triton_kernel
elif decode_backend.is_cutedsl():
if not is_cuda():
raise ValueError("KDA CuTe DSL backend requires CUDA")
from sglang.srt.layers.attention.linear.kernels.kda_cutedsl import (
CuteDSLKDAKernel,
)
self.decode_kernel = CuteDSLKDAKernel()
else:
raise ValueError(
f"Unsupported KDA decode backend: {decode_backend}. "
"KDA currently only supports 'triton'."
)
if prefill_backend.is_triton():
self.extend_kernel = triton_kernel
elif prefill_backend.is_flashkda():
from sglang.srt.layers.attention.linear.kernels.kda_flashkda import (
FlashKDAKernel,
)
self.extend_kernel = FlashKDAKernel()
elif prefill_backend.is_cutedsl():
if not is_cuda():
raise ValueError("KDA CuTe DSL backend requires CUDA")
from sglang.srt.layers.attention.linear.kernels.kda_cutedsl import (
CuteDSLKDAKernel,
)
cutedsl_kernel = CuteDSLKDAKernel()
if getattr(cutedsl_kernel, "supports_prefill", False):
# SM100 chunk prefill pipeline.
self.extend_kernel = cutedsl_kernel
else:
# CuTe DSL prefill kernels need SM100 (Blackwell); on older GPUs
# fall back to the Triton chunk kernel.
self.extend_kernel = triton_kernel
rank0_log(
"KDA cutedsl prefill needs SM100; falling back to Triton extend."
)
else:
raise ValueError(
f"Unsupported KDA prefill backend: {prefill_backend}. "
"KDA supports 'triton', 'flashkda', or 'cutedsl' "
"(cutedsl prefill needs SM100)."
)
self.supports_packed_decode = getattr(
self.decode_kernel, "supports_packed_decode", False
)
rank0_log(
f"KDA kernel dispatcher: decode={self.decode_kernel.__class__.__name__}, "
f"extend={self.extend_kernel.__class__.__name__} "
f"packed_decode={self.supports_packed_decode}"
)
def packed_decode(
self,
mixed_qkv: torch.Tensor,
a: torch.Tensor,
b: torch.Tensor,
*,
A_log: torch.Tensor,
dt_bias: torch.Tensor,
scale: float,
ssm_states: torch.Tensor,
cache_indices: torch.Tensor,
num_v_heads: int,
head_v_dim: int,
**kwargs,
) -> Optional[torch.Tensor]:
"""Attempt packed decode. Returns output tensor or None if the decode
kernel does not support packed decode."""
if not self.supports_packed_decode:
return None
return self.decode_kernel.packed_decode(
mixed_qkv,
a,
b,
A_log=A_log,
dt_bias=dt_bias,
scale=scale,
ssm_states=ssm_states,
cache_indices=cache_indices,
num_v_heads=num_v_heads,
head_v_dim=head_v_dim,
**kwargs,
)
def decode(
self,
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
a: torch.Tensor,
b: torch.Tensor,
*,
A_log: torch.Tensor,
dt_bias: torch.Tensor,
ssm_states: torch.Tensor,
cache_indices: torch.Tensor,
query_start_loc: torch.Tensor,
**kwargs,
) -> torch.Tensor:
return self.decode_kernel.decode(
q,
k,
v,
a,
b,
A_log=A_log,
dt_bias=dt_bias,
ssm_states=ssm_states,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
**kwargs,
)
def extend(
self,
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
g: torch.Tensor,
beta: torch.Tensor,
*,
ssm_states: torch.Tensor,
cache_indices: torch.Tensor,
query_start_loc: torch.Tensor,
**kwargs,
) -> torch.Tensor:
return self.extend_kernel.extend(
q,
k,
v,
g,
beta,
ssm_states=ssm_states,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
**kwargs,
)
class KDAAttnBackend(MambaAttnBackendBase):
"""Attention backend for KDA (Kimi Delta Attention) linear attention."""
def __init__(self, model_runner: ModelRunner):
super().__init__(model_runner)
decode_backend = get_linear_attn_decode_backend()
prefill_backend = get_linear_attn_prefill_backend()
self.kernel_dispatcher = KDAKernelDispatcher(decode_backend, prefill_backend)
def forward_decode(
self,
layer: RadixLinearAttention,
mixed_qkv: Union[torch.Tensor, Tuple[torch.Tensor, ...]],
a: torch.Tensor,
b: torch.Tensor,
**kwargs,
):
layer_cache = self.req_to_token_pool.mamba2_layer_cache(layer.layer_id)
conv_states = layer_cache.conv[0]
ssm_states = layer_cache.temporal
query_start_loc = self.forward_metadata.query_start_loc
cache_indices = self.forward_metadata.mamba_cache_indices
# ReplaySSM ring: per-layer ring slices + the once-per-forward per-row
# write cursor. All None unless --enable-linear-replayssm, so packed_decode
# falls through to the byte-identical legacy KDA path. KDA ships WITHOUT
# radix coordination for now, so force_flush is None/zeroed (the ring
# flushes only at the natural write_pos == L-1 wrap; set in the shared
# HybridLinearAttn metadata, which zeroes force_flush for KDA models).
# NOTE: ReplaySSM decode is a GDN (scalar-gate) bandwidth win; on KDA the
# per-K g_cache is K x larger and the reconstruction refolds the per-K
# decay every step, so it is correct but SLOWER than packed (a measured
# decode regression). Kept wired for correctness + the spec-decode path;
# not recommended for KDA decode. Revisit on Blackwell (more tensor-core
# throughput may flip the compute/bandwidth tradeoff).
replayssm_write_pos = getattr(
self.forward_metadata, "replayssm_write_pos", None
)
replayssm_force_flush = getattr(
self.forward_metadata, "replayssm_force_flush", None
)
replayssm_d = layer_cache.replayssm_d
replayssm_k = layer_cache.replayssm_k
replayssm_g = layer_cache.replayssm_g
qkv = causal_conv1d_update(
mixed_qkv,
conv_states.transpose(-1, -2),
layer.conv_weights,
layer.bias,
activation="silu",
conv_state_indices=cache_indices,
)
# Skip split + reshape by consuming the packed mixed_qkv directly in a
# single fused Triton kernel (KDA per-K gate variant of GDN PR #20627).
#
# The packed kernel hard-assumes one token per sequence (T=1): it has no
# query_start_loc / per-sequence loop. forward_decode is only entered in
# decode mode (see HybridLinearAttnBackend.forward dispatch), where each
# request contributes exactly one token, so #tokens == #requests. Multi-
# token-per-seq speculative paths (target_verify / draft_extend) go
# through forward_extend instead. Assert the invariant so a future
# routing change fails loudly rather than silently corrupting state.
if self.kernel_dispatcher.supports_packed_decode:
assert qkv.shape[0] == cache_indices.shape[0], (
"KDA packed decode requires one token per sequence (T=1): "
f"got {qkv.shape[0]} tokens for {cache_indices.shape[0]} requests."
)
return self.kernel_dispatcher.packed_decode(
mixed_qkv=qkv,
a=a,
b=b,
A_log=layer.A_log,
dt_bias=layer.dt_bias,
scale=layer.head_k_dim**-0.5,
ssm_states=ssm_states,
cache_indices=cache_indices,
num_v_heads=layer.num_v_heads,
head_v_dim=layer.head_v_dim,
replayssm_d=replayssm_d,
replayssm_k=replayssm_k,
replayssm_g=replayssm_g,
replayssm_write_pos=replayssm_write_pos,
replayssm_force_flush=replayssm_force_flush,
)
q, k, v = qkv.split([layer.q_dim, layer.k_dim, layer.v_dim], dim=-1)
q = q.unflatten(-1, (-1, layer.head_q_dim)).unsqueeze(0) # n (h d) -> 1 n h d
k = k.unflatten(-1, (-1, layer.head_k_dim)).unsqueeze(0) # n (h d) -> 1 n h d
v = v.unflatten(-1, (-1, layer.head_v_dim)).unsqueeze(0) # n (h d) -> 1 n h d
return self.kernel_dispatcher.decode(
q=q,
k=k,
v=v,
a=a,
b=b,
A_log=layer.A_log,
dt_bias=layer.dt_bias,
ssm_states=ssm_states,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
)
def forward_extend(
self,
layer: RadixLinearAttention,
forward_batch: ForwardBatch,
mixed_qkv: Union[torch.Tensor, Tuple[torch.Tensor, ...]],
a: torch.Tensor,
b: torch.Tensor,
**kwargs,
):
query_start_loc = self.forward_metadata.query_start_loc
cache_indices = self.forward_metadata.mamba_cache_indices
mamba_cache_params = self.req_to_token_pool.mamba2_layer_cache(layer.layer_id)
conv_states = mamba_cache_params.conv[0].transpose(-1, -2)
ssm_states = mamba_cache_params.temporal
has_initial_state = forward_batch.extend_prefix_lens > 0
splits = [layer.q_dim, layer.k_dim, layer.v_dim]
q, k, v = mixed_qkv.transpose(0, 1).split(splits, dim=0)
q_conv_weight, k_conv_weight, v_conv_weight = layer.conv_weights.split(
splits, dim=0
)
q_conv_state, k_conv_state, v_conv_state = conv_states.split(splits, dim=-2)
if layer.bias is not None:
q_bias, k_bias, v_bias = layer.bias.split(splits, dim=0)
else:
q_bias, k_bias, v_bias = None, None, None
q = causal_conv1d_fn(
q,
q_conv_weight,
q_bias,
activation="silu",
conv_states=q_conv_state,
has_initial_state=has_initial_state,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
seq_lens_cpu=forward_batch.extend_seq_lens_cpu,
).transpose(0, 1)
k = causal_conv1d_fn(
k,
k_conv_weight,
k_bias,
activation="silu",
conv_states=k_conv_state,
has_initial_state=has_initial_state,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
seq_lens_cpu=forward_batch.extend_seq_lens_cpu,
).transpose(0, 1)
v = causal_conv1d_fn(
v,
v_conv_weight,
v_bias,
activation="silu",
conv_states=v_conv_state,
has_initial_state=has_initial_state,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
seq_lens_cpu=forward_batch.extend_seq_lens_cpu,
).transpose(0, 1)
q = q.unflatten(-1, (-1, layer.head_q_dim)).unsqueeze(0) # n (h d) -> 1 n h d
k = k.unflatten(-1, (-1, layer.head_k_dim)).unsqueeze(0) # n (h d) -> 1 n h d
v = v.unflatten(-1, (-1, layer.head_v_dim)).unsqueeze(0) # n (h d) -> 1 n h d
core_attn_out = self.kernel_dispatcher.extend(
q=q,
k=k,
v=v,
g=a,
beta=b,
ssm_states=ssm_states,
cache_indices=cache_indices,
query_start_loc=query_start_loc,
A_log=layer.A_log,
dt_bias=layer.dt_bias,
lower_bound=getattr(layer, "lower_bound", None),
extend_seq_lens_cpu=forward_batch.extend_seq_lens_cpu,
# target_verify / draft_extend_v2 also reach forward_extend; they must
# stay rollback-able, so a kernel that commits state in place (e.g.
# FlashKDA) must not run for them.
is_spec_decode=(
forward_batch.forward_mode.is_target_verify()
or forward_batch.forward_mode.is_draft_extend_v2()
),
)
return core_attn_out