昇腾AI芯片与算子开发
3.5 算子工程组织与 msprof 性能分析
掌握 Ascend C 算子工程的工程化组织(op_host/op_kernel 结构、CMake、算子注册与编译),以及 msprof 性能分析工具的使用,让算子既能写出来也能调得快
Ascend C 算子工程 msprof 性能分析 算子注册
前几章我们一直在「写算子代码」。但一个能跑的算子,远不止核函数那么简单——它需要一套工程化组织:Host 侧的算子实现、Device 侧的核函数、Tiling 数据定义、算子注册与编译流程。这一章讲清楚算子工程的骨架,并介绍 msprof 这个性能分析利器。
📑 目录
- 1. 算子工程的目录结构
- 2. op_host 与 op_kernel 的分工
- 3. 算子注册与编译:从源码到 NPU 可执行文件
- 4. 用 msprof 做性能分析
- 5. 读懂一个算子 Profile 的关键指标
- 6. 性能调优的常见路线
- 总结
- 延伸阅读
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_host | CPU | 校验输入、计算 Tiling、注册算子、绑定内核 | 输入校验、Tiling 计算、REGISTER/初始化算子信息 |
| op_kernel | AI 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. 性能调优的常见路线
- 先用默认实现跑通,确认正确性(结果与 CPU 参考实现一致)。
- Profile 定位瓶颈:搬运多还是计算慢?
- Memory Bound:上双缓冲、加大块、对齐地址、减少搬运次数。
- Compute Bound:调整 Tiling(更贴合 Cube 粒度)、检查 FP32 累积是否被放大、考虑算子融合。
- 多核不充分:调整多核切分策略,让各核负载均衡。
- 回归验证:每改一处,用 msprof 对比耗时与精度,避免「改出更快但错了」。
记住:性能优化必须以数据为依据。直觉可以指引方向,但结论要交给 msprof 的数据。
总结
- 算子工程 = op_host(Tiling 计算与算子注册)+ op_kernel(核函数),Tiling 结构体是两侧的接口。
msopgen可以快速生成算子工程骨架;编译后注册进算子库即可被 aclnn/框架调用。- msprof 是昇腾的性能分析利器,对标 Nsight;核心看「搬运 vs 计算占比、多核利用率、带宽利用率」。
- 调优路线固定:跑通 → Profile → 定位瓶颈 → 针对性优化 → 回归验证。