CANN-Profiler-昇腾NPU上推理慢到底慢在哪
推理服务上线前最重要的一步是性能 Profiling。ATB 的推理速度不达标,可能有十几个原因——不拿数据说话就是瞎猜。CANN Profiler 给你精确到每个 kernel 的执行时间。
开启 Profiling
importtorch_npu# 方法 1:Python APIwithtorch_npu.profiler.profile(activities=[torch_npu.profiler.ProfilerActivity.CPU,torch_npu.profiler.ProfilerActivity.NPU],record_shapes=True,profile_memory=True)asprof:model.generate("Hello",max_new_tokens=50)print(prof.key_averages().table(sort_by="npu_time_total",row_limit=20))# 方法 2:环境变量(更底层)exportPROFILING_MODE=1exportPROFILING_OPTIONS='{"output":"./profiling_data","task_trace":"on"}'python infer.py方法 2 生成原始 profiling 数据,需要用 CANN 的分析工具处理。
看 Profiling 报告
关键的几列:
| 列名 | 含义 | 关注点 |
|---|---|---|
| Name | 算子名称 | 有没有FusedKernel(融合了) |
| NPU Time | NPU 执行时间 | 哪个算子最慢 |
| CPU Time | CPU 调度时间 | CPU 有没有成为瓶颈 |
| Calls | 调用次数 | 有没有异常频繁的调用 |
| CPU Mem / NPU Mem | 内存占用 | 有没有显存泄漏 |
典型分析流程:
- 按 NPU Time 排序,找 Top 10 最慢的算子
- 检查这些算子有没有融合版本可用
- 检查 CPU Time 是否异常高(调度瓶颈)
- 检查 Calls 是否有异常(重复计算)
常见性能问题诊断
问题 1:Softmax 没走融合
Profiler 报告: Softmax 0.08ms × 32 层 = 2.56ms ← 太慢 期望: FusedKernel (FlashAttention 内部 Softmax) 0.03ms原因:输入 tensor 不连续或 dtype 不对。检查x.is_contiguous()和x.dtype。
问题 2:CPU 调度瓶颈
Profiler 报告: NPU Time: 3.1ms CPU Time: 4.8ms ← CPU 比 NPU 还慢 原因:eager mode 下每个算子都有 Python→C++ 的调度开销 解决:torch.compile(model, backend="npu")问题 3:HBM 读写过多
Profiler 报告: MatMul 0.5ms CopyH2D 0.3ms ← 数据在 HBM 进出太多 原因:算子没融合,中间结果频繁写回 HBM 解决:确认 graph-autofusion 是否生效对比分析
最有效的 Profiling 方法是做 A/B 对比:
# 版本 A:标准 PyTorchmodel_a=AutoModel.from_pretrained("model_id",torch_dtype=torch.float16).to("npu:0")# 版本 B:ATB 加速model_b=LLM("model_id",device="npu:0")# 分别 profile,对比 kernel 列表对比两个版本的 profiler 输出,看哪些 kernel 被替换了、哪些 kernel 消失了。这是验证优化是否生效的最直接方式。
NPU 利用率
Profiler 会输出 NPU 的整体利用率:
NPU Compute Utilization: 42% NPU Memory Utilization: 78% NPU DMA Utilization: 35%- Compute < 30%:计算不够密集,可能是 batch 太小或融合不够
- Memory > 90%:显存压力大,需要减少 batch 或开启 KV Cache 优化
- DMA < 50%:数据搬运没跟计算重叠,需要 double buffer
decode 阶段的 Compute 利用率低(5-10%)是正常的——M=1 的 GEMM 打不满 Cube 单元。prefill 阶段应该 > 70%。
线上持续 Profiling
推理服务上线后可以用采样 Profiling,每隔 N 个请求采集一次:
importrandomclassSamplingProfiler:def__init__(self,sample_rate=0.01):self.sample_rate=sample_ratedefshould_profile(self):returnrandom.random()<self.sample_ratedefrecord(self,request):ifself.should_profile():withtorch_npu.profiler.profile(...)asprof:result=model.generate(request.prompt)self.save_profile(prof)returnresultelse:returnmodel.generate(request.prompt)1% 的采样率对性能影响 < 1%,但能持续监控线上服务的算子执行时间。
不 Profile 就优化是盲人摸象。CANN Profiler 给你精确到微秒的算子执行数据,用 A/B 对比验证优化效果,用线上采样持续监控。推理性能问题 90% 可以靠 Profiling 定位。仓库在这里:
https://atomgit.com/cann/ATB
