Prhub

#53004 [ROCm][CI] Speed up `test_rocm_aiter_qk_norm_rope_kvcache_fusion`

原始 PR 作者 micah-wil 合并时间 2026-08-20 10:20 文件变更 1 提交数 5 评论 6 代码增减 +30 / -20

执行摘要

裁剪 ROCm 融合测试参数化,耗时从 2.5 小时降至 6 分钟

原测试因 1440 个参数化组合耗时 2.5 小时以上,成为 ROCm CI 的瓶颈。PR body 说明:use_shuffle_kv_layout="1" 的所有用例实际都被跳过,保留该维度没有意义;rms_norm_eps=1e-51e-6 的差异不带来实际收益;num_tokens 只需覆盖 5(小请求)与 2048(大序列)两个边界。同时,AITER < 0.1.20 时融合内核存在已知 abort,需要版本门槛避免 CI 反复失败。

值得一读,尤其是大型参数化测试的加速思路:裁剪冗余参数、用模块级清理替代逐用例清理、收集期跳过与版本门槛。不过要关注覆盖度变化,未来若要新增参数组合应充分评估必要性。

讨论亮点

本 PR 来自 fork,claude[bot] 自动审查被禁用,未产生实际代码评审建议。维护者 AndreasKaratzas 在最后直接批准(LGTM)。PR body 是主要设计说明,作者对参数裁剪理由的逐条解释(跳过集合、无用 epsilon、边界 token 数)是整个变更的核心依据。无未解决的讨论线程。

实现拆解

  1. 参数化裁剪:移除 use_shuffle_kv_layout 参数(含函数签名中的对应入参与 skip 分支);num_tokens[5, 16, 2048] 收敛为 [5, 2048]rms_norm_eps[1e-5, 1e-6] 收敛为 [1e-6]。组合数从 1440 降至 480。
  2. 清理策略变更:新增 pytestmark = pytest.mark.skip_global_cleanup 跳过逐用例的全局清理;新增模块级 autouse fixture module_global_cleanup,只在模块结束时统一调用 cleanup_dist_env_and_memory(),避免每个用例重复初始化/销毁分布式环境带来的开销。
  3. 收集期跳过与版本门槛:在模块加载时若 is_aiter_found_and_supported() 为假,则用 pytest.skip(allow_module_level=True) 直接跳过整个模块;skipif 条件从仅检查 AITER 存在改为 Version(version("amd_aiter")) >= Version("0.1.20"),并给出旧版本内核 abort 的原因说明。
  4. 配套导入:新增 importlib.metadata.versionpackaging.version.Version 用于版本比较;测试函数签名中移除 use_shuffle_kv_layout 参数并删除对应 skip 分支。
文件 模块 状态 重要度
tests/compile/passes/test_rocm_aiter_qk_norm_rope_kvcache_fusion.py 编译测试 modified 5.2

关键符号

module_global_cleanup test_qk_norm_rope_kvcache_fusion _run_qk_norm_rope_kvcache_fusion_test

关键源码片段

tests/compile/passes/test_rocm_aiter_qk_norm_rope_kvcache_fusion.py test-coverage

唯一变更文件。通过参数化裁剪(1440 → 480)、模块级清理与 AITER 版本门槛,将该测试运行时间从 2.5 小时以上降至约 6 分钟,同时保持核心融合路径覆盖。

# tests/compile/passes/test_rocm_aiter_qk_norm_rope_kvcache_fusion.py
# 本文件验证 QkNormRopeKvCacheFusionPass 在 ROCm AITER 上的融合正确性。
# 本次变更的三大提速点:参数化裁剪、模块级清理、AITER 版本门槛。import os
from importlib.metadata import versionimport pytest
import torch
from packaging.version import Versionimport vllm.config
# ... 其余导入省略 ...# 提速点 1:标记整个模块跳过逐用例的全局清理(原实现每个用例都清理分布式环境)
pytestmark = pytest.mark.skip_global_cleanup# 提速点 2:AITER 不可用时,在收集阶段直接跳过整个模块,避免无意义的用例执行
if not is_aiter_found_and_supported():
    pytest.skip(
        "ROCm with supported AITER is required",
        allow_module_level=True,
    )# 提速点 3:模块级 autouse fixture,只在模块结束时统一释放分布式环境与显存
