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
238 lines
6.9 KiB
Python
238 lines
6.9 KiB
Python
from typing import Literal
|
|
|
|
import torch
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
from sglang.srt.layers.quantization.fp8_kernel import is_fp8_fnuz
|
|
|
|
_FP8_DTYPE = torch.float8_e4m3fnuz if is_fp8_fnuz() else torch.float8_e4m3fn
|
|
_FP8_INFO = torch.finfo(_FP8_DTYPE)
|
|
|
|
# DeepSeek-V4 MLA paged FP8 cache layout
|
|
_MLA_HEAD_DIM = 512 # full MLA token dim (elements per input row)
|
|
_MLA_NOPE_DIM = 448 # nope sub-dim (elements)
|
|
_MLA_TILE_SIZE = 64 # FP8 tile width (also rope copy stride)
|
|
_MLA_SLOT_BYTES = 576 # bytes per slot in the paged FP8 cache
|
|
_MLA_BF16_SLOT_ELEMS = _MLA_SLOT_BYTES // 2 # bf16-view slot stride (elements)
|
|
_MLA_BF16_ROPE_OFFSET = _MLA_NOPE_DIM // 2 # bf16-view rope offset (elements)
|
|
_MLA_SCALES_PER_TOKEN = 8 # UE8M0 scales per token (7 nope tiles + 1 padding)
|
|
_MLA_NUM_TILES = 8 # 7 nope quant tiles + 1 rope copy tile
|
|
_MLA_ROPE_TILE_ID = 7 # tile id reserved for the rope copy
|
|
|
|
# C4 indexer paged FP8 cache layout
|
|
_INDEXER_HEAD_DIM = 128
|
|
|
|
_UE8M0_EXPONENT_BIAS = 127
|
|
|
|
|
|
@triton.jit
|
|
def _triton_fused_store_flashmla_kernel(
|
|
input_ptr,
|
|
cache_fp8_ptr,
|
|
cache_bf16_ptr,
|
|
cache_u8_ptr,
|
|
indices_ptr,
|
|
N,
|
|
PAGE_SIZE: tl.constexpr,
|
|
BYTES_PER_PAGE: tl.constexpr,
|
|
BYTES_PER_PAGE_BF16: tl.constexpr,
|
|
S_OFFSET: tl.constexpr,
|
|
TILE_SIZE: tl.constexpr,
|
|
HEAD_DIM: tl.constexpr,
|
|
NOPE_DIM: tl.constexpr,
|
|
SLOT_BYTES: tl.constexpr,
|
|
BF16_SLOT_ELEMS: tl.constexpr,
|
|
BF16_ROPE_OFFSET: tl.constexpr,
|
|
SCALES_PER_TOKEN: tl.constexpr,
|
|
ROPE_TILE_ID: tl.constexpr,
|
|
UE8M0_BIAS: tl.constexpr,
|
|
FP8_MIN: tl.constexpr,
|
|
FP8_MAX: tl.constexpr,
|
|
EPS: tl.constexpr,
|
|
):
|
|
token_id = tl.program_id(0)
|
|
tile_id = tl.program_id(1)
|
|
|
|
if token_id >= N:
|
|
return
|
|
|
|
loc = tl.load(indices_ptr + token_id).to(tl.int32)
|
|
page = loc // PAGE_SIZE
|
|
slot = loc % PAGE_SIZE
|
|
|
|
if tile_id == ROPE_TILE_ID:
|
|
rope_lane = tl.arange(0, TILE_SIZE)
|
|
rope_vals = tl.load(input_ptr + token_id * HEAD_DIM + NOPE_DIM + rope_lane)
|
|
rope_bf16_offset = (
|
|
page * BYTES_PER_PAGE_BF16
|
|
+ slot * BF16_SLOT_ELEMS
|
|
+ BF16_ROPE_OFFSET
|
|
+ rope_lane
|
|
)
|
|
tl.store(cache_bf16_ptr + rope_bf16_offset, rope_vals)
|
|
else:
|
|
tile_lane = tl.arange(0, TILE_SIZE)
|
|
x_bf16 = tl.load(
|
|
input_ptr + token_id * HEAD_DIM + tile_id * TILE_SIZE + tile_lane
|
|
)
|
|
x_fp32 = x_bf16.to(tl.float32)
|
|
|
|
abs_max = tl.max(tl.abs(x_fp32))
|
|
scale = tl.maximum(abs_max, EPS) / FP8_MAX
|
|
|
|
# cast scale to ue8m0 format
|
|
log2_scale = tl.log2(scale)
|
|
ceil_log2 = tl.math.ceil(log2_scale)
|
|
inv_scale = tl.exp2(-ceil_log2)
|
|
|
|
x_fp8 = tl.clamp(x_fp32 * inv_scale, FP8_MIN, FP8_MAX).to(
|
|
cache_fp8_ptr.dtype.element_ty
|
|
)
|
|
|
|
nope_offset = (
|
|
page * BYTES_PER_PAGE + slot * SLOT_BYTES + tile_id * TILE_SIZE + tile_lane
|
|
)
|
|
tl.store(cache_fp8_ptr + nope_offset, x_fp8)
|
|
|
|
ue8m0 = (ceil_log2.to(tl.int32) + UE8M0_BIAS).to(tl.uint8)
|
|
scale_offset = (
|
|
page * BYTES_PER_PAGE + S_OFFSET + slot * SCALES_PER_TOKEN + tile_id
|
|
)
|
|
tl.store(cache_u8_ptr + scale_offset, ue8m0)
|
|
|
|
|
|
def triton_fused_store_flashmla(
|
|
input: torch.Tensor,
|
|
cache: torch.Tensor,
|
|
indices: torch.Tensor,
|
|
page_size: int,
|
|
) -> None:
|
|
"""Fused FP8 quantise + paged scatter for the SWA (flashmla) KV cache."""
|
|
N = input.shape[0]
|
|
if N == 0:
|
|
return
|
|
|
|
bytes_per_page = cache.shape[1]
|
|
cache_fp8 = cache.view(_FP8_DTYPE)
|
|
cache_bf16 = cache.view(torch.bfloat16)
|
|
indices_i32 = indices.to(torch.int32) if indices.dtype != torch.int32 else indices
|
|
|
|
_triton_fused_store_flashmla_kernel[(N, _MLA_NUM_TILES)](
|
|
input,
|
|
cache_fp8,
|
|
cache_bf16,
|
|
cache,
|
|
indices_i32,
|
|
N,
|
|
PAGE_SIZE=page_size,
|
|
BYTES_PER_PAGE=bytes_per_page,
|
|
BYTES_PER_PAGE_BF16=bytes_per_page // 2,
|
|
S_OFFSET=page_size * _MLA_SLOT_BYTES,
|
|
TILE_SIZE=_MLA_TILE_SIZE,
|
|
HEAD_DIM=_MLA_HEAD_DIM,
|
|
NOPE_DIM=_MLA_NOPE_DIM,
|
|
SLOT_BYTES=_MLA_SLOT_BYTES,
|
|
BF16_SLOT_ELEMS=_MLA_BF16_SLOT_ELEMS,
|
|
BF16_ROPE_OFFSET=_MLA_BF16_ROPE_OFFSET,
|
|
SCALES_PER_TOKEN=_MLA_SCALES_PER_TOKEN,
|
|
ROPE_TILE_ID=_MLA_ROPE_TILE_ID,
|
|
UE8M0_BIAS=_UE8M0_EXPONENT_BIAS,
|
|
FP8_MIN=_FP8_INFO.min,
|
|
FP8_MAX=_FP8_INFO.max,
|
|
EPS=1e-8,
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def _triton_fused_store_indexer_kernel(
|
|
input_ptr,
|
|
cache_fp8_ptr,
|
|
cache_f32_ptr,
|
|
indices_ptr,
|
|
N,
|
|
PAGE_SIZE: tl.constexpr,
|
|
BYTES_PER_PAGE: tl.constexpr,
|
|
BYTES_PER_PAGE_F32: tl.constexpr,
|
|
SCALE_PAGE_OFFSET_F32: tl.constexpr,
|
|
HEAD_DIM: tl.constexpr,
|
|
FP8_MIN: tl.constexpr,
|
|
FP8_MAX: tl.constexpr,
|
|
EPS: tl.constexpr,
|
|
):
|
|
token_id = tl.program_id(0)
|
|
if token_id >= N:
|
|
return
|
|
|
|
loc = tl.load(indices_ptr + token_id).to(tl.int32)
|
|
page = loc // PAGE_SIZE
|
|
slot = loc % PAGE_SIZE
|
|
|
|
lane = tl.arange(0, HEAD_DIM)
|
|
x_fp32 = tl.load(input_ptr + token_id * HEAD_DIM + lane).to(tl.float32)
|
|
|
|
abs_max = tl.max(tl.abs(x_fp32))
|
|
scale = tl.maximum(abs_max, EPS) / FP8_MAX
|
|
inv_scale = 1.0 / scale
|
|
|
|
x_fp8 = tl.clamp(x_fp32 * inv_scale, FP8_MIN, FP8_MAX).to(
|
|
cache_fp8_ptr.dtype.element_ty
|
|
)
|
|
|
|
fp8_offset = page * BYTES_PER_PAGE + slot * HEAD_DIM + lane
|
|
tl.store(cache_fp8_ptr + fp8_offset, x_fp8)
|
|
|
|
f32_offset = page * BYTES_PER_PAGE_F32 + SCALE_PAGE_OFFSET_F32 + slot
|
|
tl.store(cache_f32_ptr + f32_offset, scale)
|
|
|
|
|
|
def triton_fused_store_indexer(
|
|
input: torch.Tensor,
|
|
cache: torch.Tensor,
|
|
indices: torch.Tensor,
|
|
page_size: int,
|
|
) -> None:
|
|
"""Fused FP8 quantise + paged scatter for the C4 indexer KV cache."""
|
|
N = input.shape[0]
|
|
if N == 0:
|
|
return
|
|
|
|
bytes_per_page = cache.shape[1]
|
|
bytes_per_page_f32 = bytes_per_page // 4
|
|
scale_page_offset_f32 = (_INDEXER_HEAD_DIM * page_size) // 4
|
|
|
|
cache_fp8 = cache.view(_FP8_DTYPE)
|
|
cache_f32 = cache.view(torch.float32)
|
|
indices_i32 = indices.to(torch.int32) if indices.dtype != torch.int32 else indices
|
|
|
|
_triton_fused_store_indexer_kernel[(N,)](
|
|
input,
|
|
cache_fp8,
|
|
cache_f32,
|
|
indices_i32,
|
|
N,
|
|
PAGE_SIZE=page_size,
|
|
BYTES_PER_PAGE=bytes_per_page,
|
|
BYTES_PER_PAGE_F32=bytes_per_page_f32,
|
|
SCALE_PAGE_OFFSET_F32=scale_page_offset_f32,
|
|
HEAD_DIM=_INDEXER_HEAD_DIM,
|
|
FP8_MIN=_FP8_INFO.min,
|
|
FP8_MAX=_FP8_INFO.max,
|
|
EPS=1e-8,
|
|
)
|
|
|
|
|
|
def triton_fused_store_cache(
|
|
input: torch.Tensor,
|
|
cache: torch.Tensor,
|
|
indices: torch.Tensor,
|
|
*,
|
|
page_size: int,
|
|
type: Literal["flashmla", "indexer"],
|
|
) -> None:
|
|
"""ROCm dispatch for fused_store_cache()."""
|
|
if type == "flashmla":
|
|
triton_fused_store_flashmla(input, cache, indices, page_size)
|
|
else:
|
|
triton_fused_store_indexer(input, cache, indices, page_size)
|