Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions vllm/v1/attention/backends/mla/triton_mla.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
MLACommonBackend,
MLACommonImpl,
MLACommonMetadata,
MLACommonMetadataBuilder,
)
from vllm.model_executor.layers.batch_invariant import (
vllm_is_batch_invariant,
)
from vllm.platforms.interface import DeviceCapability
from vllm.v1.attention.backend import (
AttentionCGSupport,
AttentionLayer,
AttentionType,
is_quantized_kv_cache,
Expand All @@ -26,6 +28,12 @@
logger = init_logger(__name__)


class TritonMLAMetadataBuilder(MLACommonMetadataBuilder[MLACommonMetadata]):
_cudagraph_support: ClassVar[AttentionCGSupport] = (
Comment thread
koush marked this conversation as resolved.
Outdated
AttentionCGSupport.UNIFORM_SINGLE_TOKEN_DECODE
)


class TritonMLABackend(MLACommonBackend):
supported_dtypes: ClassVar[list[torch.dtype]] = [torch.float16, torch.bfloat16]
supported_kv_cache_dtypes: ClassVar[list[CacheDType]] = [
Expand All @@ -37,6 +45,10 @@ class TritonMLABackend(MLACommonBackend):
def get_name() -> str:
return "TRITON_MLA"

@staticmethod
def get_builder_cls() -> type["TritonMLAMetadataBuilder"]:
return TritonMLAMetadataBuilder

@staticmethod
def get_impl_cls() -> type["TritonMLAImpl"]:
return TritonMLAImpl
Expand Down Expand Up @@ -98,6 +110,11 @@ def __init__(
"TritonMLA V1 with FP8 KV cache not yet supported"
)

# Pre-compute sm_count to avoid recomputing it. Use device 0 as a proxy
# (assumes all devices are similar)
properties = torch.cuda.get_device_properties(torch.device("cuda:0"))
Comment thread
koush marked this conversation as resolved.
Outdated
self._sm_count = properties.multi_processor_count

def _flash_attn_varlen_diff_headdims(
self, q, k, v, return_softmax_lse=False, softmax_scale=None, **kwargs
):
Expand Down Expand Up @@ -134,8 +151,11 @@ def forward_mqa(
)
lse = torch.zeros(B, q_num_heads, dtype=q.dtype, device=q.device)

# For batch invariance, use only 1 split to ensure deterministic reduction
num_kv_splits = 1 if vllm_is_batch_invariant() else 4
if vllm_is_batch_invariant():
num_kv_splits = 1
else:
heads_per_64 = (q_num_heads + 63) // 64
num_kv_splits = min(max(self._sm_count // heads_per_64, 1), 16)

# TODO(lucas) Allocate ahead of time
attn_logits = torch.empty(
Expand Down
44 changes: 26 additions & 18 deletions vllm/v1/attention/ops/triton_decode_attention.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,12 @@ def _fwd_grouped_kernel_stage1(
cur_batch_req_idx = cur_batch

offs_q = cur_batch * stride_qbs + cur_head[:, None] * stride_qh + offs_d[None, :]
q = tl.load(Q + offs_q, mask=(mask_h[:, None]) & (mask_d[None, :]), other=0.0)
q = tl.load(
Comment thread
koush marked this conversation as resolved.
Q + offs_q,
mask=(mask_h[:, None]) & (mask_d[None, :]),
other=0.0,
cache_modifier=".ca",
)

if BLOCK_DPE > 0:
offs_dpe = BLOCK_DMODEL + tl.arange(0, BLOCK_DPE)
Expand All @@ -304,7 +309,10 @@ def _fwd_grouped_kernel_stage1(
cur_batch * stride_qbs + cur_head[:, None] * stride_qh + offs_dpe[None, :]
)
qpe = tl.load(
Q + off_qpe, mask=(mask_h[:, None]) & (mask_dpe[None, :]), other=0.0
Q + off_qpe,
mask=(mask_h[:, None]) & (mask_dpe[None, :]),
other=0.0,
cache_modifier=".ca",
)

kv_len_per_split = tl.cdiv(cur_batch_seq_len, NUM_KV_SPLITS)
Expand All @@ -316,37 +324,40 @@ def _fwd_grouped_kernel_stage1(
acc = tl.zeros([BLOCK_H, BLOCK_DV], dtype=tl.float32)

if split_kv_end > split_kv_start:
for start_n in range(split_kv_start, split_kv_end, BLOCK_N):
base_offs_k = cur_kv_head * stride_buf_kh + offs_d[:, None]
base_offs_v = cur_kv_head * stride_buf_vh + offs_dv[None, :]
if BLOCK_DPE > 0:
base_offs_kpe = cur_kv_head * stride_buf_kh + offs_dpe[:, None]

for start_n in tl.range(split_kv_start, split_kv_end, BLOCK_N):
Comment thread
koush marked this conversation as resolved.
offs_n = start_n + tl.arange(0, BLOCK_N)
kv_page_number = tl.load(
Req_to_tokens
+ stride_req_to_tokens_b * cur_batch_req_idx
+ offs_n // PAGE_SIZE,
mask=offs_n < split_kv_end,
other=0,
cache_modifier=".ca",
)
kv_loc = kv_page_number * PAGE_SIZE + offs_n % PAGE_SIZE
offs_buf_k = (
kv_loc[None, :] * stride_buf_kbs
+ cur_kv_head * stride_buf_kh
+ offs_d[:, None]
)

# explicitly facilitate overlapping load/compute
offs_buf_k = kv_loc[None, :] * stride_buf_kbs + base_offs_k
k = tl.load(
K_Buffer + offs_buf_k,
mask=(offs_n[None, :] < split_kv_end) & (mask_d[:, None]),
other=0.0,
cache_modifier=".cg",
)

qk = tl.dot(q, k.to(q.dtype))
if BLOCK_DPE > 0:
offs_buf_kpe = (
kv_loc[None, :] * stride_buf_kbs
+ cur_kv_head * stride_buf_kh
+ offs_dpe[:, None]
)
offs_buf_kpe = kv_loc[None, :] * stride_buf_kbs + base_offs_kpe
kpe = tl.load(
K_Buffer + offs_buf_kpe,
mask=(offs_n[None, :] < split_kv_end) & (mask_dpe[:, None]),
other=0.0,
cache_modifier=".cg",
)
qk += tl.dot(qpe, kpe.to(qpe.dtype))
qk *= sm_scale
Expand All @@ -358,15 +369,12 @@ def _fwd_grouped_kernel_stage1(
mask_h[:, None] & (offs_n[None, :] < split_kv_end), qk, float("-inf")
)

offs_buf_v = (
kv_loc[:, None] * stride_buf_vbs
+ cur_kv_head * stride_buf_vh
+ offs_dv[None, :]
)
offs_buf_v = kv_loc[:, None] * stride_buf_vbs + base_offs_v
v = tl.load(
V_Buffer + offs_buf_v,
mask=(offs_n[:, None] < split_kv_end) & (mask_dv[None, :]),
other=0.0,
cache_modifier=".cg",
)

n_e_max = tl.maximum(tl.max(qk, 1), e_max)
Expand Down