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
476 lines
16 KiB
Python
476 lines
16 KiB
Python
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
"""CuTe DSL FP8 Paged MQA Logits runner and custom op.
|
|
|
|
Ported from TensorRT-LLM https://github.com/NVIDIA/TensorRT-LLM/pull/13219
|
|
Provides ``torch.ops.sglang.cute_dsl_fp8_paged_mqa_logits`` as an alternative
|
|
to ``deep_gemm.fp8_paged_mqa_logits`` on Blackwell SM100. It performs well, when the bs is low,
|
|
and the context is long.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
import cutlass
|
|
import cutlass.cute as cute
|
|
import torch
|
|
from cutlass.utils import HardwareInfo
|
|
|
|
from sglang.jit_kernel.cutedsl_fp8_paged_mqa_logits import FP8MQALogitsKernel
|
|
from sglang.srt.utils import is_sm100_supported
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def pick_dsl_expand(
|
|
next_n: int,
|
|
batch_size: int = 0,
|
|
max_ctx: int = 0,
|
|
num_sms: int = 148,
|
|
kernel_atoms: tuple[int, ...] = (1, 2, 3, 4),
|
|
num_heads: int = 0,
|
|
) -> tuple[int, int]:
|
|
"""Pick (expand_factor, effective_next_n) for the DSL paged kernel
|
|
using a wave-aware strategy.
|
|
|
|
The DSL FP8 kernel natively supports ``effective_next_n ∈ kernel_atoms``
|
|
(default ``(1, 2, 3, 4)``). When SM utilization can be improved, reshape
|
|
``[B, next_n, ...]`` -> ``[B * expand_factor, effective_next_n, ...]``
|
|
caller-side.
|
|
|
|
Strategy: enumerate ``(expand_factor, effective_next_n)`` pairs with
|
|
``expand_factor * effective_next_n == next_n`` and ``effective_next_n
|
|
in kernel_atoms``. Score each by ``(waves, -expand_factor)`` where
|
|
``waves = ceil(B * expand_factor * ceil(max_ctx/256) / num_sms)``.
|
|
Pick min waves; on tie, prefer LARGER expand_factor (more SMs busy per
|
|
wave; pays HBM cost of expand_factor x KV re-reads).
|
|
|
|
When ``batch_size == 0`` or ``max_ctx == 0`` (workload unknown), fall
|
|
back to the legacy HBM-minimizing heuristic: largest effective_next_n
|
|
that divides next_n cleanly (still constrained to ``kernel_atoms``).
|
|
"""
|
|
if batch_size <= 0 or max_ctx <= 0:
|
|
for eff in sorted(kernel_atoms, reverse=True):
|
|
if next_n % eff == 0:
|
|
return next_n // eff, eff
|
|
return next_n, 1
|
|
|
|
# Measured override for next_n=6, num_heads=32 on SM100 (~148 SMs): the
|
|
# min-waves heuristic picks 3/1->2 (atom=3) but the kernel's atom=2 path
|
|
# wins by up to ~20% in a jagged (batch, ctx) region the wave model can't
|
|
# see. These bounds are empirical (autotuned), not analytic; outside them
|
|
# min-waves is optimal. Reduces mean split-regret 1.0%->0.05% on the grid.
|
|
if next_n == 6:
|
|
# Native single-launch next_n=6 (factor=1) reads KV once vs 2-3x for the
|
|
# split, and with weights-in-SMEM (see _propose_epi_config) it beats the
|
|
# split by +17..44% once there is enough work to fill the SMs. Requires
|
|
# N=6*num_heads<=256 (the single-MMA TMEM limit), i.e. num_heads<=42.
|
|
# Below the work threshold (few SMs busy) the split's extra tasks win.
|
|
if 0 < num_heads * 6 <= 256:
|
|
native_wins = (
|
|
batch_size >= 16
|
|
or (batch_size >= 4 and max_ctx >= 32768)
|
|
or (batch_size >= 2 and max_ctx >= 131072)
|
|
)
|
|
if native_wins:
|
|
return 1, 6
|
|
use_atom2 = (
|
|
(batch_size >= 45 and max_ctx <= (batch_size - 44) * 32768)
|
|
or (batch_size == 16 and max_ctx >= 49152)
|
|
or (batch_size == 10 and max_ctx >= 90000)
|
|
or (batch_size == 17 and 49152 <= max_ctx <= 110000)
|
|
or (batch_size == 7 and max_ctx >= 120000)
|
|
)
|
|
if use_atom2 and 2 in kernel_atoms:
|
|
return 3, 2
|
|
|
|
SPLIT_KV_TOKENS = 256
|
|
cands = []
|
|
for eff in kernel_atoms:
|
|
if next_n % eff == 0:
|
|
factor = next_n // eff
|
|
ntask = (
|
|
batch_size
|
|
* factor
|
|
* ((max_ctx + SPLIT_KV_TOKENS - 1) // SPLIT_KV_TOKENS)
|
|
)
|
|
waves = (ntask + num_sms - 1) // num_sms
|
|
cands.append((waves, factor, eff))
|
|
if not cands:
|
|
return next_n, 1
|
|
cands.sort(key=lambda x: (x[0], -x[1]))
|
|
_, factor, eff = cands[0]
|
|
return factor, eff
|
|
|
|
|
|
_TORCH_TO_CUTLASS_DTYPE = {
|
|
torch.float16: cutlass.Float16,
|
|
torch.bfloat16: cutlass.BFloat16,
|
|
torch.float32: cutlass.Float32,
|
|
}
|
|
|
|
# Epilogue pipeline-flag presets for the auto-tuner (see _propose_epi_config).
|
|
_EPI_KV_UMMA_SUB = dict(
|
|
max_kv_pipeline=True, max_umma_pipeline=True, smem_subpartition_opt=True
|
|
)
|
|
_EPI_NOWAIT = dict(_EPI_KV_UMMA_SUB, remove_kv_wait_in_epilogue=True)
|
|
|
|
|
|
def _propose_epi_config(
|
|
num_heads: int,
|
|
next_n_k: int,
|
|
batch_split: int,
|
|
max_ctx: int,
|
|
num_sms: int,
|
|
) -> tuple[int, dict]:
|
|
"""Auto-tune (num_epi_subtiles, pipeline_flags) for the FP8 MQA epilogue.
|
|
|
|
Tuned on B300 (~148 SMs) for the GLM-5.2 32-head path; ``next_n_k`` and
|
|
``batch_split`` are the post-split atom and batch reaching the kernel.
|
|
Wins +3..14% vs the untuned base config across the next_n=6 (atom 2/3)
|
|
grid. num_heads>32 is left at the safe baseline (no change).
|
|
"""
|
|
# Only the <=32-head path is tuned; leave wider indexers untouched.
|
|
if num_heads > 32 or num_heads % 8 != 0:
|
|
return 1, {}
|
|
# Native next_n=6 (single launch, N=6*heads<=256): the per-token weight cache
|
|
# is 6*heads regs and spills to local/GMEM (3x slowdown). Reading weights from
|
|
# SMEM instead (max_w_in_reg=8) avoids the spill; combined with the 1x KV read
|
|
# (vs the split's 2-3x) this beats the split by +17..44% at HBM-bound shapes.
|
|
if next_n_k == 6 and num_heads * 6 <= 256:
|
|
return 1, {"max_w_in_reg": 8}
|
|
# num_epi_subtiles=2 interleaves LDTM with FP32 FMA on the multi-slot
|
|
# (atom != 2) epilogue; neutral elsewhere, slightly negative on atom==2.
|
|
nst = 2 if next_n_k != 2 else 1
|
|
if (num_heads // nst) % 4 != 0:
|
|
nst = 1
|
|
waves = (batch_split * ((max_ctx + 255) // 256) + num_sms - 1) // num_sms
|
|
# The nowait + deep KV/UMMA pipeline wins broadly below grid saturation, but
|
|
# above ~130 waves the win flips non-monotonically with occupancy (deep_gemm
|
|
# scheduler resonance — not modelable by waves/work/fill). Measured on B300
|
|
# (~148 SM, hd=32, dense ctx=131k saturated sweep): the 2/3-split (atom 3)
|
|
# resonates positively exactly when post-split batch % 24 == 0 (Bs 48,72 win
|
|
# +10..16%; 40,44,52,56,60,64,80,88 all regress 3-6%); the 3/2-split (atom 2)
|
|
# only resonates at Bs % 144 == 0 (144 wins +12%; 48 regresses). Whitelist
|
|
# those; otherwise fall back to the exact baseline at saturation.
|
|
if next_n_k == 3:
|
|
resonant = batch_split % 24 == 0
|
|
elif next_n_k == 2:
|
|
resonant = batch_split % 144 == 0
|
|
else:
|
|
resonant = False
|
|
if waves >= 130 and not resonant:
|
|
return 1, {}
|
|
# The multi-slot (atom>=3) epilogue benefits at any sub-saturation occupancy;
|
|
# the atom==2 epilogue only benefits once there is enough work to hide the
|
|
# flag overhead (it dominates at ~1 wave).
|
|
flags = _EPI_NOWAIT if (next_n_k >= 3 or waves >= 50) else {}
|
|
return nst, flags
|
|
|
|
|
|
class CuteDSLPagedMQALogitsRunner:
|
|
"""Runner for CuTe DSL FP8 Paged MQA Logits kernel (Blackwell SM100).
|
|
|
|
Caches compiled kernels keyed by static params
|
|
(compute_block_kv, phys_block_kv, num_heads, head_dim, next_n, num_sms).
|
|
"""
|
|
|
|
kernel_cache: dict[tuple, object] = dict()
|
|
|
|
@classmethod
|
|
def _compile(
|
|
cls,
|
|
compute_block_kv,
|
|
phys_block_kv,
|
|
num_heads,
|
|
head_dim,
|
|
next_n,
|
|
num_sms,
|
|
num_epi_subtiles,
|
|
epi_dtype,
|
|
acc_dtype,
|
|
output_dtype,
|
|
pipeline_flags=None,
|
|
):
|
|
"""Compile kernel using fake tensors + TVM FFI."""
|
|
pipeline_flags = pipeline_flags or {}
|
|
key = (
|
|
compute_block_kv,
|
|
phys_block_kv,
|
|
num_heads,
|
|
head_dim,
|
|
next_n,
|
|
num_sms,
|
|
num_epi_subtiles,
|
|
epi_dtype,
|
|
acc_dtype,
|
|
output_dtype,
|
|
tuple(sorted(pipeline_flags.items())),
|
|
)
|
|
if key in cls.kernel_cache:
|
|
return
|
|
|
|
to_cutlass = _TORCH_TO_CUTLASS_DTYPE
|
|
N = next_n * num_heads
|
|
block_bytes = phys_block_kv * (head_dim + 4)
|
|
|
|
sym_num_phys_blocks = cute.sym_int()
|
|
sym_B = cute.sym_int()
|
|
max_ctx = cute.sym_int()
|
|
max_blocks_per_seq = cute.sym_int()
|
|
num_ctas = cute.sym_int()
|
|
|
|
kv_fake = cute.runtime.make_fake_compact_tensor(
|
|
cutlass.Uint8,
|
|
(sym_num_phys_blocks, block_bytes),
|
|
stride_order=(1, 0),
|
|
)
|
|
|
|
q_fake = cute.runtime.make_fake_compact_tensor(
|
|
cutlass.Uint8, (N, head_dim, sym_B), stride_order=(1, 0, 2)
|
|
)
|
|
|
|
w_dtype = (
|
|
cutlass.Float16 if epi_dtype == torch.float16 else to_cutlass[epi_dtype]
|
|
)
|
|
w_fake = cute.runtime.make_fake_compact_tensor(
|
|
w_dtype, (N, sym_B), stride_order=(0, 1)
|
|
)
|
|
|
|
logits_fake = cute.runtime.make_fake_tensor(
|
|
to_cutlass[output_dtype],
|
|
(cute.sym_int(), max_ctx),
|
|
stride=(cute.sym_int64(), 1),
|
|
)
|
|
|
|
bt_fake = cute.runtime.make_fake_compact_tensor(
|
|
cutlass.Int32, (sym_B, max_blocks_per_seq), stride_order=(1, 0)
|
|
)
|
|
|
|
cl_fake = cute.runtime.make_fake_compact_tensor(
|
|
cutlass.Int32, (sym_B,), stride_order=(0,)
|
|
)
|
|
|
|
sm_fake = cute.runtime.make_fake_compact_tensor(
|
|
cutlass.Int32, (num_ctas, 2), stride_order=(1, 0)
|
|
)
|
|
|
|
fake_stream = cute.runtime.make_fake_stream(use_tvm_ffi_env_stream=True)
|
|
|
|
kernel = FP8MQALogitsKernel(
|
|
block_kv=compute_block_kv,
|
|
phys_block_kv=phys_block_kv,
|
|
num_heads=num_heads,
|
|
head_dim=head_dim,
|
|
next_n=next_n,
|
|
num_sms=num_sms,
|
|
num_epi_subtiles=num_epi_subtiles,
|
|
epi_dtype=to_cutlass[epi_dtype],
|
|
acc_dtype=to_cutlass[acc_dtype],
|
|
output_dtype=to_cutlass[output_dtype],
|
|
**pipeline_flags,
|
|
)
|
|
|
|
compiled = cute.compile(
|
|
kernel,
|
|
kv_fake,
|
|
q_fake,
|
|
w_fake,
|
|
logits_fake,
|
|
bt_fake,
|
|
cl_fake,
|
|
sm_fake,
|
|
cutlass.Int32(1),
|
|
cutlass.Int32(1),
|
|
fake_stream,
|
|
options="--enable-tvm-ffi",
|
|
)
|
|
cls.kernel_cache[key] = compiled
|
|
logger.debug(
|
|
f"[compile cute_dsl fp8_paged_mqa_logits] {key}"
|
|
f" kv_stages={kernel.num_kv_stages}"
|
|
f" umma_stages={kernel.num_umma_stages}"
|
|
)
|
|
|
|
@classmethod
|
|
def forward(
|
|
cls,
|
|
q: torch.Tensor,
|
|
kv_fused: torch.Tensor,
|
|
weights: torch.Tensor,
|
|
context_lens: torch.Tensor,
|
|
block_table: torch.Tensor,
|
|
schedule_meta: torch.Tensor,
|
|
max_context_len: int,
|
|
num_epi_subtiles: int | None = None,
|
|
epi_dtype: torch.dtype = torch.float32,
|
|
acc_dtype: torch.dtype = torch.float32,
|
|
output_dtype: torch.dtype = torch.float32,
|
|
) -> torch.Tensor:
|
|
"""Execute FP8 paged MQA logits kernel.
|
|
|
|
Args:
|
|
q: [B, next_n, H, D] FP8
|
|
kv_fused: [num_blocks, phys_block_kv, 1, D+4] uint8
|
|
weights: [B*next_n, H] float32
|
|
context_lens: [B] int32
|
|
block_table: [B, max_blocks] int32
|
|
schedule_meta: [num_sms+1, 2] int32
|
|
max_context_len: int
|
|
num_epi_subtiles: epilogue sub-tile count (1, 2, or 4); None auto-tunes
|
|
epi_dtype: epilogue compute dtype
|
|
acc_dtype: MMA accumulator dtype
|
|
output_dtype: output logits dtype
|
|
Returns:
|
|
logits: [B*next_n, max_context_len] output_dtype
|
|
"""
|
|
B, next_n, H, D = q.shape
|
|
N = next_n * H
|
|
phys_block_kv = kv_fused.shape[1]
|
|
compute_block_kv = 128
|
|
num_phys_blocks = kv_fused.shape[0]
|
|
num_sms = HardwareInfo().get_device_multiprocessor_count()
|
|
|
|
# Auto-tune (num_epi_subtiles, pipeline flags) for the epilogue when the
|
|
# caller leaves num_epi_subtiles unset; an explicit value disables the
|
|
# flag auto-tuning and is honored as-is.
|
|
auto_nst, pipeline_flags = _propose_epi_config(
|
|
H, next_n, B, max_context_len, num_sms
|
|
)
|
|
if num_epi_subtiles is None:
|
|
num_epi_subtiles = auto_nst
|
|
else:
|
|
pipeline_flags = {}
|
|
|
|
# Reshape Q: [B, next_n, H, D] -> [B, N, D] -> [N, D, B]
|
|
q_3d = q.reshape(B, N, D).permute(1, 2, 0)
|
|
|
|
# Reshape weights: [B*next_n, H] -> [B, N] -> [N, B]
|
|
if epi_dtype == torch.float16:
|
|
# TODO: move type conversion to weight loading
|
|
w_2d = weights.reshape(B, N).half().t()
|
|
else:
|
|
w_2d = weights.reshape(B, N).t()
|
|
|
|
# Flatten fused KV to [num_phys_blocks, block_bytes]
|
|
kv_flat = kv_fused.reshape(num_phys_blocks, -1)
|
|
|
|
# Allocate output with alignment padding
|
|
SPLIT_KV = compute_block_kv * 2 # NUM_MATH_WG = 2
|
|
aligned_max_ctx = ((max_context_len + SPLIT_KV - 1) // SPLIT_KV) * SPLIT_KV
|
|
logits = torch.empty(
|
|
(B * next_n, aligned_max_ctx),
|
|
device=q.device,
|
|
dtype=output_dtype,
|
|
)
|
|
logits = logits[:, :max_context_len]
|
|
|
|
key = (
|
|
compute_block_kv,
|
|
phys_block_kv,
|
|
H,
|
|
D,
|
|
next_n,
|
|
num_sms,
|
|
num_epi_subtiles,
|
|
epi_dtype,
|
|
acc_dtype,
|
|
output_dtype,
|
|
tuple(sorted(pipeline_flags.items())),
|
|
)
|
|
if key not in cls.kernel_cache:
|
|
cls._compile(
|
|
compute_block_kv,
|
|
phys_block_kv,
|
|
H,
|
|
D,
|
|
next_n,
|
|
num_sms,
|
|
num_epi_subtiles,
|
|
epi_dtype,
|
|
acc_dtype,
|
|
output_dtype,
|
|
pipeline_flags,
|
|
)
|
|
compiled = cls.kernel_cache[key]
|
|
|
|
# FP8 q needs uint8 view to match compile-time dtype
|
|
q_for_ffi = (
|
|
q_3d.view(torch.uint8)
|
|
if q_3d.dtype in (torch.float8_e4m3fn, torch.float8_e5m2)
|
|
else q_3d
|
|
)
|
|
|
|
compiled(
|
|
kv_flat,
|
|
q_for_ffi,
|
|
w_2d,
|
|
logits,
|
|
block_table,
|
|
context_lens,
|
|
schedule_meta,
|
|
num_phys_blocks,
|
|
B,
|
|
)
|
|
return logits
|
|
|
|
|
|
@torch.library.custom_op(
|
|
"sglang::cute_dsl_fp8_paged_mqa_logits",
|
|
mutates_args=(),
|
|
device_types="cuda",
|
|
)
|
|
def cute_dsl_fp8_paged_mqa_logits(
|
|
q: torch.Tensor,
|
|
kv_fused: torch.Tensor,
|
|
weights: torch.Tensor,
|
|
context_lens: torch.Tensor,
|
|
block_table: torch.Tensor,
|
|
schedule_meta: torch.Tensor,
|
|
max_context_len: int,
|
|
num_epi_subtiles: int | None = None,
|
|
epi_dtype: torch.dtype = torch.float32,
|
|
acc_dtype: torch.dtype = torch.float32,
|
|
output_dtype: torch.dtype = torch.float32,
|
|
) -> torch.Tensor:
|
|
if not is_sm100_supported():
|
|
raise ValueError("CuteDSL FP8 Paged MQA Logits only supports SM 100 family.")
|
|
return CuteDSLPagedMQALogitsRunner.forward(
|
|
q,
|
|
kv_fused,
|
|
weights,
|
|
context_lens,
|
|
block_table,
|
|
schedule_meta,
|
|
max_context_len,
|
|
num_epi_subtiles=num_epi_subtiles,
|
|
epi_dtype=epi_dtype,
|
|
acc_dtype=acc_dtype,
|
|
output_dtype=output_dtype,
|
|
)
|
|
|
|
|
|
@torch.library.register_fake("sglang::cute_dsl_fp8_paged_mqa_logits")
|
|
def _(
|
|
q: torch.Tensor,
|
|
kv_fused: torch.Tensor,
|
|
weights: torch.Tensor,
|
|
context_lens: torch.Tensor,
|
|
block_table: torch.Tensor,
|
|
schedule_meta: torch.Tensor,
|
|
max_context_len: int,
|
|
num_epi_subtiles: int | None = None,
|
|
epi_dtype: torch.dtype = torch.float32,
|
|
acc_dtype: torch.dtype = torch.float32,
|
|
output_dtype: torch.dtype = torch.float32,
|
|
) -> torch.Tensor:
|
|
B = q.shape[0]
|
|
next_n = q.shape[1]
|
|
return torch.empty(
|
|
B * next_n,
|
|
max_context_len,
|
|
dtype=output_dtype,
|
|
device=q.device,
|
|
)
|