已合并
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
已合并
xuyafei创建于 14 天前
xuyafei成员
14 天前

描述

一、主要解决的问题

1.1 CV tiling wrapper 重复编译

Inductor CV fusion 场景会生成主 tiling 源文件和 cube tiling wrapper 源文件。原流程在 host/device 链接链路中会随每次编译重新处理 wrapper 源文件,AutofuseDoCubeMatMulTiling 等 wrapper 实现会重复参与 host 编译,增加编译耗时。

本次将 CV tiling wrapper 编译为可复用 shared object,并按 wrapper 源码、CANN 路径、平台架构、SoC、编译选项等生成缓存 key,避免相同 wrapper 在同一缓存根目录下重复编译。

1.2 非 CV 编译链路可能被 stale shared wrapper 状态污染

shared_cv_wrapper_so 是 CV wrapper 复用流程的中间状态。如果同一个编译参数对象或流程边界中残留该字段,非 CV host/device 链接不应追加 CV wrapper so,也不应切换到 CV 专用链接库。

本次补充非 CV 边界保护,确保 shared CV wrapper 只在 CVAutofuseTilingData 相关编译中生效。

1.3 CV wrapper cache 目录清理策略

static_shape_kernel_proc 会清理临时目录。为了让 wrapper 编译产物可跨重编译阶段复用,需要保留 cv_tiling_wrapper_cache,避免静态 shape 重编译阶段误删缓存。

1.4 CV 融合位宽/精度转换

CV fusion 场景中,Cast、RoundToInt、TruncToInt、FloorToInt 等位宽转换算子需要同时处理 float16bfloat16float32int32 等不同输入/输出精度。原代码复用普通向量路径的一维 actual_size 和默认 stride,未按 CV stage 的二维 curAivM/curAivN 以及 dtype 位宽计算对齐,可能导致不同位宽转换链路中的 Cast 参数、DataCopy stride 或 RemovePad/GatherMask 处理不一致,进而影响转换精度和访存正确性。

本次补齐 CV stage 下的 dtype-aware dims/stride 生成逻辑:统一按 curAivM/curAivN 生成二维 Cast 参数,按 tensor dtype 计算 block-aligned N 方向 stride,并区分 UBFuse 与 fallback 路径处理 DataCopy。UBFuse 路径使用 dtype 对齐后的 load/store 参数并跳过不必要的 RemovePad;fallback 路径继续针对 1/2/4 字节类型生成 GatherMask 去 padding 逻辑,保证低位宽与高位宽数据在拷入、计算和拷出链路中的对齐语义一致。

1.5 本次采用的性能优化手段

  • 将 wrapper 编译从每次编译路径移到可复用缓存路径:CV fusion 的主 tiling 逻辑会随图和 shape 变化重新生成,但 cube tiling wrapper 的共享实现相对稳定。将 wrapper 源文件单独编译为 libautofuse_cv_tiling_wrapper_<hash>.so 后,相同 wrapper 输入只在首次命中时编译一次,后续 host/device 链接直接复用缓存 so,减少重复 host 编译开销。
  • 使用内容相关 cache key 保证复用正确性:缓存 key 覆盖 wrapper 源码内容、CANN 安装路径、机器架构、SoC、编译选项和 stage。只有这些会影响 wrapper ABI 或编译结果的输入完全一致时才复用缓存,避免为了性能牺牲正确性。
  • split wrapper 独立编译,减少主 tiling 重编译体量:识别 cube_kernel_tiling_wrapper.cpp 和 split 后的 *_tiling_func_BCubeKernelTilingWrapperCpp.cpp,将 wrapper 从普通 host source 列表中剥离。主 tiling 文件继续按图编译,wrapper 走共享 so 链接,降低单次 host 编译需要处理的源码规模。
  • 文件锁串行化首次编译,避免并发重复构建:多个编译任务同时命中同一 wrapper cache key 时,通过 .lock 文件保护首次构建流程。只有一个任务负责编译并原子替换最终 so,其他任务等待后复用结果,避免并发场景下重复编译和部分写入风险。
  • 清理流程保留缓存目录,支持静态 shape 重编译复用:静态 shape 重编译会清理临时目录并重新处理 device/host 产物。保留 cv_tiling_wrapper_cache 可以让首次编译生成的 wrapper so 在后续重编译阶段继续复用,避免 recompile 阶段再次构建相同 wrapper。
  • CV-only gating 避免非 CV 路径额外链接开销prepare_shared_cv_wrapperappend_shared_cv_wrapper_so 都以 is_cv_fusion_compile(args) 为边界。非 CV 编译不扫描、不编译、不链接 shared CV wrapper so,也不切换到 nnopbase 链接库,避免对普通 Autofuse 编译路径引入额外负担。

