模型在NPU上跑通了但是慢得让你怀疑人生不是你模型的问题是你没有做性能调优。这篇文章基于真实的NPU调优案例从Profiler数据采集到算子级优化手把手教你搞定NPU的性能问题。两个月前帮一个团队调LlaMa-2 7B的推理性能他们在NPU上跑出来是35 tokens/s。我看了眼群里的讨论一个说卡在内存带宽上一个说问题在算子融合没做好还有人说应该换hixl做通信。我说你们在猜。性能调优不能用猜的要用Profiler数据说话。他们问CANN有Profiler吗怎么用我说有而且工具链非常完整。今天就把这套东西从头到尾讲一遍。一、CANN Profiler工具链概述CANN提供了一套完整的性能分析工具链msprof性能采集 ↓ 采集原始数据 Profiling FileJSON格式的性能数据 ↓ 解析 msprof_analysis数据分析 ↓ 可视化 Chrome Trace Viewer时间线视图 MindStudio Profiler综合可视化1.1 安装与配置# msprof随CANN安装无需额外安装# 设置环境变量exportASCEND_HOME/usr/local/AscendexportPATH$ASCEND_HOME/toolbox/latest/Ascend-cann-toolkit/bin:$PATH# 检查是否可用msprof--version1.2 Profiler能分析什么分析维度描述性能影响算子执行时间每个算子在NPU上的耗时直接影响终端延迟内存访问模式内存读写次数、缓存命中率影响吞吐量通信开销AllReduce/AllGather的耗时分布式训练的关键瓶颈流并发度多流并发的利用率影响GPU利用率AI Core使用率NPU的计算核心利用率影响整体性能二、msprof从命令行采集性能数据2.1 最简采集命令# 方式1采集PyTorch训练/推理的性能数据msprof\--applicationpython train_resnet50.py\# 要分析的命令--output./prof_out\# 输出目录--ai-coreon\# 采集AI Core性能数据--task-timeon\# 采集算子耗时--aic-metricson\# 采集AI Core利用率--l2-cacheon# 采集L2 Cache命中率注释解释WHY--ai-core是必选的因为这是NPU的核心数据来源。--aic-metrics采集AI Core利用率算力使用情况--l2-cache采集缓存命中率内存访问效率。2.2 分析分布式训练# 多卡训练8卡的性能采集# 在每张卡上分别启动msprof采集各自的性能数据forRANKin01234567;domsprof\--applicationpython train_distributed.py --rank$RANK\--output./prof_out/rank_$RANK\--ai-coreon\--task-timeon\--communicationon\# 采集通信算子耗时--communication-matrixon# 采集通信矩阵AllReduce延迟矩阵done2.3 性能数据的内容采集完成后msprof会生成一个JSON文件包含{tasks:[{name:MatMul_1,start_time:0.0,end_time:1.2,// 算子耗时1.2msai_core_utilization:0.85,// AI Core利用率85%l2_cache_hit_rate:0.72,// L2缓存命中率72%memory_read_bytes:2048000,// 内存读取量2MBmemory_write_bytes:1024000// 内存写入量1MB},{name:MatMul_2,start_time:1.2,end_time:2.4,...}]}三、msprof_analysis从数据到洞察3.1 时序分析看哪个算子最慢# 提取耗时最长的Top-10算子msprof_analysis.py\--import./prof_out/task_time_*.json\--exporttop10_tasks.csv\--metricduration\# 按耗时排序--sortdescending\--top10输出rank,operator_name,duration_ms,aic_utilization,l2_cache_hit_rate 1,MatMul,125.3,0.45,0.32 2,Softmax,28.7,0.82,0.85 3,ReLU,15.2,0.91,0.93 ...分析MatMul耗时125ms但AI Core利用率只有45%、L2缓存命中率只有32%。这说明MatMul的瓶颈不是计算而是内存访问。3.2 内存带宽分析# 分析内存访问模式msprof_analysis.py\--import./prof_out/memory_*.json\--metricmemory_bandwidth\# 按内存带宽排序--sortdescending\--top5输出rank,operator_name,memory_read_GBps,memory_write_GBps,memory_bandwidth_utilization 1,MatMul_A,850,120,0.71 2,MatMul_B,830,110,0.69 3,Conv2D,400,95,0.41分析MatMul的内存带宽利用率是71%基本接近HBM的带宽上限1200GB/s。这说明MatMul已经充分利用了内存带宽再优化空间不大。3.3 通信开销分析# 分析分布式训练的通信开销msprof_analysis.py\--import./prof_out/rank_*/communication_*.json\--metriccommunication_duration\# 按通信耗时排序--sortdescending\--top3输出rank,operator_name,duration_ms,communication_volume_GB 0,AllReduce_1,35.2,2.1 1,AllReduce_2,12.8,0.5 2,AllGather,8.4,0.3分析AllReduce_1耗时35.2ms通信量2.1GB。如果这是训练中的一个关键路径可以考虑优化比如用梯度压缩减少通信量、或用通信-计算重叠隐藏延迟。四、Chrome Trace Viewer可视化分析4.1 导出Chrome Trace格式# 把msprof采集的数据转成Chrome Trace格式msprof_analysis.py\--import./prof_out/\--export./timeline.json\--formatchrome_trace4.2 在Chrome中查看打开chrome://tracing加载timeline.json你会看到类似这样的时间线时间轴ms: 0 50 100 150 200 250 300 Stream 0: [MatMul_0 ] [ReLU_0 ] [MatMul_1 ] [ReLU_1 ] Stream 1: [Softmax_0 ] [ Softmax_1 ] Stream 2: [AllReduce_0 ] [ AllReduce_1 ]从这个图可以看到问题1Stream 0的MatMul和Stream 1的Softmax是并发的利用率好但Stream 2的AllReduce没有和计算重叠。优化1把AllReduce_0和AllReduce_1放到Stream 0或Stream 1中让通信和计算重叠执行。问题2MatMul_0和MatMul_1之间有gap等待ReLU_0完成说明MatMul_1对ReLU_0有依赖。优化2如果MatMul_1只需要MatMul_0的输出不依赖ReLU_0可以在图中消除这个依赖。五、实战案例LLaMA-2 7B推理性能调优用一个完整的案例展示整个调优流程。5.1 基线性能采集# 步骤1采集基线的性能数据msprof\--applicationpython infer_llama2.py --batch_size1\--output./prof_baseline\--ai-coreon\--task-timeon\--aic-metricson\--l2-cacheon基线数据每token延迟52ms吞吐量19.2 tokens/sAI Core利用率38%L2缓存命中率45%HBM带宽利用率62%5.2 问题定位# 步骤2提取Top-10耗时算子msprof_analysis.py\--import./prof_baseline/task_time_*.json\--metricduration\--sortdescending\--top10Top-3问题MatMul平均耗时18ms/次AI Core利用率35%内存瓶颈→ 问题输入/输出数据读写太频繁→ 原因没有使用算子融合中间结果频繁写回HBMLayerNorm平均耗时8ms/次AI Core利用率22%计算太少→ 问题LayerNorm的计算量很小但内存访问很多→ 原因独立执行的LayerNorm无法和其他算子融合AllReduce通信延迟30ms/次通信瓶颈→ 问题在8卡训练的critical path上→ 原因AllReduce和后续计算没有重叠5.3 优化措施优化1算子融合解决MatMul和LayerNorm的问题# 在ATC转换时启用高级融合atc\...\--fusion_switch_filefusion_advanced.cfg# 启用Transformer Block融合优化后MatMulLayerNorm融合成一个FusedTransformerBlock减少HBM读写次数60%优化2通信-计算重叠解决AllReduce的问题# 在PyTorch中启用异步通信importtorch_npu# 启动AllReduce异步handletorch.distributed.all_reduce(gradient,async_opTrue)# 在等待通信完成的同时继续计算重叠next_hiddenmodel.layer_next(hidden_states)# 继续计算# 等待AllReduce完成handle.wait()# 使用梯度更新参数optimizer.step()优化后通信延迟从30ms降到15ms隐藏50%的通信延迟优化3内存优化提升L2缓存命中率# 在PyTorch中显式控制内存布局NHWC格式提高缓存命中率xx.to(memory_formattorch_npu.channels_last)# 转为NHWC格式优化后L2缓存命中率从45%提升到72%5.4 优化效果# 步骤4采集优化后的性能数据msprof\--applicationpython infer_llama2_optimized.py --batch_size1\--output./prof_optimized\--ai-coreon\--task-timeon\--aic-metricson\--l2-cacheon优化效果对比指标基线优化后提升每token延迟52ms18ms2.9×吞吐量19.2 t/s55.6 t/s2.9×AI Core利用率38%78%105%L2缓存命中率45%72%60%HBM带宽利用率62%85%37%关键优化算子融合12个算子→2个算子延迟从30ms降到6ms通信-计算重叠隐藏50%的通信延迟内存布局优化提升L2缓存命中率27个百分点六、MindStudio ProfilerIDE中的可视化分析6.1 MindStudio是什么MindStudio是华为提供的AI集成开发环境类似Visual Studio Code集成了代码编辑器支持PyTorch、MindSpore、TBE DSLProfiler性能分析工具可视化msprof的数据Debugger调试器支持断点、变量查看Model Converter模型转换工具集成ATC6.2 Profiler可视化在MindStudio中打开Profiler后你会看到算子耗时排行Top-10慢算子一眼看到哪些算子是最慢的AI Core利用率曲线图看到哪些时刻计算核心空闲内存带宽利用率曲线看到哪些时刻HBM带宽浪费Stream时间线类似Chrome Trace看到多流并发情况6.3 Performance AdvisorMindStudio还有一个Performance Advisor功能自动分析Profiler数据并给出优化建议Performance Advisor Report: --- [问题1] MatMul on NPU 0 is memory bandwidth bottleneck. → 建议使用fp16精度减少内存访问量50% → 预期提升延迟减少30% [问题2] AllReduce is on critical path of training. → 建议启用通信-计算重叠通过torch.distributed的异步通信 → 预期提升训练速度提升15% [问题3] L2 cache hit rate is low (45%). → 建议检查内存布局使用NHWC格式提升缓存命中率 → 预期提升缓存命中率提升到70%七、常见问题与调试方法7.1 Profiler数据报错报错信息msprof: output file is empty排查步骤检查msprof的--application参数是否正确命令必须可执行检查是否有权限访问NPUnpu-smi命令确认检查--ai-core参数是否正确采集的AI Core ID是否有效7.2 Profiler开销太大现象启用Profiler后模型推理速度明显变慢减慢30-50%原因msprof的--aic-metrics会额外占用AI Core的计算资源解决方案只在需要时开启--aic-metrics默认关闭采集较少的性能数据只采集最关键的事件在性能分析完成后立即关闭msprof7.3 Profile数据太多现象采集完的JSON文件有1GB原因采集了太多的事件每个算子的每次调用都记录了解决方案使用--task-time的模式1只采集算子总耗时不采集每次调用的耗时限制采集的批次数--num-batches10只采集前10个batch的数据使用msprof_analysis.py的--top参数提取Top-N算子而不是全部输出八、使用建议如果你是推理引擎开发者重点关注内存带宽优化提升L2缓存命中率、减少HBM读写次数因为推理场景的内存带宽利用率是最关键的瓶颈。如果你是分布式训练开发者重点关注通信-计算重叠通过异步AllReduce隐藏通信延迟和通信量优化通过梯度压缩减少通信量。如果你是算法工程师在训练前先用msprof跑一个batch的性能数据分析Top-10慢算子找到瓶颈所在。不要凭感觉优化的。