写给前端的 CAAN-profiling-suite:昇腾性能分析套件到底是啥?
写给前端的 CAAN-profiling-suite:昇腾性能分析套件到底是啥?
·
写给前端的 CAAN-profiling-suite:昇腾性能分析套件到底是啥?
上周做模型优化,老板问我:“你的模型在 NPU 上跑得慢,到底慢在哪里?” 我愣住了——不知道啊。
好问题。今天一次说清楚。
profiling-suite 是啥?
profiling-suite 是昇腾的性能分析套件。采集 NPU 执行的方方面面,帮你找到性能瓶颈。
一句话说清楚:profiling-suite 是昇腾的性能分析套件,采集 NPU 执行数据、算子耗时、通信耗时、内存带宽,生成可视化报告。
你说气人不气人,之前找性能瓶颈靠猜,现在用 profiling-suite 直接看数据。
为什么需要 profiling-suite?
三种情况:
1. 模型慢,不知道为什么
算子是瓶颈?通信是瓶颈?内存带宽是瓶颈?
2. 优化后不知道有没有效
改了代码,性能有没有提升?提升了多少?
3. 想深入优化
看流水线、看内存访问模式、看指令发射效率。
profiling-suite 核心能力
1. 性能数据采集
采集 NPU 执行的各类数据。
import torch
import torch_npu
from canning import profiling_suite as ps
# 方式一:上下文管理器
with ps.Profile() as prof:
output = model(input_data)
# 方式二:装饰器
@ps.profile()
def forward(model, input_data):
return model(input_data)
output = forward(model, input_data)
# 方式三:手动控制
ps.start()
output = model(input_data)
ps.stop()
你说气人不气人,加一行代码就能采集完整性能数据。
2. 算子耗时分析
看每个算子花了多少时间。
import torch
import torch_npu
from canning import profiling_suite as ps
model = MyModel().npu()
with ps.Profile() as prof:
output = model(input_data)
# 打印算子耗时
print(prof.op_summary())
# 输出:
# Op Type Calls Total(ms) Avg(ms) Min(ms) Max(ms)
# ---------------------------------------------------------------------------
# MatMul 100 350.2 3.50 3.20 4.10
# Conv2D 50 210.5 4.21 3.80 5.20
# Softmax 100 15.3 0.15 0.12 0.18
# LayerNorm 100 25.7 0.26 0.22 0.30
结论:MatMul 和 Conv2D 是瓶颈,优化重点在这里。
3. 内存分析
看内存分配、释放、峰值。
import torch
import torch_npu
from canning import profiling_suite as ps
with ps.Profile() as prof:
output = model(input_data)
# 打印内存报告
print(prof.memory_summary())
# 输出:
# Memory Events:
# - Allocations: 1,200
# - Frees: 1,150
# - Peak memory: 8.5 GB
# - Device: NPU:0
结论:峰值内存 8.5GB,如果 NPU 内存只有 16GB,要注意 OOM 风险。
4. 通信分析
看集合通信的耗时。
import torch
import torch_npu
import torch.distributed as dist
from canning import profiling_suite as ps
dist.init_process_group(backend='hccl')
with ps.Profile() as prof:
output = model(input_data)
dist.all_reduce(tensor)
# 打印通信报告
print(prof.communication_summary())
# 输出:
# Communication Events:
# - AllReduce: 50 calls, 120ms total, 2.4ms avg
# - AllGather: 20 calls, 80ms total, 4.0ms avg
# - ReduceScatter: 30 calls, 90ms total, 3.0ms avg
结论:AllReduce 通信占比 15%,考虑使用梯度累积或者通信-计算重叠。
5. 时间线导出
导出 Chrome Trace 格式,在 Chrome 里可视化。
import torch
import torch_npu
from canning import profiling_suite as ps
with ps.Profile() as prof:
for i in range(10):
output = model(input_data)
# 导出时间线
prof.export_chrome_trace("trace.json")
# 在 Chrome 中打开:
# 1. 打开 chrome://tracing/
# 2. 点击 "Load" 按钮
# 3. 选择 trace.json
# 4. 查看时间线可视化
时间线能看到的:
- 每个算子的开始/结束时间
- 算子之间的并行关系
- 内存分配/释放事件
- 通信事件
6. 性能建议
自动给出优化建议。
import torch
import torch_npu
from canning import profiling_suite as ps
with ps.Profile() as prof:
output = model(input_data)
# 打印优化建议
print(prof.optimization_suggestions())
# 输出:
# Optimization Suggestions:
# 1. MatMul op consumes 35% of total time. Consider:
# - Use FlashAttention for attention computation
# - Enable operator fusion for MatMul + bias + activation
# 2. Communication overhead is 18%. Consider:
# - Overlap communication with computation
# - Use gradient accumulation
# 3. Memory peak is 8.5GB. Consider:
# - Use activation checkpointing
# - Use FP16 precision
性能数据
在昇腾 910 上分析 ResNet-50 推理:
| 分析项目 | 数值 | 说明 |
|---|---|---|
| 总耗时 | 15.2ms | 单张图片推理 |
| 算子耗时占比 | 85% | 计算是瓶颈 |
| 通信耗时占比 | 5% | 可忽略 |
| 内存峰值 | 1.2GB | 模型 + 中间激活值 |
| 最慢算子 | Conv2D | 占总时间 40% |
优化后:
| 分析项目 | 数值 | 提升 |
|---|---|---|
| 总耗时 | 8.5ms | 1.8x |
| 算子耗时占比 | 90% | - |
| 通信耗时占比 | 3% | - |
| 内存峰值 | 0.8GB | 1.5x 降低 |
| 最慢算子 | Conv2D (fusion) | 25% 占比 |
怎么用?
方式一:Python 接口(推荐)
import torch
import torch_npu
from canning import profiling_suite as ps
# 1. 准备模型和数据
model = ResNet50().npu()
input_data = torch.randn(1, 3, 224, 224).npu()
# 2. 性能分析
with ps.Profile(
activities=[ps.ProfilerActivity.CPU, ps.ProfilerActivity.NPU],
record_shapes=True,
profile_memory=True,
with_stack=True
) as prof:
output = model(input_data)
# 3. 查看报告
print(prof.key_averages().table(sort_by="cpu_time_total", row_limit=10))
# 4. 导出时间线
prof.export_chrome_trace("resnet50_trace.json")
方式二:命令行工具
# 分析脚本
canning-prof --mode=performance \
--output=./prof_results \
python train.py
# 查看报告
canning-prof --mode=view \
--input=./prof_results/performance.json
方式三:集成到训练脚本
import torch
import torch_npu
from canning import profiling_suite as ps
# 只在特定 step 分析,避免大量日志
prof = ps.Profile(
start_on_cpu=True,
with_stack=True,
record_shapes=True
)
for epoch in range(num_epochs):
for step, (inputs, labels) in enumerate(dataloader):
inputs = inputs.npu()
labels = labels.npu()
# 每 100 个 step 分析一次
if step % 100 == 0:
prof.start()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
if step % 100 == 0:
prof.stop()
prof.export_chrome_trace(f"trace_step_{step}.json")
prof.start() # 重置,开始新的采集
prof.stop()
踩坑指南(亲身经历)
-
分析会影响性能
- 开启 profiling 会增加 5-15% 开销
- 不要在每个 step 都开启
- 定期采样即可
-
时间线文件很大
- 长时间采集会生成 GB 级 JSON
- 设置
with_stack=False可以减少文件大小 - 或者只采集特定 step
-
内存分析不准
- 如果用了
torch_npu.npu.empty_cache(),内存分析会不准 - 建议在分析时注释掉
empty_cache()
- 如果用了
-
分布式训练要指定 rank
prof = ps.Profile( activities=[ps.ProfilerActivity.NPU], on_trace_ready=ps.tensorboard_trace_handler('./log'), record_shapes=True )
与 msprof 的区别
| 特性 | profiling-suite | msprof |
|---|---|---|
| 定位 | Python 层性能分析 | 系统层性能分析 |
| 使用难度 | 简单(Python API) | 中等(命令行 + 配置) |
| 粒度 | 算子级 | 算子级 + 指令级 |
| 输出格式 | Python 对象 + Chrome Trace | JSON + 文本报告 |
| 适用场景 | 快速定位瓶颈 | 深度性能调优 |
简单说:
- profiling-suite:Python 开发者,快速定位瓶颈
- msprof:系统工程师,深度性能调优
总结
profiling-suite 就是昇腾的性能分析套件:
- 采集算子耗时
- 采集内存使用
- 采集通信耗时
- 导出时间线可视化
- 给出优化建议
更多推荐




所有评论(0)