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

468 lines
15 KiB
Python

from typing import TYPE_CHECKING, Optional
import torch
import triton
import triton.language as tl
if TYPE_CHECKING:
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
@triton.jit
def get_num_kv_splits_triton(
num_kv_splits_ptr,
seq_lens_ptr,
num_seq,
num_group,
num_head,
num_kv_head,
max_kv_splits,
device_core_count,
MAX_NUM_SEQ: tl.constexpr,
):
# TODO: this method is tunable, we need more online serving data to tune it
offs_seq = tl.arange(0, MAX_NUM_SEQ)
mask_seq = offs_seq < num_seq
seq_lens = tl.load(seq_lens_ptr + offs_seq, mask=mask_seq, other=0)
max_seq_len = tl.max(seq_lens)
seq_lens = tl.load(seq_lens_ptr + offs_seq, mask=mask_seq, other=max_seq_len)
min_seq_len = tl.min(seq_lens)
if max_seq_len * 8 < min_seq_len * 10:
min_seq_len = max_seq_len
max_kv_splits_1 = tl.minimum(tl.cdiv(max_seq_len, min_seq_len), max_kv_splits)
kv_chunk_size_1 = tl.cdiv(max_seq_len, max_kv_splits_1)
# NOTE: this is a hack to let num_kv_split grows up with seqlen gradually
ext_seq_len = tl.cast(max_seq_len, tl.float32) / 64.0
ext_device_core_count = tl.cast(
device_core_count * tl.maximum(tl.log2(ext_seq_len), 1.0), tl.int32
)
block_h, num_kv_group = 16, num_head // num_kv_head
if num_kv_group == 1:
token_grid = num_seq * num_group * num_head
else:
# from triton_ops/decode_attention.py:_decode_grouped_att_m_fwd
block_h = tl.minimum(block_h, num_kv_group)
token_grid = num_seq * num_group * tl.cdiv(num_head, block_h)
max_kv_splits_2 = tl.minimum(
tl.cdiv(ext_device_core_count, token_grid), max_kv_splits
)
kv_chunk_size_2 = tl.cdiv(max_seq_len, max_kv_splits_2)
num_kv_splits = tl.maximum(
tl.cdiv(seq_lens, kv_chunk_size_1), tl.cdiv(seq_lens, kv_chunk_size_2)
)
offs_token = offs_seq * num_group
mask_token = offs_token < num_seq * num_group
for i in range(0, num_group):
tl.store(num_kv_splits_ptr + i + offs_token, num_kv_splits, mask=mask_token)
@triton.jit
def _prepare_swa_spec_page_table_kernel(
dst_ptr,
src_a_ptr,
src_b_ptr,
seq_len_a_ptr,
seq_len_b_ptr,
dst_stride_m,
dst_stride_n,
a_stride_m,
a_stride_n,
b_stride_m,
b_stride_n,
LEN_A: tl.constexpr,
LEN_B: tl.constexpr,
REPEAT_STEP: tl.constexpr,
BLOCK_N: tl.constexpr,
):
pid_m = tl.program_id(0)
pid_n = tl.program_id(1)
idx_a = pid_m // REPEAT_STEP
idx_b = pid_m
seq_len_a = tl.load(seq_len_a_ptr + idx_a)
seq_len_b = tl.load(seq_len_b_ptr + idx_b)
offs_n = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
total_len = seq_len_a + seq_len_b
if pid_n * BLOCK_N >= total_len:
return
mask = offs_n < total_len
dst = dst_ptr + pid_m * dst_stride_m + offs_n * dst_stride_n
if (pid_n + 1) * BLOCK_N < seq_len_a:
a_ptr = src_a_ptr + idx_a * a_stride_m + offs_n * a_stride_n
a_mask = mask & (offs_n < LEN_A)
val = tl.load(a_ptr, mask=a_mask, other=0)
tl.store(dst, val, mask=mask)
elif pid_n * BLOCK_N >= seq_len_a:
offs_b = offs_n - seq_len_a
b_ptr = src_b_ptr + idx_b * b_stride_m + offs_b * b_stride_n
b_mask = mask & (offs_b < LEN_B)
val = tl.load(b_ptr, mask=b_mask, other=0)
tl.store(dst, val, mask=mask)
else:
# mixed part
a_offs = offs_n
a_mask = (a_offs < seq_len_a) & (a_offs < LEN_A)
a_ptr = src_a_ptr + idx_a * a_stride_m + a_offs * a_stride_n
a_val = tl.load(a_ptr, mask=a_mask, other=0)
b_offs = offs_n - seq_len_a
b_mask = (b_offs >= 0) & (b_offs < seq_len_b) & (b_offs < LEN_B)
b_ptr = src_b_ptr + idx_b * b_stride_m + b_offs * b_stride_n
b_val = tl.load(b_ptr, mask=b_mask, other=0)
result = tl.where(offs_n < seq_len_a, a_val, b_val)
tl.store(dst, result, mask=mask)
def prepare_swa_spec_page_table_triton(
page_table_dst: torch.Tensor,
page_table_a: torch.Tensor,
page_table_b: torch.Tensor, # expand page table
seq_len_a: torch.Tensor,
seq_len_b: torch.Tensor, # expand seq lens
speculative_num_draft_tokens: int,
):
# concat page_table and expand page_table by kv seq length
bs = seq_len_a.numel()
bs_expand = seq_len_b.numel()
assert bs_expand == bs * speculative_num_draft_tokens
LEN_A = page_table_a.shape[1]
LEN_B = page_table_b.shape[1]
LEN_OUT = LEN_A + LEN_B
REPEAT_STEP = speculative_num_draft_tokens
BLOCK_N = 256
grid = (bs_expand, triton.cdiv(LEN_OUT, BLOCK_N))
_prepare_swa_spec_page_table_kernel[grid](
page_table_dst,
page_table_a,
page_table_b,
seq_len_a,
seq_len_b,
page_table_dst.stride(0),
page_table_dst.stride(1),
page_table_a.stride(0),
page_table_a.stride(1),
page_table_b.stride(0),
page_table_b.stride(1),
LEN_A=LEN_A,
LEN_B=LEN_B,
REPEAT_STEP=REPEAT_STEP,
BLOCK_N=BLOCK_N,
num_warps=4,
)
@triton.jit
def _fused_metadata_kernel_general(
# Input tensors
seq_lens,
seq_lens_stride_0,
req_to_token,
req_to_token_stride_0,
req_to_token_stride_1,
req_pool_indices,
req_pool_indices_stride_0,
# Output buffers
cache_seqlens_int32,
cache_seqlens_int32_stride_0,
cu_seqlens_k,
cu_seqlens_k_stride_0,
page_table,
page_table_stride_0,
page_table_stride_1,
swa_page_table,
swa_page_table_stride_0,
swa_page_table_stride_1,
full_to_swa_mapping,
full_to_swa_mapping_stride_0,
# Scalar parameters
B,
max_seq_pages,
page_size: tl.constexpr,
seq_len_delta: tl.constexpr,
use_swa: tl.constexpr,
SHIFT: tl.constexpr,
BLOCK_COLS: tl.constexpr,
):
pid_b = tl.program_id(0) # batch index
pid_c = tl.program_id(1) # column chunk index
# 1. Prefix sum (only one block does it)
if pid_b == 0 and pid_c == 0:
acc = 0
for idx in range(B):
seq = tl.load(seq_lens + idx * seq_lens_stride_0)
val = (seq + seq_len_delta).to(tl.int32)
tl.store(cache_seqlens_int32 + idx * cache_seqlens_int32_stride_0, val)
tl.store(cu_seqlens_k + idx * cu_seqlens_k_stride_0, acc)
acc += val
tl.store(cu_seqlens_k + B * cu_seqlens_k_stride_0, acc)
# 2. Gather for this batch and column chunk
if max_seq_pages == 0:
return
i = pid_b
# Load row index for this batch (all threads in block have same i)
row_idx = tl.load(req_pool_indices + i * req_pool_indices_stride_0)
row_offset = row_idx * req_to_token_stride_0
col_start = pid_c * BLOCK_COLS
col_offsets = col_start + tl.arange(0, BLOCK_COLS)
mask = col_offsets < max_seq_pages
# Compute column indices in the source tensor (token offset)
if page_size == 1:
col_idx = col_offsets
else:
col_idx = col_offsets << SHIFT # faster than multiplication for power-of-two
# Load page indices from req_to_token
rt_offsets = row_offset + col_idx * req_to_token_stride_1
page_index = tl.load(
req_to_token + rt_offsets, mask=mask, other=0, cache_modifier=".cg"
)
# Compute page_table
if page_size == 1:
page_table_val = page_index
else:
page_table_val = page_index >> SHIFT
# Store to page_table
pt_offsets = i * page_table_stride_0 + col_offsets * page_table_stride_1
tl.store(page_table + pt_offsets, page_table_val, mask=mask, cache_modifier=".cg")
if use_swa:
swa_slot = tl.load(
full_to_swa_mapping + page_index * full_to_swa_mapping_stride_0,
mask=mask,
other=0,
cache_modifier=".cg",
)
if page_size == 1:
swa_val = swa_slot
else:
swa_val = swa_slot >> SHIFT
swa_offsets = (
i * swa_page_table_stride_0 + col_offsets * swa_page_table_stride_1
)
tl.store(swa_page_table + swa_offsets, swa_val, mask=mask, cache_modifier=".cg")
@triton.jit
def _fused_metadata_kernel_ps1_no_swa(
# Input tensors
seq_lens,
seq_lens_stride_0,
req_to_token,
req_to_token_stride_0,
req_to_token_stride_1,
req_pool_indices,
req_pool_indices_stride_0,
# Output buffers
cache_seqlens_int32,
cache_seqlens_int32_stride_0,
cu_seqlens_k,
cu_seqlens_k_stride_0,
page_table,
page_table_stride_0,
page_table_stride_1,
# Scalar parameters
B,
max_seq_pages,
seq_len_delta: tl.constexpr,
BLOCK_COLS: tl.constexpr,
):
pid_b = tl.program_id(0) # batch index
pid_c = tl.program_id(1) # column chunk index
# 1. Prefix sum (only one block does it)
if pid_b == 0 and pid_c == 0:
acc = 0
for idx in range(B):
seq = tl.load(seq_lens + idx * seq_lens_stride_0)
val = (seq + seq_len_delta).to(tl.int32)
tl.store(cache_seqlens_int32 + idx * cache_seqlens_int32_stride_0, val)
tl.store(cu_seqlens_k + idx * cu_seqlens_k_stride_0, acc)
acc += val
tl.store(cu_seqlens_k + B * cu_seqlens_k_stride_0, acc)
# 2. Gather for this batch and column chunk
if max_seq_pages == 0:
return
i = pid_b
# Load row index for this batch (all threads in block have same i)
row_idx = tl.load(req_pool_indices + i * req_pool_indices_stride_0)
row_offset = row_idx * req_to_token_stride_0
col_start = pid_c * BLOCK_COLS
col_offsets = col_start + tl.arange(0, BLOCK_COLS)
mask = col_offsets < max_seq_pages
# page_size = 1: col_idx = col_offsets
rt_offsets = row_offset + col_offsets * req_to_token_stride_1
page_index = tl.load(
req_to_token + rt_offsets, mask=mask, other=0, cache_modifier=".cg"
)
# page_table = page_index // 1 = page_index
pt_offsets = i * page_table_stride_0 + col_offsets * page_table_stride_1
tl.store(page_table + pt_offsets, page_index, mask=mask, cache_modifier=".cg")
def normal_decode_set_metadata(
cache_seqlens_int32: torch.Tensor,
cu_seqlens_k: torch.Tensor,
page_table: torch.Tensor,
req_to_token: torch.Tensor,
req_pool_indices: torch.Tensor,
strided_indices: torch.Tensor,
max_seq_pages: torch.Tensor,
seq_lens: torch.Tensor,
seq_len_delta: int,
page_size: int,
swa_page_table: Optional[torch.Tensor] = None,
token_to_kv_pool: Optional["SWAKVPool"] = None,
):
"""
Fused Triton implementation that replaces 4-5 sequential CUDA kernels with 1-2 kernels:
1. cache_seqlens = seq_lens + seq_len_delta (int64->int32 cast)
2. cu_seqlens_k = cumsum(cache_seqlens) (prefix-sum)
3. page_indices = req_to_token[pool_idx, stride_idx] (2-D gather)
4. page_table = page_indices // page_size (floor-divide)
5. (optional) swa_page_table for sliding window attention
Achieves ~5.2x speedup on H200 hardware for typical decode workloads.
"""
assert (
page_size > 0 and (page_size & (page_size - 1)) == 0
), f"page_size must be a power of two, got {page_size}"
batch_size = cache_seqlens_int32.shape[0]
device = seq_lens.device
# Ensure contiguous memory layout for efficient Triton access
seq_lens = seq_lens.contiguous()
req_to_token = req_to_token.contiguous()
req_pool_indices = req_pool_indices.contiguous()
# Prepare tensor strides
seq_lens_stride_0 = seq_lens.stride(0)
req_to_token_stride_0 = req_to_token.stride(0)
req_to_token_stride_1 = req_to_token.stride(1)
req_pool_indices_stride_0 = req_pool_indices.stride(0)
cache_seqlens_int32_stride_0 = cache_seqlens_int32.stride(0)
cu_seqlens_k_stride_0 = cu_seqlens_k.stride(0)
page_table_stride_0 = page_table.stride(0)
page_table_stride_1 = page_table.stride(1)
# Check if we should use the specialized fast path for page_size=1, no SWA
use_swa = swa_page_table is not None and token_to_kv_pool is not None
if page_size == 1 and not use_swa:
# Specialized kernel for the common case (page_size=1, no SWA)
BLOCK_COLS = 256
if max_seq_pages == 0:
grid = (1, 1)
else:
num_blocks_j = triton.cdiv(max_seq_pages, BLOCK_COLS)
grid = (batch_size, num_blocks_j)
_fused_metadata_kernel_ps1_no_swa[grid](
seq_lens,
seq_lens_stride_0,
req_to_token,
req_to_token_stride_0,
req_to_token_stride_1,
req_pool_indices,
req_pool_indices_stride_0,
cache_seqlens_int32,
cache_seqlens_int32_stride_0,
cu_seqlens_k,
cu_seqlens_k_stride_0,
page_table,
page_table_stride_0,
page_table_stride_1,
batch_size,
max_seq_pages,
seq_len_delta,
BLOCK_COLS=BLOCK_COLS,
num_warps=8,
num_stages=3,
)
else:
# General kernel for page_size > 1 or SWA cases
# SWA parameters
if use_swa:
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
assert isinstance(token_to_kv_pool, SWAKVPool)
swa_page_table = swa_page_table.contiguous()
swa_page_table_stride_0 = swa_page_table.stride(0)
swa_page_table_stride_1 = swa_page_table.stride(1)
# Extract the full_to_swa_index_mapping from token_to_kv_pool
full_to_swa_mapping = (
token_to_kv_pool.full_to_swa_index_mapping.contiguous()
)
full_to_swa_mapping_stride_0 = full_to_swa_mapping.stride(0)
else:
# Dummy tensors (not used)
swa_page_table = torch.empty(0, dtype=torch.int32, device=device)
swa_page_table_stride_0 = 0
swa_page_table_stride_1 = 0
full_to_swa_mapping = torch.empty(0, dtype=torch.int32, device=device)
full_to_swa_mapping_stride_0 = 0
# Kernel configuration
BLOCK_COLS = 128
shift = (page_size).bit_length() - 1 if page_size > 1 else 0
if max_seq_pages == 0:
grid = (1, 1)
else:
num_blocks_j = triton.cdiv(max_seq_pages, BLOCK_COLS)
grid = (batch_size, num_blocks_j)
_fused_metadata_kernel_general[grid](
seq_lens,
seq_lens_stride_0,
req_to_token,
req_to_token_stride_0,
req_to_token_stride_1,
req_pool_indices,
req_pool_indices_stride_0,
cache_seqlens_int32,
cache_seqlens_int32_stride_0,
cu_seqlens_k,
cu_seqlens_k_stride_0,
page_table,
page_table_stride_0,
page_table_stride_1,
swa_page_table,
swa_page_table_stride_0,
swa_page_table_stride_1,
full_to_swa_mapping,
full_to_swa_mapping_stride_0,
batch_size,
max_seq_pages,
page_size,
seq_len_delta,
use_swa,
shift,
BLOCK_COLS=BLOCK_COLS,
num_warps=4,
num_stages=3,
)