Prhub

#48582 [M3] Improve indexer for long-context decode (sm100)

原始 PR 作者 gau-nernst 合并时间 2026-07-17 09:12 文件变更 7 提交数 4 评论 0 代码增减 +756 / -63

执行摘要

为 M3 长上下文 decode 添加 CuteDSL indexer 内核,支持 FP8 和 BF16

现有的 Triton indexer 在非均匀上下文长度时负载均衡不佳,因为 TARGET_GRID 调优偏向均匀上下文。新的 CuteDSL 使用 TMA + mma.sync,通过高占用率和硬件调度更容易达到内存带宽饱和,尤其在上下文不均衡时表现更稳定。此外需要支持 BF16/FP8 缓存和 speculative decoding。

该 PR 值得精读,尤其是 CuteDSL kernel 设计思路(TMA+mma.sync 对比 tcgen05 的权衡)以及 fallback 策略。合并后无已知回归,但建议关注后续其他 CuteDSL 模块是否顺利迁移至 mma_sync 接口。

讨论亮点

作者在 PR body 中解释了设计决策:选择 TMA + mma.sync 而非 tcgen05 软件流水线,因为该得分 GEMM 的 N 维度很小(每请求一个 tile),高 CTA 占用率结合硬件调度更容易饱和内存带宽,且对上下文长度不均衡更鲁棒。另外 speculative decoding 支持的限制条件 (1+num_spec_tokens)*num_idx_heads <= 32 是由于 CuteDSL kernel 的 Q tile 硬编码为最多 32 列(每个 warp 元素一个),当条件不满足时自动回退到 Triton 保证正确性。

实现拆解

  1. 新增 CuteDSL decode score kernelvllm/models/minimax_m3/nvidia/ops/index_decode_score.py):核心类 IndexDecodeScoreKernel,通过 @cute.jit 编译为 CUDA kernel。使用 TMA 加载 Q 和 K 数据,然后通过 mma_sync 计算 block scores。支持 BF16 和 FP8 两种 cache 格式,FP8 时通过 _fp8_to_f16_mma_fragments 转为 FP16 后再做 mma。内核设计采用高 CTA 占用率而非 tcgen05 流水线,以适应上下文长度不均衡。

  2. 重构 CuteDSL 基础设施vllm/cute_utils/__init__.py):将硬编码 bf16mma_bf16 泛化为 mma_sync,通过类型映射 _CUTE_TO_PTX_DTYPE 自动生成正确的 PTX 指令后缀(如 e4m3bf16f16)。同时添加 _TORCH_TO_CUTE_DTYPE 映射、Float8E4M3FN 导入,以及处理 TensorSSA 输入时的 materialize 逻辑。

  3. 集成与 fallbackvllm/models/minimax_m3/nvidia/indexer_msa.py):在 MiniMaxM3IndexerMSAImpl.forward 中,当 num_index_heads * max_decode_query_len <= 32 时调用 CuteDSL kernel(minimax_m3_index_decode_score_cutedsl),否则回退到原有 Triton kernel(minimax_m3_index_decode_score),保证兼容性。

  4. 添加 FP8→FP16 转换工具vllm/cute_utils/cvt.py):新增 fp8x4_to_fp16x4 函数,使用 PTX 内联汇编 cvt.rn.f16x2.e4m3x2 指令批量转换,供 FP8 cache 场景使用。

  5. 更新下游 kernel 适配vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/kernel_kkt_inv_uw.py):将旧 mma_bf16 调用替换为 mma_sync,并调整寄存器布局(将 mma_B_bf16M_bf16 改为 rank-2 视图)以匹配新接口期望。

  6. 测试覆盖tests/kernels/attention/test_minimax_m3.py):添加 _reference_decode_index_score 参考实现(纯 PyTorch),扩展 test_msa_indexer_impl_matches_triton 参数化 index_dtype(BF16/FP8),并新增 test_decode_index_score_cutedsl_correctness 直接验证 CuteDSL kernel 输出与参考实现的一致性。

文件 模块 状态 重要度
vllm/models/minimax_m3/nvidia/ops/index_decode_score.py M3 模型 added 8.15
vllm/cute_utils/__init__.py CuteDSL 工具 modified 7.42
tests/kernels/attention/test_minimax_m3.py M3 测试 modified 6.77
vllm/models/minimax_m3/nvidia/indexer_msa.py M3 模型 modified 6.5
vllm/cute_utils/cvt.py CuteDSL 工具 modified 6.45
vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/kernel_kkt_inv_uw.py GDN 模块 modified 5.18
vllm/models/minimax_m3/nvidia/ops/__init__.py M3 模型 added 3.81

关键符号

minimax_m3_index_decode_score_cutedsl IndexDecodeScoreKernel.__call__ IndexDecodeScoreKernel.compile mma_sync _fp8_to_f16_mma_fragments fp8x4_to_fp16x4 _reference_decode_index_score test_decode_index_score_cutedsl_correctness test_msa_indexer_impl_matches_triton

关键源码片段

vllm/models/minimax_m3/nvidia/ops/index_decode_score.py core-logic

