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
419 lines
12 KiB
Python
419 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
import torch
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
from sglang.srt.utils import (
|
|
is_cpu,
|
|
is_cuda,
|
|
is_hip,
|
|
is_musa,
|
|
is_npu,
|
|
is_xpu,
|
|
next_power_of_2,
|
|
)
|
|
|
|
_is_cpu = is_cpu()
|
|
_is_cuda = is_cuda()
|
|
_is_hip = is_hip()
|
|
_is_npu = is_npu()
|
|
_is_musa = is_musa()
|
|
_is_xpu = is_xpu()
|
|
|
|
if _is_cpu:
|
|
from sgl_kernel import assign_extend_cache_locs_cpu, assign_req_to_token_pool_cpu
|
|
|
|
|
|
@triton.jit
|
|
def assign_req_to_token_pool(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
pool_len: tl.constexpr,
|
|
bs_upper: tl.constexpr,
|
|
):
|
|
BLOCK_SIZE: tl.constexpr = 32
|
|
pid = tl.program_id(axis=0)
|
|
kv_start = tl.load(start_offset + pid)
|
|
kv_end = tl.load(end_offset + pid)
|
|
token_pool = req_to_token + tl.load(req_pool_indices + pid) * pool_len
|
|
|
|
length_offset = tl.arange(0, bs_upper)
|
|
start = tl.load(start_offset + length_offset, mask=length_offset < pid, other=0)
|
|
end = tl.load(end_offset + length_offset, mask=length_offset < pid, other=0)
|
|
out_offset = tl.sum(end - start, axis=0)
|
|
|
|
out_cache_ptr = out_cache_loc + out_offset
|
|
|
|
save_offset = tl.arange(0, BLOCK_SIZE) + kv_start
|
|
load_offset = tl.arange(0, BLOCK_SIZE)
|
|
|
|
num_loop = tl.cdiv(kv_end - kv_start, BLOCK_SIZE)
|
|
for _ in range(num_loop):
|
|
mask = save_offset < kv_end
|
|
data = tl.load(out_cache_ptr + load_offset, mask=mask)
|
|
tl.store(token_pool + save_offset, data, mask=mask)
|
|
save_offset += BLOCK_SIZE
|
|
load_offset += BLOCK_SIZE
|
|
|
|
|
|
def assign_req_to_token_pool_func(
|
|
req_pool_indices: torch.Tensor,
|
|
req_to_token: torch.Tensor,
|
|
start_offset: torch.Tensor,
|
|
end_offset: torch.Tensor,
|
|
out_cache_loc: torch.Tensor,
|
|
batch_size: int,
|
|
):
|
|
if _is_cpu:
|
|
assign_req_to_token_pool_cpu(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
req_to_token.shape[1],
|
|
)
|
|
return
|
|
assign_req_to_token_pool[(batch_size,)](
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
req_to_token.shape[1],
|
|
next_power_of_2(batch_size),
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def assign_draft_cache_locs_contiguous(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
seq_lens,
|
|
out_cache_loc,
|
|
pool_len: tl.constexpr,
|
|
topk: tl.constexpr,
|
|
speculative_num_steps: tl.constexpr,
|
|
):
|
|
BLOCK_SIZE: tl.constexpr = 128
|
|
pid = tl.program_id(axis=0)
|
|
|
|
copy_len = topk * speculative_num_steps
|
|
out_cache_ptr = out_cache_loc + pid * topk * speculative_num_steps
|
|
|
|
# Copy from req_to_token to out_cache_loc
|
|
kv_start = tl.load(seq_lens + pid)
|
|
token_pool = req_to_token + tl.load(req_pool_indices + pid) * pool_len
|
|
num_loop = tl.cdiv(copy_len, BLOCK_SIZE)
|
|
for i in range(num_loop):
|
|
copy_offset = tl.arange(0, BLOCK_SIZE) + i * BLOCK_SIZE
|
|
mask = copy_offset < copy_len
|
|
data = tl.load(token_pool + kv_start + copy_offset, mask=mask)
|
|
tl.store(out_cache_ptr + copy_offset, data, mask=mask)
|
|
|
|
|
|
@triton.jit
|
|
def generate_draft_decode_kv_indices(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
paged_kernel_lens,
|
|
kv_indices,
|
|
kv_indptr,
|
|
positions,
|
|
pool_len: tl.constexpr,
|
|
kv_indices_stride: tl.constexpr,
|
|
kv_indptr_stride: tl.constexpr,
|
|
bs_upper: tl.constexpr,
|
|
iter_upper: tl.constexpr,
|
|
num_tokens_upper: tl.constexpr,
|
|
page_size: tl.constexpr,
|
|
):
|
|
BLOCK_SIZE: tl.constexpr = 128
|
|
iters = tl.program_id(axis=0)
|
|
bid = tl.program_id(axis=1)
|
|
topk_id = tl.program_id(axis=2)
|
|
|
|
num_steps = tl.num_programs(axis=0)
|
|
num_seqs = tl.num_programs(axis=1)
|
|
topk = tl.num_programs(axis=2)
|
|
|
|
kv_indices += kv_indices_stride * iters
|
|
kv_indptr += kv_indptr_stride * iters
|
|
iters += 1
|
|
|
|
load_offset = tl.arange(0, bs_upper)
|
|
seq_lens = tl.load(paged_kernel_lens + load_offset, mask=load_offset < bid, other=0)
|
|
seq_len = tl.load(paged_kernel_lens + bid)
|
|
cum_seq_len = tl.sum(seq_lens)
|
|
|
|
# Update kv_indices
|
|
kv_offset = cum_seq_len * topk + bid * iters * topk + topk_id * (seq_len + iters)
|
|
kv_ptr = kv_indices + kv_offset
|
|
token_pool_ptr = req_to_token + tl.load(req_pool_indices + bid) * pool_len
|
|
|
|
kv_offset = tl.arange(0, BLOCK_SIZE)
|
|
num_loop = tl.cdiv(seq_len, BLOCK_SIZE)
|
|
for _ in range(num_loop):
|
|
mask = kv_offset < seq_len
|
|
data = tl.load(token_pool_ptr + kv_offset, mask=mask)
|
|
tl.store(kv_ptr + kv_offset, data, mask=mask)
|
|
kv_offset += BLOCK_SIZE
|
|
|
|
extend_offset = tl.arange(0, iter_upper)
|
|
if page_size == 1 or topk == 1:
|
|
extend_data = tl.load(
|
|
token_pool_ptr + seq_len + topk_id * num_steps + tl.arange(0, iter_upper),
|
|
mask=extend_offset < iters,
|
|
)
|
|
else:
|
|
prefix_len = seq_len
|
|
last_page_len = prefix_len % page_size
|
|
num_new_pages_per_topk = (
|
|
last_page_len + num_steps + page_size - 1
|
|
) // page_size
|
|
prefix_base = seq_len // page_size * page_size
|
|
start = (
|
|
prefix_base + topk_id * num_new_pages_per_topk * page_size + last_page_len
|
|
)
|
|
extend_data = tl.load(
|
|
token_pool_ptr + start + extend_offset,
|
|
mask=extend_offset < iters,
|
|
)
|
|
|
|
tl.store(kv_ptr + seq_len + extend_offset, extend_data, mask=extend_offset < iters)
|
|
|
|
# Update kv_indptr
|
|
bs_offset = tl.arange(0, num_tokens_upper)
|
|
|
|
zid = bid * topk + topk_id
|
|
if zid == 0:
|
|
zid = num_seqs * topk
|
|
positions = tl.load(positions + bs_offset, mask=bs_offset < zid, other=0)
|
|
base = tl.sum(positions)
|
|
tl.store(kv_indptr + zid, base + zid * iters)
|
|
|
|
|
|
@triton.jit
|
|
def align_evict_mask_to_page_size(
|
|
seq_lens,
|
|
evict_mask,
|
|
page_size: tl.constexpr,
|
|
num_draft_tokens: tl.constexpr,
|
|
BLOCK_SIZE: tl.constexpr,
|
|
):
|
|
t_range = tl.arange(0, BLOCK_SIZE)
|
|
|
|
bid = tl.program_id(axis=0)
|
|
seq_len = tl.load(seq_lens + bid)
|
|
io_mask = t_range < num_draft_tokens
|
|
mask_row = tl.load(
|
|
evict_mask + bid * num_draft_tokens + t_range, mask=io_mask, other=0
|
|
)
|
|
|
|
num_trues = tl.sum(mask_row)
|
|
num_false = num_draft_tokens - num_trues
|
|
|
|
start = (seq_len + num_false - 1) // page_size * page_size - seq_len
|
|
for i in range(max(start, 0), min(start + page_size, num_draft_tokens)):
|
|
tl.store(evict_mask + bid * num_draft_tokens + i, False)
|
|
|
|
|
|
@torch.compile(dynamic=True, disable=_is_npu)
|
|
def get_src_tgt_cache_loc(
|
|
seq_lens: torch.Tensor,
|
|
out_cache_loc: torch.Tensor,
|
|
accept_index: torch.Tensor,
|
|
num_correct_drafts: torch.Tensor,
|
|
draft_token_num: int,
|
|
page_size: int,
|
|
):
|
|
src_cache_loc = out_cache_loc[accept_index]
|
|
# zeros_like, not empty_like: any uncovered tail stays at slot 0 (padding)
|
|
# instead of caching-allocator garbage.
|
|
tgt_cache_loc = torch.zeros_like(src_cache_loc)
|
|
extended_len = seq_lens + draft_token_num
|
|
keep_len = torch.minimum(
|
|
(seq_lens + num_correct_drafts + 1 + page_size - 1) // page_size * page_size,
|
|
extended_len,
|
|
)
|
|
to_free_num_slots = extended_len - keep_len
|
|
return src_cache_loc, tgt_cache_loc, to_free_num_slots
|
|
|
|
|
|
@triton.jit
|
|
def get_target_cache_loc(
|
|
tgt_cache_loc,
|
|
to_free_slots,
|
|
num_correct_drafts,
|
|
to_free_num_slots,
|
|
out_cache_loc,
|
|
num_verify_tokens: tl.constexpr,
|
|
num_verify_tokens_upper: tl.constexpr,
|
|
bs_upper: tl.constexpr,
|
|
):
|
|
bid = tl.program_id(axis=0)
|
|
offset = tl.arange(0, num_verify_tokens_upper)
|
|
bs_offset = tl.arange(0, bs_upper)
|
|
|
|
# write the first part to tgt_cache_loc
|
|
accept_len_all = tl.load(num_correct_drafts + bs_offset, mask=bs_offset < bid)
|
|
tgt_cache_loc_start = tl.sum(accept_len_all) + bid
|
|
copy_len = tl.load(num_correct_drafts + bid) + 1
|
|
out_cache_loc_row = tl.load(
|
|
out_cache_loc + bid * num_verify_tokens + offset, mask=offset < copy_len
|
|
)
|
|
tl.store(
|
|
tgt_cache_loc + tgt_cache_loc_start + offset,
|
|
out_cache_loc_row,
|
|
mask=offset < copy_len,
|
|
)
|
|
|
|
# write the second part to to_free_num_pages
|
|
to_free_num_slots_all = tl.load(to_free_num_slots + bs_offset, mask=bs_offset < bid)
|
|
to_free_num_slots_cur = tl.load(to_free_num_slots + bid)
|
|
out_cache_loc_start = num_verify_tokens - to_free_num_slots_cur
|
|
to_free_slots_start = tl.sum(to_free_num_slots_all)
|
|
|
|
copy_len = to_free_num_slots_cur
|
|
out_cache_loc_row = tl.load(
|
|
out_cache_loc + bid * num_verify_tokens + out_cache_loc_start + offset,
|
|
mask=offset < copy_len,
|
|
)
|
|
tl.store(
|
|
to_free_slots + to_free_slots_start + offset,
|
|
out_cache_loc_row,
|
|
mask=offset < copy_len,
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def filter_finished_cache_loc_kernel(
|
|
out_cache_loc,
|
|
tgt_cache_loc,
|
|
num_correct_drafts,
|
|
num_accept_tokens_filter,
|
|
bs_upper: tl.constexpr,
|
|
num_verify_tokens_upper: tl.constexpr,
|
|
):
|
|
bid = tl.program_id(0)
|
|
bs_offset = tl.arange(0, bs_upper)
|
|
|
|
num_correct_drafts_all = tl.load(
|
|
num_correct_drafts + bs_offset, mask=bs_offset < bid
|
|
)
|
|
old_start = tl.sum(num_correct_drafts_all) + bid
|
|
|
|
num_accept_tokens_filter_all = tl.load(
|
|
num_accept_tokens_filter + bs_offset, mask=bs_offset < bid
|
|
)
|
|
new_start = tl.sum(num_accept_tokens_filter_all)
|
|
|
|
copy_len = tl.load(num_accept_tokens_filter + bid)
|
|
copy_offset = tl.arange(0, num_verify_tokens_upper)
|
|
value = tl.load(
|
|
tgt_cache_loc + old_start + copy_offset, mask=copy_offset < copy_len
|
|
)
|
|
tl.store(
|
|
out_cache_loc + new_start + copy_offset, value, mask=copy_offset < copy_len
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def assign_extend_cache_locs(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
pool_len: tl.constexpr,
|
|
bs_upper: tl.constexpr,
|
|
):
|
|
BLOCK_SIZE: tl.constexpr = 32
|
|
pid = tl.program_id(axis=0)
|
|
kv_start = tl.load(start_offset + pid)
|
|
kv_end = tl.load(end_offset + pid)
|
|
token_pool = req_to_token + tl.load(req_pool_indices + pid) * pool_len
|
|
|
|
length_offset = tl.arange(0, bs_upper)
|
|
start = tl.load(start_offset + length_offset, mask=length_offset < pid, other=0)
|
|
end = tl.load(end_offset + length_offset, mask=length_offset < pid, other=0)
|
|
out_offset = tl.sum(end - start, axis=0)
|
|
|
|
out_cache_ptr = out_cache_loc + out_offset
|
|
|
|
load_offset = tl.arange(0, BLOCK_SIZE) + kv_start
|
|
save_offset = tl.arange(0, BLOCK_SIZE)
|
|
|
|
num_loop = tl.cdiv(kv_end - kv_start, BLOCK_SIZE)
|
|
for _ in range(num_loop):
|
|
mask = load_offset < kv_end
|
|
data = tl.load(token_pool + load_offset, mask=mask)
|
|
tl.store(out_cache_ptr + save_offset, data, mask=mask)
|
|
load_offset += BLOCK_SIZE
|
|
save_offset += BLOCK_SIZE
|
|
|
|
|
|
def assign_extend_cache_locs_func(
|
|
req_pool_indices: torch.Tensor,
|
|
req_to_token: torch.Tensor,
|
|
start_offset: torch.Tensor,
|
|
end_offset: torch.Tensor,
|
|
batch_size: int,
|
|
draft_token_num: int,
|
|
device,
|
|
) -> torch.Tensor:
|
|
if _is_cuda or _is_hip or _is_musa or _is_xpu:
|
|
out_cache_loc = torch.empty(
|
|
(batch_size * draft_token_num,),
|
|
dtype=torch.int64,
|
|
device=device,
|
|
)
|
|
assign_extend_cache_locs[(batch_size,)](
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
req_to_token.shape[1],
|
|
next_power_of_2(batch_size),
|
|
)
|
|
|
|
return out_cache_loc
|
|
|
|
elif _is_npu:
|
|
out_cache_loc = torch.empty(
|
|
(batch_size * draft_token_num,),
|
|
dtype=torch.int32,
|
|
device=device,
|
|
)
|
|
torch.ops.npu.cache_loc_update(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
)
|
|
|
|
return out_cache_loc
|
|
|
|
elif _is_cpu:
|
|
out_cache_loc = torch.empty(
|
|
(batch_size * draft_token_num,),
|
|
dtype=torch.int64,
|
|
device=device,
|
|
)
|
|
assign_extend_cache_locs_cpu(
|
|
req_pool_indices,
|
|
req_to_token,
|
|
start_offset,
|
|
end_offset,
|
|
out_cache_loc,
|
|
req_to_token.shape[1],
|
|
)
|
|
|
|
return out_cache_loc
|