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
282 lines
10 KiB
Python
282 lines
10 KiB
Python
# Copyright 2023-2026 SGLang Team
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
# ==============================================================================
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
|
|
@triton.jit
|
|
def sgl_build_tree_kernel_efficient_triton(
|
|
parent_list_ptr,
|
|
selected_index_ptr,
|
|
verified_seq_len_ptr,
|
|
seq_len_prefix_sum_ptr,
|
|
tree_mask_ptr,
|
|
positions_ptr,
|
|
retrieve_index_ptr,
|
|
retrieve_next_token_ptr,
|
|
retrieve_next_sibling_ptr,
|
|
topk: tl.constexpr,
|
|
depth: tl.constexpr,
|
|
draft_token_num: tl.constexpr,
|
|
tree_mask_mode: tl.constexpr,
|
|
batch_size: tl.constexpr,
|
|
parent_list_stride: tl.constexpr,
|
|
selected_index_stride: tl.constexpr,
|
|
):
|
|
"""
|
|
Triton kernel for building EAGLE tree structure.
|
|
Each program handles one batch item (batch_idx).
|
|
"""
|
|
batch_idx = tl.program_id(0)
|
|
|
|
# Calculate seq_tree_idx
|
|
seq_len = tl.load(verified_seq_len_ptr + batch_idx)
|
|
seq_len_prefix_sum = tl.load(seq_len_prefix_sum_ptr + batch_idx)
|
|
|
|
# Cast initial value to match the dtype of loaded tensors to avoid type inconsistency
|
|
seq_tree_idx = (
|
|
tl.cast(draft_token_num * draft_token_num * batch_idx, seq_len.dtype)
|
|
+ seq_len_prefix_sum * draft_token_num
|
|
)
|
|
|
|
positions_offset = batch_idx * draft_token_num
|
|
tl.store(positions_ptr + positions_offset, seq_len)
|
|
|
|
retrieve_index_offset = batch_idx * draft_token_num
|
|
|
|
# Build retrieval index structure (reverse loop from draft_token_num-1 to 1)
|
|
for i in range(draft_token_num - 1, 0, -1):
|
|
current_token_idx = retrieve_index_offset + i
|
|
tl.store(
|
|
retrieve_index_ptr + batch_idx * draft_token_num + i,
|
|
current_token_idx,
|
|
)
|
|
|
|
parent_tb_idx = (
|
|
tl.load(selected_index_ptr + batch_idx * selected_index_stride + (i - 1))
|
|
// topk
|
|
)
|
|
parent_position = 0
|
|
found = 0
|
|
|
|
if parent_tb_idx == 0:
|
|
found = 1
|
|
else:
|
|
parent_token_idx = tl.load(
|
|
parent_list_ptr + batch_idx * parent_list_stride + parent_tb_idx
|
|
)
|
|
|
|
# Find parent position
|
|
for pp in range(draft_token_num - 1):
|
|
if found == 0:
|
|
sel_idx = tl.load(
|
|
selected_index_ptr + batch_idx * selected_index_stride + pp
|
|
)
|
|
if sel_idx == parent_token_idx:
|
|
parent_position = pp + 1
|
|
found = 1
|
|
|
|
if found == 1:
|
|
# Update next token links
|
|
next_tok_addr = (
|
|
retrieve_next_token_ptr + batch_idx * draft_token_num + parent_position
|
|
)
|
|
next_tok = tl.load(next_tok_addr)
|
|
|
|
if next_tok == -1:
|
|
tl.store(next_tok_addr, i)
|
|
else:
|
|
tl.store(next_tok_addr, i)
|
|
tl.store(
|
|
retrieve_next_sibling_ptr + batch_idx * draft_token_num + i,
|
|
next_tok,
|
|
)
|
|
|
|
tl.store(retrieve_index_ptr + batch_idx * draft_token_num, retrieve_index_offset)
|
|
|
|
# Process all draft token indices for tree mask
|
|
for draft_tokenx in range(draft_token_num):
|
|
if tree_mask_mode == 0: # FULL_MASK
|
|
token_tree_idx = (
|
|
seq_tree_idx + (seq_len + draft_token_num) * draft_tokenx + seq_len + 1
|
|
)
|
|
else:
|
|
token_tree_idx = (
|
|
draft_token_num * draft_token_num * batch_idx
|
|
+ draft_token_num * draft_tokenx
|
|
+ 1
|
|
)
|
|
|
|
tl.store(tree_mask_ptr + token_tree_idx - 1, 1)
|
|
for i in range(draft_token_num - 1):
|
|
tl.store(tree_mask_ptr + token_tree_idx + i, 0)
|
|
|
|
if draft_tokenx > 0:
|
|
# Build tree path for draft_tokenx > 0
|
|
cur_position = draft_tokenx - 1
|
|
position = 0
|
|
should_continue = 1
|
|
|
|
for _ in range(depth):
|
|
if should_continue:
|
|
position += 1
|
|
tl.store(tree_mask_ptr + token_tree_idx + cur_position, 1)
|
|
|
|
parent_tb_idx = (
|
|
tl.load(
|
|
selected_index_ptr
|
|
+ batch_idx * selected_index_stride
|
|
+ cur_position
|
|
)
|
|
// topk
|
|
)
|
|
if parent_tb_idx == 0:
|
|
should_continue = 0
|
|
else:
|
|
parent_token_idx = tl.load(
|
|
parent_list_ptr
|
|
+ batch_idx * parent_list_stride
|
|
+ parent_tb_idx
|
|
)
|
|
|
|
# Find cur_position for next iteration
|
|
found = 0
|
|
for cp in range(draft_token_num - 1):
|
|
if found == 0:
|
|
if (
|
|
tl.load(
|
|
selected_index_ptr
|
|
+ batch_idx * selected_index_stride
|
|
+ cp
|
|
)
|
|
== parent_token_idx
|
|
):
|
|
cur_position = cp
|
|
found = 1
|
|
if found == 0:
|
|
should_continue = 0
|
|
|
|
tl.store(
|
|
positions_ptr + batch_idx * draft_token_num + draft_tokenx,
|
|
position + seq_len,
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def verify_tree_greedy_kernel_triton(
|
|
predicts_ptr,
|
|
accept_index_ptr,
|
|
accept_token_num_ptr,
|
|
candidates_ptr,
|
|
retrieve_index_ptr,
|
|
retrieve_next_token_ptr,
|
|
retrieve_next_sibling_ptr,
|
|
target_predict_ptr,
|
|
batch_size: tl.constexpr,
|
|
num_speculative_tokens: tl.constexpr,
|
|
num_draft_tokens: tl.constexpr,
|
|
):
|
|
"""
|
|
Triton kernel for verifying EAGLE tree in greedy mode.
|
|
Each program handles one batch item.
|
|
"""
|
|
bx = tl.program_id(0)
|
|
|
|
# Initialize
|
|
last_accept_retrieve_idx = tl.load(retrieve_index_ptr + bx * num_draft_tokens)
|
|
tl.store(accept_index_ptr + bx * num_speculative_tokens, last_accept_retrieve_idx)
|
|
# Cast to match dtype of loaded tensors to avoid type inconsistency
|
|
num_accept_tokens = tl.cast(0, last_accept_retrieve_idx.dtype)
|
|
cur_index = tl.cast(0, last_accept_retrieve_idx.dtype)
|
|
|
|
# Tree traversal loop
|
|
should_continue = 1
|
|
for j in range(1, num_speculative_tokens):
|
|
if should_continue: # Early exit guard
|
|
cur_index = tl.load(
|
|
retrieve_next_token_ptr + bx * num_draft_tokens + cur_index
|
|
)
|
|
|
|
# Load target token once per level (before sibling search)
|
|
# last_accept_retrieve_idx is constant during sibling traversal
|
|
target_row = last_accept_retrieve_idx // num_draft_tokens
|
|
target_col = last_accept_retrieve_idx % num_draft_tokens
|
|
target_token = tl.load(
|
|
target_predict_ptr + target_row * num_draft_tokens + target_col
|
|
)
|
|
|
|
# Traverse siblings
|
|
found_match = 0
|
|
for _ in range(num_draft_tokens): # Max iterations = num_draft_tokens
|
|
if found_match == 0: # Early exit guard
|
|
# Check if we've reached end of sibling list
|
|
is_valid = cur_index != -1
|
|
|
|
# Use masked loads with safe address (0 when invalid)
|
|
safe_cur_index = (
|
|
cur_index * is_valid
|
|
) # 0 if invalid, cur_index if valid
|
|
safe_index = bx * num_draft_tokens + safe_cur_index
|
|
|
|
# Load draft token info (loads from index 0 when invalid, but we won't use it)
|
|
draft_index = tl.load(retrieve_index_ptr + safe_index)
|
|
draft_token = tl.load(candidates_ptr + safe_index)
|
|
|
|
# Check for token match (only valid when is_valid is True)
|
|
token_match = is_valid & (draft_token == target_token)
|
|
|
|
# Accept token using predicated stores (only write if matched)
|
|
tl.store(
|
|
predicts_ptr + last_accept_retrieve_idx,
|
|
target_token,
|
|
mask=token_match,
|
|
)
|
|
next_num_accept_tokens = num_accept_tokens + 1
|
|
tl.store(
|
|
accept_index_ptr
|
|
+ bx * num_speculative_tokens
|
|
+ next_num_accept_tokens,
|
|
draft_index,
|
|
mask=token_match,
|
|
)
|
|
|
|
num_accept_tokens = num_accept_tokens + token_match
|
|
last_accept_retrieve_idx = (
|
|
token_match * draft_index
|
|
+ (~token_match) * last_accept_retrieve_idx
|
|
)
|
|
found_match = token_match * 1 + (~is_valid) * (-1)
|
|
|
|
# Masked load: only load next sibling when no match (hardware predication)
|
|
# When matched: returns cur_index (other); when not matched: loads sibling
|
|
cur_index = tl.load(
|
|
retrieve_next_sibling_ptr + safe_index,
|
|
mask=~token_match
|
|
& is_valid, # Only load when valid and NOT matched
|
|
other=cur_index, # Keep cur_index when matched or invalid
|
|
)
|
|
|
|
if found_match != 1:
|
|
should_continue = 0
|
|
|
|
# Store final results
|
|
tl.store(accept_token_num_ptr + bx, num_accept_tokens)
|
|
|
|
target_row = last_accept_retrieve_idx // num_draft_tokens
|
|
target_col = last_accept_retrieve_idx % num_draft_tokens
|
|
final_target = tl.load(
|
|
target_predict_ptr + target_row * num_draft_tokens + target_col
|
|
)
|
|
tl.store(predicts_ptr + last_accept_retrieve_idx, final_target)
|