二、修改方案

2.1 抽离并复用 CV tiling wrapper 编译产物

  • 新增 CV wrapper 源文件识别,覆盖 cube_kernel_tiling_wrapper.cpp 和 split 后的 *_tiling_func_BCubeKernelTilingWrapperCpp.cpp
  • 新增 get_shared_cv_wrapper_so_path,基于 wrapper 源码内容、CANN 安装路径、平台架构、SoC、编译选项、stage 生成稳定缓存文件名。
  • 新增 ensure_shared_cv_wrapper_so,首次编译生成 libautofuse_cv_tiling_wrapper_<hash>.so,后续命中缓存直接复用。
  • 使用文件锁保护并发首次编译,避免多个编译进程同时写同一个缓存 so。
  • wrapper so 链接时使用 CV_HOST_LINK_LIBRARIES,包含 nnopbase

2.2 收敛 CV wrapper 对非 CV 流程的影响范围

  • prepare_shared_cv_wrapper 仅在 is_cv_fusion_compile(args) 为 true 时拆出 wrapper 源文件。
  • append_shared_cv_wrapper_so 仅在 CV 编译中追加 shared wrapper so。
  • 非 CV host/device 链接保持原有 object 列表和 HOST_LINK_LIBRARIES

2.3 补齐 opbase 头文件路径

  • host 编译 include 选项补充 pkg_inc 根目录和 machine-specific pkg_inc 根目录。
  • machine-specific pkg_inc/base 优先于 generic pkg_inc/base,优先使用当前架构安装态头文件。

2.4 保留 wrapper cache 目录

  • clean_before_modify 保留 cv_tiling_wrapper_cache,避免静态 shape 重编译清理缓存。

三、代码修改流程图

flowchart LR
    A[host_files 输入] ==> B{是否 CV fusion}
    B ==>|否| C[按原流程编译全部 host 源文件]
    B ==>|是| D[识别 cube wrapper 源文件]
    D ==> E{缓存 so 是否存在}
    E ==>|是| F[复用 libautofuse_cv_tiling_wrapper_<hash>.so]
    E ==>|否| G[文件锁保护首次编译 wrapper so]
    F ==> H[主 tiling object + wrapper so 链接]
    G ==> H
    C ==> I[非 CV host/device 链接不追加 wrapper so]

变更类型

关联的Issue

无。

如何测试

一、测试用例说明

1.1 Python 单元测试

  • test_compile_host_objs_skips_shared_cv_wrapper_source:验证 CV wrapper 源文件不再作为普通 host object 编译,改为生成 shared wrapper so。
  • test_compile_host_objs_skips_split_shared_cv_wrapper_source:验证 split 文件名 BCubeKernelTilingWrapperCpp 也会走 shared wrapper 复用流程。
  • test_ensure_shared_cv_wrapper_so_reuses_existing_so:验证命中缓存时不重复编译 wrapper。
  • test_ensure_shared_cv_wrapper_so_serializes_concurrent_first_compile:验证并发首次编译通过文件锁串行化,只生成一次 wrapper so。
  • test_build_device_so_ignores_shared_cv_wrapper_so_for_non_cv_compile:验证非 CV device 链接不会追加 stale shared CV wrapper so。
  • test_link_host_target_ignores_shared_cv_wrapper_so_for_non_cv_compile:验证非 CV host 链接不会追加 stale shared CV wrapper so。
  • test_clean_before_modify_keeps_shared_cv_wrapper_cache:验证静态 shape 重编译清理流程保留 wrapper cache。
  • host include 相关用例验证新增 pkg_inc 路径和 include 优先级。

1.2 C++ codegen 单元测试

  • GenerateForInductorCvFusionShouldEmitCvTilingAndCubeWrapper:验证 CV fusion 仍生成主 tiling 和 cube wrapper 文件。
  • GenerateForInductorCvFusionShouldCacheActualMatmulTilingBytes:验证 CV tiling 主流程仍保留 matmul tiling bytes 缓存逻辑。
  • CubeWrapper*:验证 wrapper 源码结构、cache key、compile info、runtime shape fallback、tiling scratch 复用等关键行为。

核对清单

其他信息

