254 lines
6.8 KiB
Python
254 lines
6.8 KiB
Python
# Copyright 2025 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.
|
|
# ==============================================================================
|
|
"""Common utilities."""
|
|
|
|
from typing import Any, List, Optional, Tuple
|
|
|
|
import torch
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
from sglang.srt.environ import envs
|
|
|
|
|
|
@triton.jit
|
|
def set_mla_kv_buffer_kernel(
|
|
kv_buffer_ptr,
|
|
cache_k_nope_ptr,
|
|
cache_k_rope_ptr,
|
|
loc_ptr,
|
|
buffer_stride: tl.constexpr,
|
|
nope_stride: tl.constexpr,
|
|
rope_stride: tl.constexpr,
|
|
nope_dim: tl.constexpr,
|
|
rope_dim: tl.constexpr,
|
|
BLOCK: tl.constexpr,
|
|
):
|
|
pid_loc = tl.program_id(0)
|
|
pid_blk = tl.program_id(1)
|
|
|
|
base = pid_blk * BLOCK
|
|
offs = base + tl.arange(0, BLOCK)
|
|
total_dim = nope_dim + rope_dim
|
|
mask = offs < total_dim
|
|
|
|
loc = tl.load(loc_ptr + pid_loc).to(tl.int64)
|
|
dst_ptr = kv_buffer_ptr + loc * buffer_stride + offs
|
|
|
|
if base + BLOCK <= nope_dim:
|
|
src = tl.load(
|
|
cache_k_nope_ptr + pid_loc * nope_stride + offs,
|
|
mask=mask,
|
|
)
|
|
else:
|
|
offs_rope = offs - nope_dim
|
|
src = tl.load(
|
|
cache_k_rope_ptr + pid_loc * rope_stride + offs_rope,
|
|
mask=mask,
|
|
)
|
|
|
|
tl.store(dst_ptr, src, mask=mask)
|
|
|
|
|
|
def set_mla_kv_buffer_triton(
|
|
kv_buffer: torch.Tensor,
|
|
loc: torch.Tensor,
|
|
cache_k_nope: torch.Tensor,
|
|
cache_k_rope: torch.Tensor,
|
|
):
|
|
nope_dim = cache_k_nope.shape[-1]
|
|
rope_dim = cache_k_rope.shape[-1]
|
|
total_dim = nope_dim + rope_dim
|
|
BLOCK = 128
|
|
n_loc = loc.numel()
|
|
grid = (n_loc, triton.cdiv(total_dim, BLOCK))
|
|
|
|
set_mla_kv_buffer_kernel[grid](
|
|
kv_buffer,
|
|
cache_k_nope,
|
|
cache_k_rope,
|
|
loc,
|
|
kv_buffer.stride(0),
|
|
cache_k_nope.stride(0),
|
|
cache_k_rope.stride(0),
|
|
nope_dim,
|
|
rope_dim,
|
|
BLOCK=BLOCK,
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def set_mla_kv_scale_buffer_kernel(
|
|
kv_buffer_ptr,
|
|
cache_k_nope_ptr,
|
|
cache_k_rope_ptr,
|
|
loc_ptr,
|
|
buffer_stride: tl.constexpr,
|
|
nope_stride: tl.constexpr,
|
|
rope_stride: tl.constexpr,
|
|
nope_dim: tl.constexpr,
|
|
rope_dim: tl.constexpr,
|
|
BLOCK: tl.constexpr,
|
|
):
|
|
pid_loc = tl.program_id(0)
|
|
pid_blk = tl.program_id(1)
|
|
|
|
base = pid_blk * BLOCK
|
|
offs = base + tl.arange(0, BLOCK)
|
|
total_dim = nope_dim + rope_dim
|
|
mask = offs < total_dim # Make sure don't cross the boundary
|
|
|
|
loc = tl.load(loc_ptr + pid_loc)
|
|
dst_ptr = kv_buffer_ptr + loc * buffer_stride + offs
|
|
|
|
# Check each offs should read 'nope' or 'rope'
|
|
is_nope = offs < nope_dim
|
|
src_nope = tl.load(
|
|
cache_k_nope_ptr + pid_loc * nope_stride + offs, mask=mask & is_nope, other=0.0
|
|
)
|
|
src_rope = tl.load(
|
|
cache_k_rope_ptr + pid_loc * rope_stride + (offs - nope_dim),
|
|
mask=mask & ~is_nope,
|
|
other=0.0,
|
|
)
|
|
|
|
# Combine nope + rope
|
|
src = src_nope + src_rope
|
|
tl.store(dst_ptr, src, mask=mask)
|
|
|
|
|
|
def set_mla_kv_scale_buffer_triton(
|
|
kv_buffer: torch.Tensor,
|
|
loc: torch.Tensor,
|
|
cache_k_nope: torch.Tensor,
|
|
cache_k_rope: torch.Tensor,
|
|
):
|
|
nope_dim = cache_k_nope.shape[-1]
|
|
rope_dim = cache_k_rope.shape[-1]
|
|
total_dim = nope_dim + rope_dim
|
|
BLOCK = 128 # Keep origin, works for smaller total_dim as well.
|
|
n_loc = loc.numel()
|
|
grid = (n_loc, triton.cdiv(total_dim, BLOCK))
|
|
|
|
set_mla_kv_scale_buffer_kernel[grid](
|
|
kv_buffer,
|
|
cache_k_nope,
|
|
cache_k_rope,
|
|
loc,
|
|
kv_buffer.stride(0),
|
|
cache_k_nope.stride(0),
|
|
cache_k_rope.stride(0),
|
|
nope_dim,
|
|
rope_dim,
|
|
BLOCK=BLOCK,
|
|
)
|
|
|
|
|
|
@triton.jit
|
|
def get_mla_kv_buffer_kernel(
|
|
kv_buffer_ptr,
|
|
cache_k_nope_ptr,
|
|
cache_k_rope_ptr,
|
|
loc_ptr,
|
|
buffer_stride: tl.constexpr,
|
|
nope_stride: tl.constexpr,
|
|
rope_stride: tl.constexpr,
|
|
nope_dim: tl.constexpr,
|
|
rope_dim: tl.constexpr,
|
|
):
|
|
pid_loc = tl.program_id(0)
|
|
loc = tl.load(loc_ptr + pid_loc).to(tl.int64)
|
|
loc_src_ptr = kv_buffer_ptr + loc * buffer_stride
|
|
|
|
nope_offs = tl.arange(0, nope_dim)
|
|
nope_src_ptr = loc_src_ptr + nope_offs
|
|
nope_src = tl.load(nope_src_ptr)
|
|
|
|
tl.store(
|
|
cache_k_nope_ptr + pid_loc * nope_stride + nope_offs,
|
|
nope_src,
|
|
)
|
|
|
|
rope_offs = tl.arange(0, rope_dim)
|
|
rope_src_ptr = loc_src_ptr + nope_dim + rope_offs
|
|
rope_src = tl.load(rope_src_ptr)
|
|
tl.store(
|
|
cache_k_rope_ptr + pid_loc * rope_stride + rope_offs,
|
|
rope_src,
|
|
)
|
|
|
|
|
|
def get_mla_kv_buffer_triton(
|
|
kv_buffer: torch.Tensor,
|
|
loc: torch.Tensor,
|
|
cache_k_nope: torch.Tensor,
|
|
cache_k_rope: torch.Tensor,
|
|
):
|
|
# The source data type will be implicitly converted to the target data type.
|
|
nope_dim = cache_k_nope.shape[-1] # 512
|
|
rope_dim = cache_k_rope.shape[-1] # 64
|
|
n_loc = loc.numel()
|
|
grid = (n_loc,)
|
|
|
|
get_mla_kv_buffer_kernel[grid](
|
|
kv_buffer,
|
|
cache_k_nope,
|
|
cache_k_rope,
|
|
loc,
|
|
kv_buffer.stride(0),
|
|
cache_k_nope.stride(0),
|
|
cache_k_rope.stride(0),
|
|
nope_dim,
|
|
rope_dim,
|
|
)
|
|
|
|
|
|
def maybe_init_custom_mem_pool(
|
|
device: str,
|
|
) -> Tuple[bool, Optional[Any], Optional[str]]:
|
|
"""
|
|
Initialize custom memory pool based on environment variable.
|
|
|
|
This function can be modified to support more features that require a custom memory pool.
|
|
|
|
Args:
|
|
device: The device to allocate memory on
|
|
|
|
Returns:
|
|
Tuple of (enable_custom_mem_pool, custom_mem_pool, custom_mem_pool_type)
|
|
"""
|
|
enable_custom_mem_pool = (
|
|
True if envs.SGLANG_MOONCAKE_CUSTOM_MEM_POOL.get() is not None else False
|
|
)
|
|
|
|
if enable_custom_mem_pool:
|
|
# Currently, only mooncake requires a custom mem pool for MNNVL/Barex PD disaggregation
|
|
from sglang.srt.disaggregation.mooncake.utils import (
|
|
init_mooncake_custom_mem_pool,
|
|
)
|
|
|
|
return init_mooncake_custom_mem_pool(device)
|
|
else:
|
|
return False, None, None
|
|
|
|
|
|
def convert_to_bigram_key(tokens: List[int]) -> List[Tuple[int, int]]:
|
|
# EAGLE uses bigram keys in the radix tree since draft sequence is the one-token-shifted version of target
|
|
# [1, 2, 3, 4] -> [(1,2), (2,3), (3,4)]
|
|
if len(tokens) and isinstance(tokens[0], tuple):
|
|
return tokens
|
|
if len(tokens) < 2:
|
|
return []
|
|
return [(tokens[i], tokens[i + 1]) for i in range(len(tokens) - 1)]
|