开发工具链介绍:从编译到调试
本文介绍了昇腾CANN训练营提供的AI开发工具链,重点讲解了编译器、算子分析工具和性能分析工具的使用方法,帮助开发者提升算子开发效率。
开发工具链介绍:从编译到调试
昇腾训练营报名链接:https://www.hiascend.com/developer/activities/cann20252#cann-camp-2502-intro
训练营简介:2025年昇腾CANN训练营第二季,基于CANN开源开放全场景,推出0基础入门系列、码力全开特辑、开发者案例等专题课程,助力不同阶段开发者快速提升算子开发技能。获得Ascend C算子中级认证,即可领取精美证书,完成社区任务更有机会赢取华为手机、平板、开发板等大奖。
前言
写完算子代码只是第一步,接下来还要编译、调试、优化。刚开始我连怎么编译都不知道,报错信息看得一脸懵。后来慢慢摸索出了一套工作流程,效率提升了很多。
今天就来系统介绍CANN的开发工具链,包括编译器、调试工具、性能分析工具等。掌握这些工具,能让你的开发效率翻倍!
一、CANN工具链全景
CANN提供了一整套完整的开发工具。下图是MindStudio全流程工具链官方页面(https://www.hiascend.com/software/mindstudio):

从官方介绍可以看到,MindStudio是昇腾AI开发的端到端解决方案,提供插件化设计、可视化、自动化、智能化四大特性。
工具链完整流程:
主要工具:
- ascendc:Ascend C编译器
- msopst:算子静态分析工具
- profiling:性能分析工具
- 日志系统:运行时调试
二、编译工具:ascendc
2.1 基本用法
最简单的编译命令:
# 编译单个文件
ascendc add_kernel.cpp -o add_kernel.o
# 查看帮助
ascendc --help
2.2 常用编译选项
实际开发中,我常用的编译选项:
ascendc add_kernel.cpp -o add_kernel.o \
--ascend-arch=Ascend910B \ # 指定芯片架构
-O2 \ # 优化级别(O0/O1/O2/O3)
-g \ # 生成调试信息
-std=c++17 \ # C++标准
-I./include \ # 头文件路径
-D DEBUG # 定义宏
各选项说明:
| 选项 | 说明 | 推荐值 |
|---|---|---|
--ascend-arch |
目标芯片 | Ascend910/910B/310P |
-O |
优化级别 | 开发用O0,发布用O2 |
-g |
调试信息 | 调试时加上 |
-std |
C++标准 | c++14或c++17 |
-w |
禁用警告 | 不推荐 |
2.3 实际项目的编译
通常会用Makefile或CMakeLists.txt来管理编译:
Makefile示例:
# 编译器
CXX = ascendc
# 编译选项
CXXFLAGS = -O2 -std=c++17 -g
CXXFLAGS += --ascend-arch=Ascend910B
# 头文件路径
INCLUDES = -I$(ASCEND_TOOLKIT_HOME)/include
# 目标文件
TARGET = add_custom.so
# 源文件
SRCS = add_kernel.cpp host_code.cpp
# 编译
all: $(TARGET)
$(TARGET): $(SRCS)
\t$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@
clean:
\trm -f $(TARGET) *.o
.PHONY: all clean
使用:
# 编译
make
# 清理
make clean
我一般用Makefile,因为比较简单直观。大项目可以考虑CMake。
2.4 编译错误排查
分享几个我遇到过的编译错误:
错误1:找不到头文件
error: kernel_operator.h: No such file or directory
解决:
# 检查环境变量
echo $ASCEND_TOOLKIT_HOME
# 设置环境变量(如果没有)
source /usr/local/Ascend/ascend-toolkit/set_env.sh
# 编译时指定路径
ascendc -I$ASCEND_TOOLKIT_HOME/include add_kernel.cpp
错误2:语法错误
error: '__aicore__' attribute only applies to function types
这通常是把__aicore__用错地方了:
// ❌ 错误
class __aicore__ MyClass {};
// ✅ 正确
class MyClass {
__aicore__ void MyFunc() {}
};
错误3:未定义的引用
undefined reference to 'DataCopy'
通常是链接问题,需要添加库文件:
ascendc add_kernel.cpp -o add_kernel.o \
-L$ASCEND_TOOLKIT_HOME/lib64 \
-lascendcl
三、算子分析工具:msopst
3.1 msopst是什么?
msopst(MindSpore Operator Static Tool)用于分析算子的中间表示和性能预估。
主要功能:
- 查看算子的IR(Intermediate Representation)
- 分析指令序列
- 预估性能瓶颈
- 检查内存使用
3.2 基本用法
# 分析算子
msopst --mode=1 --input=add_kernel.o --output=add_kernel.json
# mode说明:
# mode=1: 生成IR和指令分析
# mode=2: 只生成IR
生成的JSON文件包含详细的算子信息:
{
"op_name": "AddCustom",
"input_desc": [...],
"output_desc": [...],
"attr": {...},
"task_info": {
"block_dim": 4,
"workspace_size": 1024,
...
},
"ir_info": {
"instructions": [
{"type": "vector_add", "latency": 10},
...
]
}
}
3.3 分析IR
打开JSON文件,重点看几个字段:
{
"instructions": [
{
"idx": 0,
"type": "data_copy",
"src": "GM",
"dst": "UB",
"size": 512,
"latency": 50 // 延迟(周期数)
},
{
"idx": 1,
"type": "vector_add",
"operands": ["UB0", "UB1", "UB2"],
"latency": 10
},
...
]
}
从中可以看出:
- 每条指令的类型
- 操作的内存位置
- 预估的延迟
我的使用经验:
当算子性能不符合预期时,我会用msopst分析:
- 看看是不是数据搬运太多(data_copy指令太多)
- 看看是不是有标量操作(应该改成向量操作)
- 看看内存使用是否超标
3.4 实战案例
有一次我写的Add算子性能很差,用msopst一分析,发现生成了大量的标量load/store指令:
{
"instructions": [
{"type": "scalar_load", "latency": 5}, // 标量操作!
{"type": "scalar_load", "latency": 5},
{"type": "scalar_add", "latency": 1},
{"type": "scalar_store", "latency": 5},
... // 重复256次
]
}
原因是我写成了标量循环:
// ❌ 错误:标量循环
for (int i = 0; i < TILE_SIZE; i++) {
z[i] = x[i] + y[i];
}
改成向量操作后:
// ✅ 正确:向量操作
Add(z, x, y, TILE_SIZE);
再用msopst分析,指令数量从256条变成了16条(FP16向量宽度为16)!性能提升了20倍。
四、性能分析工具:profiling
4.1 启用profiling
在代码中启用性能分析:
#include "acl/acl_prof.h"
// 初始化profiling
aclprofConfig* profilerConfig = aclprofCreateConfig(
nullptr, // profiler数据目录
0, // 时间段(0表示全程)
0,
ACL_AICORE_ARITHMETIC_UTILIZATION | // 计算利用率
ACL_AICORE_PIPE_UTILIZATION | // 流水线利用率
ACL_AICORE_MEMORY_BANDWIDTH // 内存带宽
);
aclprofInit("/home/user/profiling_data", sizeof("/home/user/profiling_data"));
aclprofStart(profilerConfig);
// 运行算子
RunKernel(...);
// 停止profiling
aclprofStop(profilerConfig);
aclprofDestroyConfig(profilerConfig);
aclprofFinalize();
4.2 查看profiling结果
执行后会生成profiling数据文件,用可视化工具查看:
# 使用MindStudio的Profiler工具打开
# 或者用命令行工具解析
# 生成的文件:
profiling_data/
├── host_info.json
├── op_summary.csv
├── op_statistic.csv
└── timeline.json
4.3 关键性能指标
重点关注这几个指标:
1. AI Core利用率
AI Core Utilization: 85%
- >80%:很好,充分利用了硬件
- 50%-80%:一般,还有优化空间
- <50%:较差,可能存在瓶颈
2. 内存带宽利用率
Memory Bandwidth Utilization: 60%
- 如果很低,说明计算密集,瓶颈在计算
- 如果很高(>90%),说明访存密集,瓶颈在内存
3. 算子执行时间
Kernel Execution Time: 125 us
对比理论值,看是否符合预期。
4. 流水线效率
Pipeline Efficiency: 92%
双缓冲做得好,这个值应该很高。
4.4 性能优化方向
根据profiling结果确定优化方向:
五、日志与调试
5.1 CANN日志系统
CANN的日志保存在:
# 默认日志路径
/var/log/npu/
# 主要日志文件
/var/log/npu/slog/host-0/ # Host日志
/var/log/npu/slog/device-0/ # Device日志
查看日志:
# 查看最新的错误日志
tail -f /var/log/npu/slog/host-0/host-log.txt
# 搜索错误信息
grep "ERROR" /var/log/npu/slog/host-0/host-log.txt
5.2 设置日志级别
# 设置环境变量
export ASCEND_GLOBAL_LOG_LEVEL=0 # 0:DEBUG, 1:INFO, 2:WARNING, 3:ERROR
# 在代码中设置
aclrtSetLogLevel(ACL_DEBUG);
5.3 常见错误日志
错误1:内存不足
[ERROR] RUNTIME(21131): Malloc memory failed, size=1048576
解决:减小Tile大小或batch size
错误2:算子执行失败
[ERROR] KERNEL(30001): Kernel execution failed, error code=507033
错误码507033通常是内存访问越界,检查:
- 数据索引是否正确
- Tile大小是否超出Buffer容量
错误3:数据类型不匹配
[ERROR] TYPE_MISMATCH: Expected FP16, got FP32
检查输入输出的数据类型定义。
5.4 我的调试技巧
技巧1:二分法定位问题
// 在关键位置打日志
void Process() {
printf("Step 1: CopyIn\n");
CopyIn();
printf("Step 2: Compute\n");
Compute();
printf("Step 3: CopyOut\n");
CopyOut();
printf("All done!\n");
}
看看在哪一步出错,缩小排查范围。
技巧2:对比CPU结果
// 实现CPU版本作为参考
void ReferenceAdd(float* x, float* y, float* z, int n) {
for (int i = 0; i < n; i++) {
z[i] = x[i] + y[i];
}
}
// 对比结果
float maxDiff = 0;
for (int i = 0; i < n; i++) {
float diff = fabs(npu_result[i] - cpu_result[i]);
if (diff > maxDiff) {
maxDiff = diff;
printf("Max diff at index %d: %f\n", i, diff);
}
}
技巧3:打印中间结果
// 把中间Tensor拷回CPU打印
half* tempBuffer = new half[TILE_SIZE];
DataCopy(tempBuffer, localTensor, TILE_SIZE);
printf("First 10 elements:\n");
for (int i = 0; i < 10; i++) {
printf("%f ", (float)tempBuffer[i]);
}
printf("\n");
delete[] tempBuffer;
六、IDE工具:MindStudio
6.1 MindStudio简介
MindStudio是华为官方的集成开发环境,功能很强大:
- 代码编辑和高亮
- 自动补全
- 可视化调试
- 性能分析集成
- 算子测试工具
6.2 创建算子项目
在MindStudio中:
- 点击 File -> New -> Ascend C Project
- 选择算子类型(Element-wise/Reduce等)
- 填写算子名称
- 自动生成模板代码
非常方便!生成的代码框架都是标准的,可以直接在上面改。
6.3 可视化调试
MindStudio支持断点调试:
// 在关键位置设置断点
__aicore__ inline void Compute() {
// 断点:查看localX的值
LocalTensor<half> localX = queueX.DeQue<half>();
// 断点:查看计算结果
Add(localZ, localX, localY, TILE_SIZE);
}
调试时可以:
- 查看变量值
- 单步执行
- 查看内存布局
不过我个人还是习惯用日志调试,因为断点调试有时候会改变执行时序。
6.4 MindStudio vs VS Code
我两个都用过,对比一下:
| 功能 | MindStudio | VS Code |
|---|---|---|
| 专业性 | 专为CANN设计 | 通用编辑器 |
| 上手难度 | 稍复杂 | 简单 |
| 代码补全 | 很好 | 需要配置 |
| 调试功能 | 强大 | 基础 |
| 性能分析 | 集成 | 需要外部工具 |
| 资源占用 | 较大 | 较小 |
我的选择:
- 学习阶段:用MindStudio,功能全面
- 熟练之后:用VS Code,更轻量灵活
七、其他实用工具
7.1 npu-smi:设备管理
# 查看NPU设备信息
npu-smi info
# 查看实时利用率
watch -n 1 npu-smi info
# 查看错误计数
npu-smi info -t err
7.2 模拟器工具
没有NPU硬件时,可以用模拟器:
# 设置模拟器模式
export ASCEND_DEVICE_ID=0
export ASCEND_SLOG_PRINT_TO_STDOUT=1
# 运行代码
./my_program
模拟器的限制:
- ✅ 可以验证功能正确性
- ✅ 可以调试代码逻辑
- ❌ 性能数据不准确
- ❌ 不支持所有硬件特性
7.3 算子单测工具
CANN提供了算子单测框架:
import numpy as np
from ais_bench.infer.interface import InferSession
# 加载算子
session = InferSession(device_id=0)
session.load_model("add_custom.om")
# 准备输入
x = np.random.rand(1000).astype(np.float16)
y = np.random.rand(1000).astype(np.float16)
# 执行
outputs = session.infer([x, y])
# 验证结果
expected = x + y
assert np.allclose(outputs[0], expected, rtol=1e-2)
八、开发流程最佳实践
总结一下我的开发流程:
具体步骤:
- 编写代码:实现基本功能
- 本地编译:用Makefile或MindStudio
- 功能测试:对比CPU结果,确保正确性
- 调试:出问题查日志,必要时用gdb
- 性能测试:用profiling工具测性能
- 性能优化:根据profiling结果优化
- 回归测试:确保优化后功能仍正确
九、总结
CANN开发工具链:
| 工具 | 用途 | 使用场景 |
|---|---|---|
| ascendc | 编译 | 每次代码改动后 |
| msopst | IR分析 | 性能调优阶段 |
| profiling | 性能分析 | 性能调优阶段 |
| 日志系统 | 调试 | 出现错误时 |
| MindStudio | IDE | 开发全流程 |
| npu-smi | 设备管理 | 查看硬件状态 |
我的建议:
- 入门阶段:重点掌握编译和日志调试
- 进阶阶段:学会用msopst和profiling优化性能
- 熟练阶段:建立自己的开发流程和工具脚本
工具只是手段,关键还是要多写代码、多调试、多思考。遇到问题不要慌,一步步排查,总能解决!
下一篇文章,我们终于要动手写第一个真正的算子了——Hello World算子!
相关文章推荐:
- 上一篇:CANN算子开发核心概念全解析
- 下一篇:第一个Hello World算子开发实战
工具下载:
- CANN Toolkit:https://www.hiascend.com/software/cann
- MindStudio:https://www.hiascend.com/software/mindstudio
有问题欢迎留言,点赞收藏支持一下~
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)