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

318 lines
12 KiB
Python

from functools import lru_cache
from typing import TYPE_CHECKING, List, Tuple, Union
import torch
import triton
import triton.language as tl
from sglang.srt.environ import envs
from sglang.srt.layers.dp_attention import (
DpPaddingMode,
)
from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import (
is_in_breakable_cuda_graph,
)
from sglang.srt.model_executor.runner_backend_utils.tc_piecewise_cuda_graph import (
is_in_tc_piecewise_cuda_graph,
)
from sglang.srt.runtime_context import get_parallel, get_server_args
from sglang.srt.utils import get_bool_env_var, is_cuda, is_hip
from sglang.srt.utils.common import ceil_align, ceil_div
@lru_cache(maxsize=1)
def aiter_can_use_preshuffle_paged_mqa() -> bool:
"""Whether aiter's preshuffle paged MQA / cache kernels can be used on this runtime.
aiter's ``deepgemm_fp8_paged_mqa_logits`` only supports ``KVBlockSize > 1`` and
``Preshuffle=True`` on its gluon kernel path. The gluon path is enabled when
Triton >= 3.5.0, OR when ``AITER_ENABLE_AOT_GLUON_PA_MQA_LOGITS=1`` is set
(which additionally requires that the AOT gluon kernel artifacts ship inside
the aiter wheel/image). Otherwise aiter asserts ``KVBlockSize == 1`` and
refuses ``Preshuffle=True``.
sglang's DSA indexer uses this single decision to pick:
* ``page_size``: 64 (preshuffle) vs 1 (legacy) on ROCm
* ``Preshuffle`` / ``preshuffle`` flags on the aiter MQA + cache kernels
* ``get_page_table_64`` vs ``get_page_table_1`` on the metadata
* whether ``GetKAndS.execute`` uses the aiter or the triton implementation
The result is cached so the cost is paid once per process.
Set ``SGLANG_DSA_HIP_DISABLE_PRESHUFFLE=1`` to force the legacy path even when
the gluon kernel would otherwise be available (useful for CI bisection).
``SGLANG_NSA_HIP_DISABLE_PRESHUFFLE`` is a deprecated alias.
"""
if not is_hip():
return False
if not get_bool_env_var("SGLANG_USE_AITER"):
return False
if envs.SGLANG_DSA_HIP_DISABLE_PRESHUFFLE.get():
return False
if get_bool_env_var("AITER_ENABLE_AOT_GLUON_PA_MQA_LOGITS"):
return True
try:
from packaging.version import Version
return Version(Version(triton.__version__).base_version) >= Version("3.5.0")
except Exception:
return False
if TYPE_CHECKING:
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
def compute_dsa_seqlens(original_seq_lens, dsa_index_topk: int):
return original_seq_lens.clamp(max=dsa_index_topk)
def is_dsa_enable_prefill_cp():
return get_server_args().enable_dsa_prefill_context_parallel
def is_dsa_prefill_cp_in_seq_split():
return (
is_dsa_enable_prefill_cp()
and get_server_args().dsa_prefill_cp_mode == "in-seq-split"
)
def is_dsa_prefill_cp_round_robin_split():
return (
is_dsa_enable_prefill_cp()
and get_server_args().dsa_prefill_cp_mode == "round-robin-split"
)
# Structural surface where the graph DSA split-op dispatch (DSA indexer) and the
# MLA BMM-into-attention fusion apply: a non-speculative extend (prefill) running
# inside a piecewise/breakable CUDA graph. Both fusions are now on by default on
# this surface (no feature flag); each adds its own extra carve-outs at its call
# site (e.g. the indexer also excludes DSA prefill context parallelism).
def is_graph_dsa_split_op_surface(forward_batch: "ForwardBatch") -> bool:
return (
is_cuda()
and (is_in_tc_piecewise_cuda_graph() or is_in_breakable_cuda_graph())
and forward_batch.forward_mode.is_extend_without_speculative()
)
def can_dsa_prefill_cp_round_robin_split(forward_batch: "ForwardBatch"):
if not forward_batch.forward_mode.is_context_parallel_extend():
return False
cp_size = get_parallel().attn_cp_size
seq_len = sum(forward_batch.extend_seq_lens_cpu)
return (
is_dsa_prefill_cp_round_robin_split()
and seq_len > 0
and seq_len >= cp_size
and cp_size > 1
)
def dsa_cp_round_robin_split_data(input_: Union[torch.Tensor, List]):
"""
# for round-robin-split, split the tokens evenly according to the rule of token_idx % cp_size.
| +-----------before split------------+|
| token0, token1, token2, token3, token4, token5, token6, token7, ...
|
| +--------------result-------------------+
| dp_atten_tp0: token0, token4, token8, token12, token16, ... |
| dp_atten_tp1: token1, token5, token9, token13, token17, ... |
| dp_atten_tp2: token2, token6, token10, token14, token18, ... |
| dp_atten_tp3: token3, token7, token11, token15, token19, ... |
| +-------------------------+
"""
cp_size = get_parallel().attn_cp_size
cp_rank = get_parallel().attn_cp_rank
if isinstance(input_, (tuple, list)):
indices = range(cp_rank, len(input_), cp_size)
return input_[indices]
tokens = len(input_)
if tokens % cp_size != 0:
cur_len = tokens // cp_size + (tokens % cp_size > cp_rank)
if cur_len == 0:
return input_.new_empty(0, *input_.shape[1:])
indices = torch.arange(cp_rank, tokens, cp_size, device=input_.device)
return input_[indices]
# for torch device tensor
return input_.view(-1, cp_size, *input_.shape[1:])[:, cp_rank].contiguous()
def cal_padded_tokens(forward_batch: "ForwardBatch"):
# Consistent with the padding calculation logic in ForwardBatch.prepare_mlp_sync_batch,
# calculate the actual token length after padding when attn_tp_size > 1 or in the MAX_LEN padding mode.
from sglang.srt.layers.utils.cp_utils import get_cp_padding_align_size
global_num_tokens = forward_batch.global_num_tokens_cpu.copy()
sync_group_size = len(global_num_tokens)
attn_cp_size = get_parallel().attn_cp_size
# Must match the CP padding in ForwardBatch.prepare_mlp_sync_batch.
cp_align_size = get_cp_padding_align_size()
for i in range(sync_group_size):
global_num_tokens[i] = ceil_align(global_num_tokens[i], cp_align_size)
dp_padding_mode = DpPaddingMode.get_dp_padding_mode(
forward_batch.is_extend_in_batch, global_num_tokens
)
if dp_padding_mode.is_max_len():
tokens = max(global_num_tokens)
elif len(global_num_tokens) > 1:
tokens = global_num_tokens[get_parallel().attn_dp_rank]
else:
tokens = global_num_tokens[0]
if can_dsa_prefill_cp_round_robin_split(forward_batch):
tokens = ceil_div(tokens, attn_cp_size)
return tokens
def pad_dsa_cache_seqlens(forward_batch: "ForwardBatch", dsa_cache_seqlens):
attn_cp_size = get_parallel().attn_cp_size
needs_cp_pad = attn_cp_size > 1 and can_dsa_prefill_cp_round_robin_split(
forward_batch
)
needs_dp_pad = forward_batch.global_num_tokens_cpu is not None
if not needs_cp_pad and not needs_dp_pad:
return dsa_cache_seqlens
tokens = cal_padded_tokens(forward_batch)
pad_len = tokens - dsa_cache_seqlens.shape[0]
if pad_len > 0:
dsa_cache_seqlens = torch.cat(
[
dsa_cache_seqlens,
dsa_cache_seqlens.new_zeros(pad_len, *dsa_cache_seqlens.shape[1:]),
]
)
return dsa_cache_seqlens
def can_dsa_cp_split(seq_len: int, cp_size: int, use_dsa: bool, forward_batch):
if is_dsa_prefill_cp_round_robin_split():
cur_cp_seq_len = seq_len // cp_size
assert (
seq_len % cp_size == 0
), f"seq_len {seq_len} is not divisible by cp_size {cp_size} when dsa_prefill_cp_mode is round-robin-split"
else:
# TODO current just support prefill batch=1 and len(input_ids) > self.cp_size * 2
# Note: (self.cp_size * 2) To achieve load balancing for seq computation,
# the seq data needs to be divided and recombined at twice the size of cp_size.
cur_cp_seq_len = seq_len // (cp_size * 2)
if (
cur_cp_seq_len != 0
and cp_size > 1
and use_dsa
and forward_batch.forward_mode.is_context_parallel_extend()
and is_dsa_enable_prefill_cp()
and sum(forward_batch.extend_seq_lens_cpu) >= cp_size
):
return True
else:
return False
@triton.jit
def dsa_cp_round_robin_split_q_seqs_kernel(
in_seqs_ptr,
out_seqs_ptr,
bs_idx_ptr,
tokens: tl.constexpr,
cp_size: tl.constexpr,
cp_rank: tl.constexpr,
):
extra_seq = 0
bs_idx = 0
for bs in range(tokens):
cur_len = tl.load(in_seqs_ptr + bs)
cur_len += extra_seq
cur_seq = cur_len // cp_size + (cur_len % cp_size > cp_rank)
if cur_seq > 0:
tl.store(bs_idx_ptr + bs_idx, bs)
tl.store(out_seqs_ptr + bs_idx, cur_seq)
bs_idx += 1
extra_seq = cur_len - cur_seq * cp_size
def dsa_cp_round_robin_split_q_seqs_cpu(extend_seqs):
cp_size = get_parallel().attn_cp_size
cp_rank = get_parallel().attn_cp_rank
extra_seq = 0
q_seqs = []
for bs, cur_len in enumerate(extend_seqs):
cur_len += extra_seq
cur_seq = cur_len // cp_size + int(cur_len % cp_size > cp_rank)
q_seqs.append(cur_seq)
extra_seq = cur_len - cur_seq * cp_size
bs_idx = list([i for i, x in enumerate(q_seqs) if x > 0])
q_seqs = [q_len for q_len in q_seqs if q_len > 0]
return q_seqs, bs_idx
def dsa_cp_round_robin_split_q_seqs(
extend_seqs_cpu, extend_seqs
) -> Tuple[List, torch.Tensor, List, torch.Tensor]:
"""
round-robin-split distributes tokens across ranks based on token_idx % cp_size.
Return:
ret_q_lens_cpu(List) and ret_q_lens(torch.Tensor): the partitioned length (excluding zeros) on the current cp rank
for each sequence after distribution across cp ranks.
bs_idx_cpu(List) and bs_idx(torch.Tensor): marks which sequences are ultimately selected,
i.e., those with a partitioned length greater than zero.
"""
cp_size = get_parallel().attn_cp_size
cp_rank = get_parallel().attn_cp_rank
# len(ret_q_lens_cpu) == len(bs_idx_cpu)
ret_q_lens_cpu, bs_idx_cpu = dsa_cp_round_robin_split_q_seqs_cpu(extend_seqs_cpu)
ret_q_lens = torch.empty(
(len(bs_idx_cpu),), device=extend_seqs.device, dtype=extend_seqs.dtype
)
bs_idx = torch.empty(
(len(bs_idx_cpu),), device=extend_seqs.device, dtype=torch.int32
)
grid = (1,)
dsa_cp_round_robin_split_q_seqs_kernel[grid](
extend_seqs, ret_q_lens, bs_idx, len(extend_seqs), cp_size, cp_rank
)
return ret_q_lens_cpu, ret_q_lens, bs_idx_cpu, bs_idx
def dsa_use_prefill_cp(forward_batch, dsa_enable_prefill_cp=None):
if dsa_enable_prefill_cp is None:
dsa_enable_prefill_cp = is_dsa_enable_prefill_cp()
if (
forward_batch.attn_cp_metadata is not None
and dsa_enable_prefill_cp
and forward_batch.forward_mode.is_context_parallel_extend()
):
return True
else:
return False
def fp8_mqa_logits_ceil_to_ue8m0(x: torch.Tensor) -> torch.Tensor:
return torch.pow(2.0, torch.ceil(torch.log2(x.abs())))
def fp8_mqa_logits_make_fused_kv(
kv_fp8: torch.Tensor,
kv_scales: torch.Tensor,
block_kv: int,
head_dim: int,
) -> torch.Tensor:
num_phys_blocks = kv_fp8.shape[0]
per_token_size = head_dim + 4
block_bytes = block_kv * per_token_size
scale_offset = block_kv * head_dim
fused = torch.zeros(
num_phys_blocks, block_bytes, dtype=torch.uint8, device=kv_fp8.device
)
for blk in range(num_phys_blocks):
fused[blk, :scale_offset] = kv_fp8[blk].view(torch.uint8).reshape(-1)
fused[blk, scale_offset:] = (
kv_scales[blk].float().contiguous().view(torch.uint8).reshape(-1)
)
return fused.view(num_phys_blocks, block_kv, 1, per_token_size)