影响范围

  • 影响 Autofuse Python 编译辅助脚本中的 host 编译、host/device 链接和临时目录清理流程。
  • 影响 Inductor CV fusion codegen 生成的 cube tiling wrapper 复用方式。
  • 非 CV 编译流程保持原有 object/link library 行为,不追加 CV wrapper so。
  • 不影响 SuperKernel、Runtime、Python/C++ 对外 API、ABI 或打包布局。

注意事项

likedislike
Pull Request已成功合入, 合并人@CANN-robot
(感谢 xuyafei 的贡献)
Xxuyafei成员
14 天前 添加了label:enhancement
Xxuyafei成员
14 天前 创建了 pull request,commit 94d88c19
atomgit-bot
atomgit-bot
14 天前 评论:

变更摘要

此 PR 主要围绕 CV Fusion(Cube-Vector 融合)场景下代码生成的 dtype 感知对齐 展开,核心是引入一套基于 IsCVFusionStage / GenBlockAlignNExpr / GetCVAlignedSize 的工具函数,在多个 API 调用生成路径(Compare、Where、LogicalNot、Cast、Unary 等)中,针对 CV 融合阶段将 actual_size 替换为按 32 字节对齐边界向上对齐后的表达式。同时,对 Tiling 代码生成进行了大规模重构,将 GenTilingFuncForInductor 拆分为多个子函数,引入共享 CV wrapper SO 的编译缓存机制,并为 V35 的 Register API Call 新增 CvApi2DParams 二维参数生成逻辑。

主要改动

  • 新增 CV 融合对齐工具函数:在 api_call_utils.cpp/h 中新增 IsCVFusionStageGenBlockAlignNExprGetCVAlignedSize 等函数,根据 tensor 的 dtype 计算 32 字节对齐的 size 表达式(((n + align - 1) / align * align)),供各 API 调用生成路径复用。

  • Elewise API Call 对齐适配compare_api_call.cppwhere_api_call.cpplogical_not_api_call.cppunary_api_tmp_call.cppunary_bitwidth_change_api_call.cpp 等文件的 Generate 方法中,将原本直接使用的 x.actual_size / tpipe.tiler.ActualSize(param.cal_count) 替换为通过 GetCVAlignedSize / GenBlockAlignNExpr 计算的对齐表达式,仅在 CV 融合阶段生效。

  • Tiling 代码生成重构:在 codegen_tiling.cpp/h 中将 GenTilingFuncForInductor 拆分为 GenInductorShapeDimGenCallCubeTilingForInductorGenPlainInductorTilingTail 等子函数;cube_kernel_tiling_wrapper.h 大幅精简(+928/-1208 行);PrepareMatMulAttrsopImplMode 改为固定值 1 而非使用 cube_info.enable_hf32

  • Python 编译系统引入共享 CV Wrapper SO 缓存ascendc_compile.py 新增 is_cv_wrapper_sourceensure_shared_cv_wrapper_soprepare_shared_cv_wrapper 等函数,将 cube_kernel_tiling_wrapper.cpp 编译为独立的 .so 文件并基于内容哈希缓存至 cv_tiling_wrapper_cache 目录,支持文件锁并发的首次编译保护。

  • V35 Register API Call 新增 CV 融合 2D 参数生成:在 reg_api_call_utils.cpp/h 中新增 CvApi2DParams 结构体及 BuildCvApi2DParamsGenCvUint32DimsGenCvUint16Stride 等函数;cast_v2_api_call.cppcompare_v2_api_call.cppfloor_to_int_api_call.cppround_to_int_api_call.cpptrunc_to_int_api_call.cpp 新增 CV 融合分支,使用 2D dims/strides 替代原先的 1D 标量形式。

likedislike
atomgit-bot
atomgit-bot
14 天前 评论:

🤖 AI Code Review

⚠️ 审查未能完成

本次代码审查未能完成,可能是临时性故障。

你可以在评论区输入 /ai review 重新发起审查。若多次失败,请联系管理员并附上下方追踪 ID。

追踪 ID: task-177051-run-170137

likedislike
CANN-robotCANN-robot成员
14 天前 添加了label:cann-cla/yes
此处折叠了134条消息 查看更多
zhang_shengjie成员
12 天前 评论:

/lgtm

likedislike
CANN-robotCANN-robot成员
12 天前 添加了label:lgtm
张德鹏成员
12 天前 评论:

/approve

likedislike
CANN-robotCANN-robot成员
12 天前 添加了label:approved
CANN-robotCANN-robot成员
12 天前 合入了pull request