核心 CuteDSL kernel 实现,新增 IndexDecodeScoreKernel 类和封装函数,包含 TMA 加载、mma.sync 计算、FP8 支持等完整逻辑。

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project@cute.jit
def _fp8_to_f16_mma_fragments(src: cute.Tensor):
    """
    将 FP8 寄存器片段转换为两路 FP16 片段,供 mma.sync 使用。
    ldmatrix 从共享内存加载 FP8 到寄存器时,每个 32b 寄存器包含 4 个 FP8 值。
    我们先将 4 个 FP8 转换为 4 个 FP16,然后拆分为较低的两个和较高的两个,
    对应两个 K 维度 MMA 片段。
    """
    src_elems = cute.size(src)
    src_u32 = cute.recast_tensor(src, Uint32)
    src_f16 = cute.make_rmem_tensor(src_elems, Float16)
    src_f16_u32 = cute.recast_tensor(src_f16, Uint32)
​
    # 每 4 个 FP8 元素(一个 b32)用 cvt 指令整体转换为两个 b32 的 FP16。
    for i in cutlass.range_constexpr(src_elems // 4):
        converted = cvt.fp8x4_to_fp16x4(src_u32[i])
        src_f16_u32[i * 2] = converted[0]
        src_f16_u32[i * 2 + 1] = converted[1]
​
    lower = cute.make_rmem_tensor(src_elems // 2, Float16)
    upper = cute.make_rmem_tensor(src_elems // 2, Float16)
​
    # 将每 4 个 FP16 中的前两个和后两个分别放入 lower 和 upper。
    for i in cutlass.range_constexpr(src_elems // 2):
        lower[i] = src_f16[(i // 2) * 4 + i % 2]
        upper[i] = src_f16[(i // 2) * 4 + 2 + i % 2]
    return lower, upper
​
​
class IndexDecodeScoreKernel:
    """
    基于 CuteDSL 的 index decode score kernel,使用 TMA + mma.sync 计算 block scores。
    设计选择:高 CTA 占用率而非 tcgen05 流水线,因为得分 GEMM 的 N 维度很小,
    更容易通过硬件调度饱和内存带宽,尤其适合上下文长度不均衡的场景。
    """
    BLOCK_K = 128
    BAR_MMA = 1
    num_stages = 2
​
    def __init__(
        self,
        dtype: type[cutlass.Numeric],
        num_heads: int,
        max_decode_query_len: int,
        split_k: int,
        head_dim: int = 128,
    ):
        self.dtype = dtype
        self.num_heads = num_heads
        self.max_decode_query_len = max_decode_query_len
        self.split_k = split_k
        self.head_dim = head_dim
​
    @cute.jit
    def __call__(
        self,
        gQ: cute.Tensor,
        gK_cache: cute.Tensor,
        block_table: cute.Tensor,
        score: cute.Tensor,
        seq_lens: cute.Tensor,
        stream: CUstream,
    ):
        # ... ( 核心 TMA 加载和 mma.sync 计算循环 )
        # 详细代码参见完整文件

评论区精华

TMA+mma.sync 与 tcgen05 的设计选择 设计

作者在 PR body 中说明选择 TMA + mma.sync 而非 tcgen05 的原因:该得分 GEMM 的 N 维度很小,高 CTA 占用率配合硬件调度更容易饱和内存带宽,且对上下文长度不均衡更稳健。tcgen05 软件流水线在 context imbalance 时效率下降。

结论:采用 TMA + mma.sync 设计,在 SM100 上验证性能优于 Triton 和 tcgen05 方案。 · 已解决

Speculative decoding 支持的限制条件 性能

CuteDSL kernel 的 Q tile 大小硬编码限制为最多 32 列(对应 warp 元素),因此要求 (1+num_spec_tokens)*num_idx_heads <= 32。当不满足时自动回退到 Triton 实现。

结论:接受此限制并实现自动 fallback,确保功能正确。 · 已解决

风险与影响

  1. 架构兼容性:新 kernel 仅针对 SM100(Blackwell)验证,其他架构上的行为未定义。但 fallback 到 Triton 的机制保障了正确性,只是可能达不到预期性能。
  2. FP8 精度风险_fp8_to_f16_mma_fragments 将 FP8 缓存转为 FP16 再做 mma,引入了转换精度损失,与直接 Triton FP8 路径可能存在微小差异。测试已覆盖两种 dtype 的一致性检查。
  3. 基础设施影响mma_sync 替换 mma_bf16 需要同步所有使用旧接口的 kernel,若存在遗漏可能导致编译错误。已确认 gdn_chunk_cutedsl 已更新,但其他潜在使用者(如 Inkling 系列)可能需要跟进。
  4. 性能回退边缘情况:条件 num_idx_heads * max_decode_query_len <= 32 在 large speculative window 时可能频繁 fallback,导致收益降低。

对用户:使用 Minimax M3 模型在 SM100 GPU 上进行长上下文 decode 时,吞吐和延迟得到显著改善(微基准显示比 Triton-4096 和 Triton-512 均有优势)。对系统:引入 CuteDSL 编译依赖,每次首次运行或 kernel 变化时会触发 CUDA 编译,增加启动时间。对团队:CuteDSL 基础设施的统一(mma_sync)为未来多精度 kernel 开发奠定基础。

新 kernel 仅 SM100 验证 条件 fallback 可能收益受限 mma_sync 重命名可能遗漏其他使用者 FP8 转换精度差异

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论