@pytest.fixture(scope="module", autouse=True)
def module_global_cleanup():
    from vllm.distributed import cleanup_dist_env_and_memory
    yield
    cleanup_dist_env_and_memory()# ... 模型定义与辅助函数省略 ...# 融合配置仅保留 5 种真实生效的 head 组合(覆盖 full/partial rotary 与 neox 变体)
_FUSION_CONFIGS = [
    pytest.param(64, 8, 64, 64, True, id="full-neox"),
    pytest.param(64, 8, 64, 64, False, id="full-non_neox"),
    pytest.param(32, 8, 128, 64, True, id="glm4_moe"),
    pytest.param(32, 2, 128, 64, False, id="glm4_dense"),
    pytest.param(16, 2, 64, 32, True, id="partial_small_head"),
]@pytest.mark.parametrize(
    "num_heads, num_kv_heads, head_size, rotary_dim, is_neox",
    _FUSION_CONFIGS,
)
@pytest.mark.parametrize(
    "attn_backend",
    [
        AttentionBackendEnum.ROCM_AITER_UNIFIED_ATTN,
        AttentionBackendEnum.ROCM_AITER_FA,
    ],
)
# 参数裁剪:num_tokens 只保留 5 和 2048,去除中间值 16,减少 1/3 组合
@pytest.mark.parametrize("num_tokens", [5, 2048])
@pytest.mark.parametrize("enable_aiter_triton_rope", [True, False])
@pytest.mark.parametrize("block_size", [16, 32, 64])
@pytest.mark.parametrize("kv_cache_dtype", ["auto", "fp8"])
# 参数裁剪:rms_norm_eps 只保留 1e-6,1e-5 与 1e-6 无实用差异
@pytest.mark.parametrize("rms_norm_eps", [1e-6])
@pytest.mark.parametrize("custom_op", ["+rotary_embedding", "+rms_norm"])# AITER < 0.1.20 的 fused_qk_norm_rope_cache 内核会因块内 KV 缓存不连续而 abort,
# 因此把 skipif 条件从仅检查 AITER 存在提升为版本门槛。
@pytest.mark.skipif(
    not Version(version("amd_aiter")) >= Version("0.1.20"),
    reason="Requires AITER >= 0.1.20; older kernels abort on fused_qk_norm_rope_cache",
)
def test_qk_norm_rope_kvcache_fusion(...):
    # ... 用例主体省略 ...
    pass

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  • 覆盖度小幅下调:移除 num_tokens=16rms_norm_eps=1e-5 以及 use_shuffle_kv_layout=1 组合。前两者对融合 pass 的行为影响很小,且 use_shuffle_kv_layout=1 原本就全部跳过,风险可接受。
  • 清理时机变化:从逐用例清理改为模块级一次性清理,若未来测试中新增跨用例状态污染,可能更难定位。当前该文件仅此一个测试函数,风险有限。
  • 版本判断强依赖version("amd_aiter") 依赖包名与 packaging 解析,若某环境包名注册不同,会抛 PackageNotFoundError。好在 is_aiter_found_and_supported() 已先行拦截未安装场景,但已安装但注册名不同时仍需关注。
  • 收集期跳过易被忽略:模块级 pytest.skip 会导致测试在 CI 报告中直接消失,若环境配置变化导致 AITER 不可用,测试缺失可能不易被察觉。

对最终用户无任何影响(纯测试变更)。对 ROCm CI 是显著正向影响:单测试从 2.5 小时降至约 6 分钟,能大幅缩短 AMD 构建队列的反馈周期。对维护该测试的工程师,需要理解参数裁剪的背景与版本门槛的含义,否则后续可能误增冗余参数。

覆盖度削减 清理时机变更 依赖版本判断 收集期模块跳过

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论