chore: import upstream snapshot with attribution
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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:16 +08:00
commit 94057c3d3e
7152 changed files with 2120455 additions and 0 deletions
@@ -0,0 +1,407 @@
from __future__ import annotations
import torch
import triton
import triton.language as tl
# =============================================================================
# Fused kernel — reads INTERLEAVED input format
# Used by Qwen3-Next whose checkpoint stores fused in_proj_qkvz weights
# in per-head-group interleaved layout:
# [g0_q, g0_k, g0_v, g0_z, g1_q, g1_k, g1_v, g1_z, ...]
# =============================================================================
@triton.jit
def fused_qkvzba_split_reshape_cat_kernel(
mixed_qkv,
z,
b,
a,
mixed_qkvz,
mixed_ba,
NUM_HEADS_QK: tl.constexpr,
NUM_HEADS_V: tl.constexpr,
HEAD_QK: tl.constexpr,
HEAD_V: tl.constexpr,
):
i_bs, i_qk = tl.program_id(0), tl.program_id(1)
QKVZ_DIM_T: tl.constexpr = HEAD_QK * 2 + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V * 2
BA_DIM_T: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK * 2
QKV_DIM_T: tl.constexpr = HEAD_QK * 2 + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
q_end: tl.constexpr = HEAD_QK
blk_q_ptr = (
mixed_qkvz
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
+ i_qk * QKVZ_DIM_T
+ tl.arange(0, q_end)
)
k_end: tl.constexpr = q_end + HEAD_QK
blk_k_ptr = (
mixed_qkvz
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
+ i_qk * QKVZ_DIM_T
+ tl.arange(q_end, k_end)
)
v_end: tl.constexpr = k_end + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
blk_v_ptr = (
mixed_qkvz
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
+ i_qk * QKVZ_DIM_T
+ tl.arange(k_end, v_end)
)
z_end: tl.constexpr = v_end + NUM_HEADS_V // NUM_HEADS_QK * HEAD_V
blk_z_ptr = (
mixed_qkvz
+ i_bs * NUM_HEADS_QK * QKVZ_DIM_T
+ i_qk * QKVZ_DIM_T
+ tl.arange(v_end, z_end)
)
blk_q_st_ptr = (
mixed_qkv
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
+ i_qk * HEAD_QK
+ tl.arange(0, HEAD_QK)
)
blk_k_st_ptr = (
mixed_qkv
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
+ NUM_HEADS_QK * HEAD_QK
+ i_qk * HEAD_QK
+ tl.arange(0, HEAD_QK)
)
blk_v_st_ptr = (
mixed_qkv
+ i_bs * NUM_HEADS_QK * QKV_DIM_T
+ NUM_HEADS_QK * HEAD_QK * 2
+ i_qk * HEAD_V * NUM_HEADS_V // NUM_HEADS_QK
+ tl.arange(0, HEAD_V * NUM_HEADS_V // NUM_HEADS_QK)
)
blk_z_st_ptr = (
z
+ i_bs * NUM_HEADS_V * HEAD_V
+ i_qk * HEAD_V * NUM_HEADS_V // NUM_HEADS_QK
+ tl.arange(0, HEAD_V * NUM_HEADS_V // NUM_HEADS_QK)
)
tl.store(blk_q_st_ptr, tl.load(blk_q_ptr))
tl.store(blk_k_st_ptr, tl.load(blk_k_ptr))
tl.store(blk_v_st_ptr, tl.load(blk_v_ptr))
tl.store(blk_z_st_ptr, tl.load(blk_z_ptr))
b_end: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK
a_end: tl.constexpr = b_end + NUM_HEADS_V // NUM_HEADS_QK
for i in tl.static_range(b_end):
blk_b_ptr = mixed_ba + i_bs * NUM_HEADS_QK * BA_DIM_T + i_qk * BA_DIM_T + i
blk_b_st_ptr = b + i_bs * NUM_HEADS_V + i_qk * NUM_HEADS_V // NUM_HEADS_QK + i
tl.store(blk_b_st_ptr, tl.load(blk_b_ptr))
for i in tl.static_range(b_end, a_end):
blk_a_ptr = mixed_ba + i_bs * NUM_HEADS_QK * BA_DIM_T + i_qk * BA_DIM_T + i
blk_a_st_ptr = (
a + i_bs * NUM_HEADS_V + i_qk * NUM_HEADS_V // NUM_HEADS_QK + (i - b_end)
)
tl.store(blk_a_st_ptr, tl.load(blk_a_ptr))
def fused_qkvzba_split_reshape_cat(
mixed_qkvz,
mixed_ba,
num_heads_qk,
num_heads_v,
head_qk,
head_v,
):
batch, seq_len = mixed_qkvz.shape[0], 1
qkv_dim_t = num_heads_qk * head_qk * 2 + num_heads_v * head_v
mixed_qkv = torch.empty(
[batch * seq_len, qkv_dim_t],
dtype=mixed_qkvz.dtype,
device=mixed_qkvz.device,
)
z = torch.empty(
[batch * seq_len, num_heads_v, head_v],
dtype=mixed_qkvz.dtype,
device=mixed_qkvz.device,
)
b = torch.empty(
[batch * seq_len, num_heads_v],
dtype=mixed_ba.dtype,
device=mixed_ba.device,
)
a = torch.empty_like(b)
grid = (batch * seq_len, num_heads_qk)
fused_qkvzba_split_reshape_cat_kernel[grid](
mixed_qkv,
z,
b,
a,
mixed_qkvz,
mixed_ba,
num_heads_qk,
num_heads_v,
head_qk,
head_v,
num_warps=1,
num_stages=3,
)
return mixed_qkv, z, b, a
# =============================================================================
# Fused kernel — reads CONTIGUOUS input format
# Used by Qwen3.5 whose checkpoint stores in_proj_qkv and in_proj_z separately.
# After MergedColumnParallelLinear loads them, the matmul output is contiguous:
# mixed_qkvz: [all_q | all_k | all_v | all_z]
# mixed_ba: [all_b | all_a]
#
# Output format is identical to the interleaved kernel (same downstream consumer).
# =============================================================================
@triton.jit
def fused_qkvzba_split_reshape_cat_contiguous_kernel(
mixed_qkv,
z,
b,
a,
mixed_qkvz,
mixed_ba,
NUM_HEADS_QK: tl.constexpr,
NUM_HEADS_V: tl.constexpr,
HEAD_QK: tl.constexpr,
HEAD_V: tl.constexpr,
):
i_bs, i_qk = tl.program_id(0), tl.program_id(1)
V_PER_GROUP: tl.constexpr = NUM_HEADS_V // NUM_HEADS_QK
# ── Input dimensions (contiguous layout) ──
TOTAL_Q: tl.constexpr = NUM_HEADS_QK * HEAD_QK
TOTAL_K: tl.constexpr = NUM_HEADS_QK * HEAD_QK
TOTAL_V: tl.constexpr = NUM_HEADS_V * HEAD_V
TOTAL_QKVZ: tl.constexpr = TOTAL_Q + TOTAL_K + TOTAL_V + TOTAL_V
TOTAL_BA: tl.constexpr = NUM_HEADS_V * 2
# ── Output dimensions ──
QKV_DIM_T: tl.constexpr = TOTAL_Q + TOTAL_K + TOTAL_V
# ── Read from contiguous input ──
# q for head group i_qk: in the all_q region, offset i_qk * HEAD_QK
blk_q_ptr = mixed_qkvz + i_bs * TOTAL_QKVZ + i_qk * HEAD_QK + tl.arange(0, HEAD_QK)
# k for head group i_qk: in the all_k region
blk_k_ptr = (
mixed_qkvz
+ i_bs * TOTAL_QKVZ
+ TOTAL_Q
+ i_qk * HEAD_QK
+ tl.arange(0, HEAD_QK)
)
# v for head group i_qk: in the all_v region
blk_v_ptr = (
mixed_qkvz
+ i_bs * TOTAL_QKVZ
+ TOTAL_Q
+ TOTAL_K
+ i_qk * V_PER_GROUP * HEAD_V
+ tl.arange(0, V_PER_GROUP * HEAD_V)
)
# z for head group i_qk: in the all_z region
blk_z_ptr = (
mixed_qkvz
+ i_bs * TOTAL_QKVZ
+ TOTAL_Q
+ TOTAL_K
+ TOTAL_V
+ i_qk * V_PER_GROUP * HEAD_V
+ tl.arange(0, V_PER_GROUP * HEAD_V)
)
# ── Write to output (identical layout to the interleaved kernel) ──
blk_q_st_ptr = mixed_qkv + i_bs * QKV_DIM_T + i_qk * HEAD_QK + tl.arange(0, HEAD_QK)
blk_k_st_ptr = (
mixed_qkv
+ i_bs * QKV_DIM_T
+ NUM_HEADS_QK * HEAD_QK
+ i_qk * HEAD_QK
+ tl.arange(0, HEAD_QK)
)
blk_v_st_ptr = (
mixed_qkv
+ i_bs * QKV_DIM_T
+ NUM_HEADS_QK * HEAD_QK * 2
+ i_qk * V_PER_GROUP * HEAD_V
+ tl.arange(0, V_PER_GROUP * HEAD_V)
)
blk_z_st_ptr = (
z
+ i_bs * NUM_HEADS_V * HEAD_V
+ i_qk * V_PER_GROUP * HEAD_V
+ tl.arange(0, V_PER_GROUP * HEAD_V)
)
tl.store(blk_q_st_ptr, tl.load(blk_q_ptr))
tl.store(blk_k_st_ptr, tl.load(blk_k_ptr))
tl.store(blk_v_st_ptr, tl.load(blk_v_ptr))
tl.store(blk_z_st_ptr, tl.load(blk_z_ptr))
# ── b and a from contiguous [all_b | all_a] ──
for i in tl.static_range(V_PER_GROUP):
blk_b_ptr = mixed_ba + i_bs * TOTAL_BA + i_qk * V_PER_GROUP + i
blk_b_st_ptr = b + i_bs * NUM_HEADS_V + i_qk * V_PER_GROUP + i
tl.store(blk_b_st_ptr, tl.load(blk_b_ptr))
for i in tl.static_range(V_PER_GROUP):
blk_a_ptr = mixed_ba + i_bs * TOTAL_BA + NUM_HEADS_V + i_qk * V_PER_GROUP + i
blk_a_st_ptr = a + i_bs * NUM_HEADS_V + i_qk * V_PER_GROUP + i
tl.store(blk_a_st_ptr, tl.load(blk_a_ptr))
def fused_qkvzba_split_reshape_cat_contiguous(
mixed_qkvz,
mixed_ba,
num_heads_qk,
num_heads_v,
head_qk,
head_v,
):
"""Fused split/reshape/cat for CONTIGUOUS input format (Qwen3.5).
Input layout:
mixed_qkvz: [all_q | all_k | all_v | all_z]
mixed_ba: [all_b | all_a]
Output layout (same as fused_qkvzba_split_reshape_cat):
mixed_qkv: [all_q | all_k | all_v] (z stripped)
z: [num_v_heads, head_v]
b: [num_v_heads]
a: [num_v_heads]
"""
batch, seq_len = mixed_qkvz.shape[0], 1
qkv_dim_t = num_heads_qk * head_qk * 2 + num_heads_v * head_v
mixed_qkv = torch.empty(
[batch * seq_len, qkv_dim_t],
dtype=mixed_qkvz.dtype,
device=mixed_qkvz.device,
)
z = torch.empty(
[batch * seq_len, num_heads_v, head_v],
dtype=mixed_qkvz.dtype,
device=mixed_qkvz.device,
)
b = torch.empty(
[batch * seq_len, num_heads_v],
dtype=mixed_ba.dtype,
device=mixed_ba.device,
)
a = torch.empty_like(b)
grid = (batch * seq_len, num_heads_qk)
fused_qkvzba_split_reshape_cat_contiguous_kernel[grid](
mixed_qkv,
z,
b,
a,
mixed_qkvz,
mixed_ba,
num_heads_qk,
num_heads_v,
head_qk,
head_v,
num_warps=1,
num_stages=3,
)
return mixed_qkv, z, b, a
@triton.jit
def fused_qkv_split_gdn_prefill_kernel(
q,
k,
v,
mixed_qkv,
MIXED_QKV_STRIDE_T: tl.constexpr,
MIXED_QKV_STRIDE_D: tl.constexpr,
NUM_Q_HEADS: tl.constexpr,
NUM_K_HEADS: tl.constexpr,
NUM_V_HEADS: tl.constexpr,
HEAD_Q: tl.constexpr,
HEAD_K: tl.constexpr,
HEAD_V: tl.constexpr,
BLOCK_SIZE: tl.constexpr,
):
i_t = tl.program_id(0)
offsets = tl.arange(0, BLOCK_SIZE)
q_dim: tl.constexpr = NUM_Q_HEADS * HEAD_Q
k_dim: tl.constexpr = NUM_K_HEADS * HEAD_K
v_dim: tl.constexpr = NUM_V_HEADS * HEAD_V
qk_dim: tl.constexpr = q_dim + k_dim
qkv_dim: tl.constexpr = qk_dim + v_dim
mask = offsets < qkv_dim
values = tl.load(
mixed_qkv + i_t * MIXED_QKV_STRIDE_T + offsets * MIXED_QKV_STRIDE_D,
mask=mask,
)
q_mask = offsets < q_dim
tl.store(q + i_t * q_dim + offsets, values, mask=q_mask)
k_offsets = offsets - q_dim
k_mask = (offsets >= q_dim) & (offsets < qk_dim)
tl.store(k + i_t * k_dim + k_offsets, values, mask=k_mask)
v_offsets = offsets - qk_dim
v_mask = (offsets >= qk_dim) & (offsets < qkv_dim)
tl.store(v + i_t * v_dim + v_offsets, values, mask=v_mask)
def fused_qkv_split_gdn_prefill(
mixed_qkv: torch.Tensor,
num_q_heads: int,
num_k_heads: int,
num_v_heads: int,
head_q: int,
head_k: int,
head_v: int,
):
"""Split packed post-conv GDN QKV into contiguous FLA prefill tensors.
`mixed_qkv` is laid out per token as `[all_q | all_k | all_v]`. The FLA
chunk kernels consume separate contiguous `[1, T, H, D]` tensors, so this
fused split replaces three independent `aten::copy_` kernels from the
generic FLA input guard. `mixed_qkv` may be a strided `[T, qkv_dim]` view.
"""
seq_len = mixed_qkv.shape[0]
q = torch.empty(
(1, seq_len, num_q_heads, head_q),
dtype=mixed_qkv.dtype,
device=mixed_qkv.device,
)
k = torch.empty(
(1, seq_len, num_k_heads, head_k),
dtype=mixed_qkv.dtype,
device=mixed_qkv.device,
)
v = torch.empty(
(1, seq_len, num_v_heads, head_v),
dtype=mixed_qkv.dtype,
device=mixed_qkv.device,
)
qkv_dim = num_q_heads * head_q + num_k_heads * head_k + num_v_heads * head_v
fused_qkv_split_gdn_prefill_kernel[(seq_len,)](
q,
k,
v,
mixed_qkv,
mixed_qkv.stride(0),
mixed_qkv.stride(1),
num_q_heads,
num_k_heads,
num_v_heads,
head_q,
head_k,
head_v,
BLOCK_SIZE=triton.next_power_of_2(qkv_dim),
num_warps=8,
num_stages=3,
)
return q, k, v
@@ -0,0 +1,99 @@
"""HIP fallback for ``hash_topk``: ``csrc/deepseek_v4/hash_topk.cuh`` uses
CUDA-only primitives, so on ROCm we dispatch to this Triton implementation.
"""
from __future__ import annotations
from typing import Tuple
import torch
import triton
import triton.language as tl
@triton.jit
def _hash_topk_triton_kernel(
router_logits_ptr,
input_ids_ptr,
tid2eid_ptr,
topk_weights_ptr,
topk_ids_ptr,
num_routed_experts: tl.constexpr,
topk_routed: tl.constexpr,
topk_fused: tl.constexpr,
routed_scaling_factor,
BLOCK_K: tl.constexpr,
):
token_pos = tl.program_id(0)
token_id = tl.load(input_ids_ptr + token_pos).to(tl.int64)
k_off = tl.arange(0, BLOCK_K)
routed_mask = k_off < topk_routed
fused_mask = k_off < topk_fused
is_shared = k_off >= topk_routed
expert_id = tl.load(
tid2eid_ptr + token_id * topk_routed + k_off,
mask=routed_mask,
other=0,
).to(tl.int32)
logit = tl.load(
router_logits_ptr + token_pos * num_routed_experts + expert_id,
mask=routed_mask,
other=0.0,
).to(tl.float32)
softplus = tl.maximum(logit, 0.0) + tl.log(1.0 + tl.exp(-tl.abs(logit)))
weight = tl.sqrt(softplus)
weight = tl.where(routed_mask, weight, 0.0)
routed_sum = tl.sum(weight, axis=0)
shared_weight = 1.0 / routed_scaling_factor
final_weight = tl.where(is_shared, shared_weight, weight / routed_sum)
shared_id = num_routed_experts + (k_off - topk_routed)
final_id = tl.where(is_shared, shared_id, expert_id).to(tl.int32)
out_off = token_pos * topk_fused + k_off
tl.store(topk_weights_ptr + out_off, final_weight, mask=fused_mask)
tl.store(topk_ids_ptr + out_off, final_id, mask=fused_mask)
def hash_topk_triton(
router_logits: torch.Tensor,
input_ids: torch.Tensor,
tid2eid: torch.Tensor,
num_fused_shared_experts: int,
routed_scaling_factor: float,
scoring_func: str,
) -> Tuple[torch.Tensor, torch.Tensor]:
assert scoring_func == "sqrtsoftplus"
num_tokens = router_logits.size(0)
num_routed_experts = router_logits.size(1)
topk_routed = tid2eid.size(1)
topk_fused = topk_routed + num_fused_shared_experts
topk_weights = torch.empty(
(num_tokens, topk_fused), dtype=torch.float32, device=router_logits.device
)
topk_ids = torch.empty(
(num_tokens, topk_fused), dtype=torch.int32, device=router_logits.device
)
if num_tokens == 0:
return topk_weights, topk_ids
block_k = max(triton.next_power_of_2(topk_fused), 1)
_hash_topk_triton_kernel[(num_tokens,)](
router_logits,
input_ids,
tid2eid,
topk_weights,
topk_ids,
num_routed_experts=num_routed_experts,
topk_routed=topk_routed,
topk_fused=topk_fused,
routed_scaling_factor=float(routed_scaling_factor),
BLOCK_K=block_k,
num_warps=1,
)
return topk_weights, topk_ids
@@ -0,0 +1,87 @@
"""Fused sigmoid-gate-multiply Triton kernels.
Two variants:
- ``sigmoid_gate_mul``: element-wise ``x * sigmoid(gate)`` when x and gate
have identical shapes.
- ``sigmoid_gate_mul_broadcast``: broadcast ``x * sigmoid(gate)`` when gate
is ``(N, 1)`` and x is ``(N, D)``.
"""
from __future__ import annotations
import torch
import triton
import triton.language as tl
from sglang.srt.utils import is_hip
_is_hip = is_hip()
@triton.jit
def _sigmoid_gate_mul_kernel(
x_ptr,
gate_ptr,
out_ptr,
n_elements,
BLOCK_SIZE: tl.constexpr,
):
pid = tl.program_id(0)
offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
mask = offsets < n_elements
x = tl.load(x_ptr + offsets, mask=mask).to(tl.float32)
g = tl.load(gate_ptr + offsets, mask=mask).to(tl.float32)
out = x * tl.sigmoid(g)
tl.store(out_ptr + offsets, out.to(x_ptr.dtype.element_ty), mask=mask)
def sigmoid_gate_mul(x: torch.Tensor, gate: torch.Tensor) -> torch.Tensor:
"""Compute ``x * sigmoid(gate)`` in a single fused kernel (same-shape)."""
out = torch.empty_like(x)
n = x.numel()
grid = lambda meta: (triton.cdiv(n, meta["BLOCK_SIZE"]),)
_sigmoid_gate_mul_kernel[grid](x, gate, out, n, BLOCK_SIZE=1024)
return out
@triton.jit
def _sigmoid_gate_mul_broadcast_kernel(
out_ptr,
gate_ptr,
x_ptr,
hidden_dim: tl.constexpr,
BLOCK_SIZE: tl.constexpr,
):
row = tl.program_id(0)
g = tl.load(gate_ptr + row).to(tl.float32)
g = tl.sigmoid(g)
offs = tl.arange(0, BLOCK_SIZE)
mask = offs < hidden_dim
x = tl.load(x_ptr + row * hidden_dim + offs, mask=mask).to(tl.float32)
out = x * g
tl.store(
out_ptr + row * hidden_dim + offs,
out.to(x_ptr.dtype.element_ty),
mask=mask,
)
def sigmoid_gate_mul_broadcast(x: torch.Tensor, gate: torch.Tensor) -> torch.Tensor:
"""Compute ``x * sigmoid(gate)`` where gate is (N, 1) and x is (N, D)."""
bs, hidden_dim = x.shape
out = torch.empty_like(x)
BLOCK_SIZE = triton.next_power_of_2(hidden_dim)
max_warps = 16 if _is_hip else 32
num_warps = max(
min(triton.next_power_of_2(triton.cdiv(hidden_dim, 8 * 32)), max_warps), 4
)
_sigmoid_gate_mul_broadcast_kernel[(bs,)](
out,
gate,
x,
hidden_dim=hidden_dim,
BLOCK_SIZE=BLOCK_SIZE,
num_warps=num_warps,
)
return out