跳到主要内容
昇腾AI芯片与算子开发

3.5 算子工程组织与 msprof 性能分析

掌握 Ascend C 算子工程的工程化组织(op_host/op_kernel 结构、CMake、算子注册与编译),以及 msprof 性能分析工具的使用,让算子既能写出来也能调得快

Ascend C 算子工程 msprof 性能分析 算子注册

前几章我们一直在「写算子代码」。但一个能跑的算子,远不止核函数那么简单——它需要一套工程化组织:Host 侧的算子实现、Device 侧的核函数、Tiling 数据定义、算子注册与编译流程。这一章讲清楚算子工程的骨架,并介绍 msprof 这个性能分析利器。

📑 目录


1. 算子工程的目录结构

一个典型的 Ascend C 算子工程长这样:

AddOperator/
├── CMakeLists.txt            # 编译配置
├── op_host/                  # Host 侧代码(在 CPU 上运行)
│   ├── add_tiling.h          # Tiling 参数结构定义
│   ├── add_tiling.cpp        # Tiling 参数计算实现
│   └── add.cpp               # 算子主体(含算子注册)
└── op_kernel/                # Device 侧代码(在 AI Core 上运行)
    ├── add.cpp               # 核函数实现
    └── add_tiling.h          # Tiling 参数结构(Host/Device 共享定义)

关键理解:

  • op_host 与 op_kernel 是两个编译单元,最终编译成不同形态:Host 代码编译成算子库插件(.so),Device 代码编译成 NPU 上的可执行段。
  • Tiling 结构体是两边的”信使”:Host 侧填好参数,Device 侧按参数执行,因此这个结构体的定义必须两侧一致。
  • 工程根目录的 CMakeLists.txt 负责组织两个子目录的构建。

2. op_host 与 op_kernel 的分工

部分运行位置职责典型内容
op_hostCPU校验输入、计算 Tiling、注册算子、绑定内核输入校验、Tiling 计算、REGISTER/初始化算子信息
op_kernelAI Core真正的计算核函数、数据搬运、矢量/矩阵计算

op_host 的关键产出是 Tiling 参数:它决定 Device 侧「每块搬多少、循环几轮、多核怎么切」。昇腾算子的性能优劣,一半在 Tiling 参数设计。

典型的 Host 侧流程:

// 伪代码:Host 侧算子实现
// 1. 解析输入张量(形状、数据类型)
// 2. 校验合法性(维度、类型是否支持)
// 3. 计算 Tiling 参数(基于 UB 容量与张量形状)
// 4. 填写 TilingData 结构体
// 5. 获取/创建 stream,下发核函数(ACLRT_LAUNCH_KERNEL)

3. 算子注册与编译:从源码到 NPU 可执行文件

算子要能被 aclnn / 框架调用,必须完成注册:

  • 算子信息注册:声明算子的输入输出、属性、支持的数据类型与形状范围(类似 CUDA 算子的 metadata)。
  • 算子实现绑定:把算子名与对应的 Host 实现 + 核函数绑定,运行时才能路由到正确实现。
  • 编译:通过 CANN 的编译工具链(如 msopgen 生成工程骨架、CMake 构建),生成算子包(.so),放入 CANN 算子库路径后即可被调用。

msopgen 是昇腾官方提供的一个算子工程生成器,可以基于算子原型自动生成目录骨架与模板代码:

# 根据算子定义生成工程骨架(示意)
msopgen gen -i add.json -c aicore -out ./AddOperator

4. 用 msprof 做性能分析

算子写出来只是第一步,跑得快才是目标。昇腾的性能分析工具是 msprof(对标 NVIDIA 的 Nsight Systems/Compute):

# 在应用运行期间采集性能数据
msprof --output=/tmp/prof_result python train.py

# 或在算子测试场景下直接指定算子执行分析

msprof 能输出:

  • 时间轴视图:各算子在 Host/Device 上的起止时间,定位「哪里在等」。
  • 算子级统计:每个算子的耗时、搬运 vs 计算占比。
  • 硬件事件:AI Core 利用率、带宽利用率、Cache 命中率等。

使用姿势:先用 msprof 跑一遍整体应用,找到耗时的热点算子;再对热点算子做单算子 Profile,观察搬运/计算占比,决定优化方向。

5. 读懂一个算子 Profile 的关键指标

拿到 Profile 报告后,重点看几个数字:

指标含义怎么用
算子耗时单个算子整体执行时间找热点、做回归对比
搬运时间占比DataCopy 花费时间 / 总时间高 → 双缓冲、减少搬运
计算时间占比计算单元忙碌时间 / 总时间高 → 已逼近算力上限
AI Core 利用率多核并行是否充分低 → 检查多核切分
带宽利用率HBM 实际/峰值带宽低 → 检查搬运对齐与块大小

判断口诀:

  • 搬运占比高 → 这是个 Memory Bound 算子 → 优化搬运。
  • 计算占比高 → 这是个 Compute Bound 算子 → 优化计算本身或换更高性能实现。
  • 利用率低 → 多核切分或流水线没做好。

6. 性能调优的常见路线

  1. 先用默认实现跑通,确认正确性(结果与 CPU 参考实现一致)。
  2. Profile 定位瓶颈:搬运多还是计算慢?
  3. Memory Bound:上双缓冲、加大块、对齐地址、减少搬运次数。
  4. Compute Bound:调整 Tiling(更贴合 Cube 粒度)、检查 FP32 累积是否被放大、考虑算子融合。
  5. 多核不充分:调整多核切分策略,让各核负载均衡。
  6. 回归验证:每改一处,用 msprof 对比耗时与精度,避免「改出更快但错了」。

记住:性能优化必须以数据为依据。直觉可以指引方向,但结论要交给 msprof 的数据。

总结

  • 算子工程 = op_host(Tiling 计算与算子注册)+ op_kernel(核函数),Tiling 结构体是两侧的接口。
  • msopgen 可以快速生成算子工程骨架;编译后注册进算子库即可被 aclnn/框架调用。
  • msprof 是昇腾的性能分析利器,对标 Nsight;核心看「搬运 vs 计算占比、多核利用率、带宽利用率」。
  • 调优路线固定:跑通 → Profile → 定位瓶颈 → 针对性优化 → 回归验证。

延伸阅读