Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
255cd9d
[None][feat] Add CuTE DSL FP8 paged MQA logits kernel for Blackwell S…
limin2021 Apr 20, 2026
c32db8f
[None][fix] Fix docstring script filename in fp8_paged_mqa_logits.py
limin2021 Apr 20, 2026
b235eb1
[None][fix] Update copyright year in paged_mqa_logits __init__.py
limin2021 Apr 20, 2026
69d7170
[None][fix] Remove unused max_mem_gb argument from benchmark
limin2021 Apr 20, 2026
a2b9b43
[None][fix] Fix stream handling, add arch guard, and rename kernel class
limin2021 Apr 21, 2026
a2b0de7
[None][fix] Ensure CuTE DSL op registration when only logits kernel i…
limin2021 Apr 21, 2026
fe637c8
[None][refactor] Rename use_cute_dsl_logits to use_cute_dsl_paged_mqa…
limin2021 Apr 21, 2026
8f9b0e1
[None][fix] Remove redundant SM version check from DSA logits config
limin2021 Apr 21, 2026
cf418ab
[None][fix] Clean up DeepGEMM/DG-FullK references in docstrings and u…
limin2021 Apr 21, 2026
b1260fb
[None][refactor] Migrate MQA logits runner to fake tensor + TVM FFI
limin2021 Apr 21, 2026
4ef3d13
[None][fix] Remove commented-out debug code from fp8_paged_mqa_logits
limin2021 Apr 21, 2026
670cd16
[None][fix] Replace compile print with logger.debug in MQA logits
limin2021 Apr 21, 2026
0a1e93d
[None][fix] Add dtype validation to cute_dsl_fp8_paged_mqa_logits wra…
limin2021 Apr 22, 2026
fabc902
[None][test] Improve fp16 accuracy test and benchmark for MQA logits
limin2021 Apr 22, 2026
aeb32d8
[None][cleanup] Remove dead standalone test code and deduplicate dtyp…
limin2021 Apr 22, 2026
d0fa1cb
[None][fix] Validate num_heads divisible by 4 regardless of num_epi_s…
limin2021 Apr 22, 2026
38ec767
[None][cleanup] Remove unused variables and unnecessary noqa comments
limin2021 Apr 22, 2026
719b333
[None][fix] Add missing use_cute_dsl_paged_mqa_logits to test mock co…
limin2021 Apr 22, 2026
1a157f4
[None][fix] Fix TMA SMEM alignment for fp16 epilogue and support DSL …
limin2021 Apr 23, 2026
6681031
[None][fix] Fix OOB read in zero-work CTA and move test seed into helper
limin2021 Apr 23, 2026
1c68831
[None][feat] Support multi-block TMA for phys_block_kv < 128 in DSL p…
limin2021 Apr 23, 2026
862260c
[None][fix] Move shuffle before barrier acquire to match DeepGEMM sch…
limin2021 Apr 23, 2026
0331897
[None][cleanup] Remove commented-out test_deepgemm_fp8_paged_mqa_logits
limin2021 Apr 23, 2026
0ca0f27
Merge branch 'main' into add_dsl_indexer_gemm
limin2021 Apr 24, 2026
26effcc
[None][cleanup] Remove unused helpers in DSL paged MQA logits kernel …
limin2021 Apr 28, 2026
f34fb16
[None][fix] Skip DSL backend on non-SM100 archs in indexer decode test
limin2021 Apr 29, 2026
9db90f0
Merge remote-tracking branch 'github-upstream/main' into add_dsl_inde…
limin2021 May 1, 2026
0a84ecc
Merge remote-tracking branch 'github-upstream/main' into add_dsl_inde…
limin2021 May 7, 2026
4bcbd79
[None][test] Fix DSL indexer scheduler buffer aliasing and extend FP8…
limin2021 May 8, 2026
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
19 changes: 14 additions & 5 deletions tensorrt_llm/_torch/attention_backend/sparse/dsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,10 @@ def __init__(self,
self.ln_events = [torch.cuda.Event(), torch.cuda.Event()]
self.use_cute_dsl_topk = (sparse_attention_config.use_cute_dsl_topk
and IS_CUTLASS_DSL_AVAILABLE)
self.use_cute_dsl_logits = (getattr(sparse_attention_config,
'use_cute_dsl_logits', False)
and IS_CUTLASS_DSL_AVAILABLE
and get_sm_version() >= 100)
Comment thread
limin2021 marked this conversation as resolved.
Outdated
self.weight_scale_factor = self.softmax_scale * self.n_heads**-0.5

self._enable_heuristic_topk = (
Expand Down Expand Up @@ -1665,11 +1669,16 @@ def sparse_attn_indexer(
k_cache = metadata.kv_cache_manager.get_indexer_k_cache_buffers(
self.layer_idx)

logits_decode = fp8_paged_mqa_logits(q_decode, k_cache,
weights_decode, context_lens,
block_table,
scheduler_metadata_buffer,
max_seq_len)
if self.use_cute_dsl_logits:
logits_decode = torch.ops.trtllm.cute_dsl_fp8_paged_mqa_logits(
q_decode, k_cache, weights_decode, context_lens,
block_table, scheduler_metadata_buffer, max_seq_len)
else:
logits_decode = fp8_paged_mqa_logits(q_decode, k_cache,
weights_decode,
context_lens, block_table,
scheduler_metadata_buffer,
max_seq_len)

if use_custom_topk:
# Kernel expects kv_lens (total cache length), not seq_lens (new tokens)
Expand Down
209 changes: 209 additions & 0 deletions tensorrt_llm/_torch/custom_ops/cute_dsl_custom_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -5127,3 +5127,212 @@ def warmup_cute_dsl_indexer_topk(
f"Warmed up CuTE DSL indexer top-k kernels: dtype={dtype}, "
f"SingleCTA bucketed_num_cols=[2^{min_seq_len_log2}..2^{max_seq_len_log2}], "
f"{multi_cta_info}, top_k={top_k}, next_n={next_n}")

# ------------------------------------------------------------------ #
# CuTE DSL FP8 Paged MQA Logits (Blackwell SM100) #
# ------------------------------------------------------------------ #
from ..cute_dsl_kernels.blackwell.paged_mqa_logits import \
FP8MQALogitsDGFullKKernel

class CuteDSLPagedMQALogitsRunner:
"""Runner for CuTe DSL FP8 Paged MQA Logits kernel (Blackwell SM100).

Caches compiled kernels keyed by static params
(block_kv, num_heads, head_dim, next_n, num_sms).
"""

kernel_cache = dict()

@classmethod
def _make_dlpacks(cls, kv_flat, q_3d, w_2d, logits, block_table,
context_lens, schedule_meta):
"""Wrap tensors with dynamic shape markers for JIT reuse."""
from cutlass.cute.runtime import from_dlpack
dl_kv = from_dlpack(kv_flat).mark_compact_shape_dynamic(mode=0)
q_for_dl = q_3d.view(
torch.uint8) if q_3d.dtype in (torch.float8_e4m3fn,
torch.float8_e5m2) else q_3d
dl_q = from_dlpack(q_for_dl).mark_compact_shape_dynamic(
mode=2, stride_order=(2, 0, 1))
dl_w = from_dlpack(w_2d).mark_compact_shape_dynamic(
mode=1, stride_order=(1, 0))
dl_logits = from_dlpack(logits).mark_compact_shape_dynamic(
mode=0, stride_order=(0, 1)).mark_compact_shape_dynamic(
mode=1, stride_order=(0, 1))
dl_bt = from_dlpack(block_table).mark_compact_shape_dynamic(
mode=0, stride_order=(0, 1)).mark_compact_shape_dynamic(
mode=1, stride_order=(0, 1))
dl_cl = from_dlpack(context_lens).mark_compact_shape_dynamic(mode=0)
dl_sm = from_dlpack(schedule_meta).mark_compact_shape_dynamic(
mode=0)
return dl_kv, dl_q, dl_w, dl_logits, dl_bt, dl_cl, dl_sm

_TORCH_TO_CUTLASS_DTYPE = {
Comment thread
yuxianq marked this conversation as resolved.
Outdated
torch.float16: cutlass.Float16,
torch.bfloat16: cutlass.BFloat16,
torch.float32: cutlass.Float32,
}

@classmethod
def _compile(cls, block_kv, num_heads, head_dim, next_n, num_sms,
kv_flat, q_3d, w_2d, logits, block_table, context_lens,
schedule_meta, num_phys_blocks, B, stream,
num_epi_subtiles, epi_dtype, acc_dtype, output_dtype):
"""Compile kernel using from_dlpack with dynamic shape markers."""
key = (block_kv, num_heads, head_dim, next_n, num_sms,
num_epi_subtiles, epi_dtype, acc_dtype, output_dtype)
if key in cls.kernel_cache:
return
to_cutlass = cls._TORCH_TO_CUTLASS_DTYPE
dl_args = cls._make_dlpacks(kv_flat, q_3d, w_2d, logits,
block_table, context_lens,
schedule_meta)
kernel = FP8MQALogitsDGFullKKernel(
block_kv=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],
)
compiled = cute.compile(kernel, *dl_args, num_phys_blocks, B,
stream)
cls.kernel_cache[key] = compiled

@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 = 1,
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, 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)
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
block_kv = kv_fused.shape[1]
num_phys_blocks = kv_fused.shape[0]
num_sms = _get_num_sms()

# 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 = 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]

# Create stream
torch_stream = torch.cuda.Stream()
stream = cuda.CUstream(torch_stream.cuda_stream)

# Compile if needed (uses real tensors for shape marking)
key = (block_kv, H, D, next_n, num_sms, num_epi_subtiles, epi_dtype,
acc_dtype, output_dtype)
if key not in cls.kernel_cache:
cls._compile(block_kv, H, D, next_n, num_sms, kv_flat, q_3d,
w_2d, logits, block_table, context_lens,
schedule_meta, num_phys_blocks, B, stream,
num_epi_subtiles, epi_dtype, acc_dtype,
output_dtype)
compiled = cls.kernel_cache[key]

# Wrap tensors for runtime call
dl_args = cls._make_dlpacks(kv_flat, q_3d, w_2d, logits,
block_table, context_lens,
schedule_meta)
compiled(*dl_args, num_phys_blocks, B, stream)
torch.cuda.synchronize()
return logits
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

@torch.library.custom_op("trtllm::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 = 1,
epi_dtype: torch.dtype = torch.float32,
acc_dtype: torch.dtype = torch.float32,
output_dtype: torch.dtype = torch.float32,
) -> torch.Tensor:
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)
Comment thread
limin2021 marked this conversation as resolved.

@torch.library.register_fake("trtllm::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 = 1,
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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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.

from .fp8_paged_mqa_logits import FP8MQALogitsDGFullKKernel
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Loading
Loading