CANN调优工具链全景:从profiler到tensorboard的完整观测体系
CANN调优工具链全景从profiler到tensorboard的完整观测体系有个团队找我说他们买了昇腾NPU集群花了大半年才把调优工具链搭起来。每个人用不同的工具各看各的数据互相之间对不上。最后我帮他们梳理了一套统一的工具链——从底层profiler到上层tensorboard覆盖了观测数据的采集、存储、查询、可视化全链路。这篇把昇腾NPU生态里的所有调优工具串起来告诉你每个工具在哪个环节用以及怎么组合起来形成完整的观测体系。工具链总览五层观测昇腾NPU的调优工具链分五层从硬件到应用应用层你的模型 ↓ 调用 算子层ops-nn, ops-transformer... ↓ 调用 CANN RuntimecanD, opbase... ↓ 调用 驱动层ACL, HCCS... ↓ 访问 硬件层达芬奇核心, AI CPU, HBM...每层都有对应的观测工具。第一层cann-colt-profiler硬件层这是最底层的profiler直接看达芬奇核心的执行流水线。能看到的指标每个指令周期的 CU utilizationC0/C1/C2利用率Cube Unit 和 Vector Unit 的占用率Unified Buffer 的命中/未命中HBM 的读/写带宽fromcann_colt_profilerimportColtProfiler profilerColtProfiler()# 配置要抓哪些硬件事件profiler.config(events[aic_metric_aiv_u利用率,aic_metric_cube_u利用率,aic_metric_vec_u利用率,aic_metric_l2命中率,aic_metric_hbm读写带宽,],interval100# 每100个cycle采一次)profiler.start()# 跑你的算子xtorch.randn(1024,1024).npu()for_inrange(100):ytorch.matmul(x,x)profiler.stop()# 打印结果reportprofiler.report()print(fCube利用率:{report[cube_u_util]:.1f}%)print(fVector利用率:{report[vec_u_util]:.1f}%)print(fL2命中率:{report[l2_hit_rate]:.1f}%)print(fHBM带宽:{report[hbm_bandwidth_gbps]:.1f}GB/s)# 如果 cube_u_util 60%说明 Cube 没吃饱# 常见原因# 1. 算子太小kernel启动开销占比高# 2. tiling 不合理片上数据不够用# 3. 数据格式不对没用 NC1HWC0第二层fwkblade算子层第二篇已经详细介绍过fwkblade第14篇。它是算子层的profiler能看到每个算子的耗时算子之间的依赖关系Host侧和Device侧的并行情况fromfwkbladeimportProfiler,ProfileConfig configProfileConfig(activities[ai_core,ai_cpu,host,memory],with_stackTrue,record_shapesTrue)profilerProfiler(config)profiler.start()# 跑模型model(input_data)profiler.stop()# 生成 timeline可以用 Chrome 的 trace event viewer 打开profiler.export_timeline(trace.json)# 打开方式在 Chrome 地址栏输入 chrome://tracing# Load - 选择 trace.json# 打印算子汇总reportprofiler.summary()foropinreport.top_ops(10):print(f{op.name:40s}{op.duration_ms:7.3f}ms ({op.percentage:.1f}%))第三层msadvisor应用层第三篇也提过msadvisor第17篇。它是应用层的调优顾问能给出具体的优化建议不只是“看数据”。frommsadvisorimportModelAdvisor advisorModelAdvisor(modelmodel,input_exampletorch.randn(1,3,224,224).npu(),optimization_goalthroughput)reportadvisor.analyze()# msadvisor 会# 1. 自动识别可融合的算子对# 2. 指出格式转换的冗余# 3. 推荐最优的 tiling 配置# 4. 生成优化后的模型代码# 直接应用优化建议optimizedadvisor.apply_optimizations()torch.save(optimized.state_dict(),model_optimized.pth)第四层TensorBoard可视化CANN的数据可以导出成TensorBoard格式在TensorBoard里统一看# 训练指标的 TensorBoard 导出fromtorch.utils.tensorboardimportSummaryWriter writerSummaryWriter(runs/npu_training)forstep,(loss,acc)inenumerate(train_metrics):writer.add_scalar(Loss/train,loss,step)writer.add_scalar(Accuracy/train,acc,step)writer.add_scalar(NPU/Memory_Used_GB,npu_memory_used,step)writer.add_scalar(NPU/AI_Core_Util,aicore_util,step)writer.close()# 启动 TensorBoard# tensorboard --logdirruns# 然后在浏览器打开 http://localhost:6006# 把 fwkblade 的 profiling 数据也导入 TensorBoardfromfwkblade.tensorboardimportTensorBoardExporter exporterTensorBoardExporter(runs/npu_profile)# 导出算子耗时exporter.export_op_stats(trace.json)# 导出内存使用exporter.export_memory_stats(memory_profile.json)# 现在 TensorBoard 里可以同时看# - 训练曲线loss、acc# - 算子耗时哪个算子最慢# - 内存使用显存趋势第五层Prometheus Grafana生产监控生产环境用Prometheus采集实时指标Grafana做监控看板fromprometheus_clientimportstart_http_server,Gauge,Counter# 启动 Prometheus exporter端口 9090start_http_server(9090)# 定义指标npu_utilGauge(npu_aicore_utilization,AI Core utilization,[device_id])npu_memoryGauge(npu_hbm_used_bytes,HBM memory used,[device_id])inference_latencyGauge(inference_latency_ms,Inference latency,[model])request_countCounter(inference_requests_total,Total requests,[status])# 在推理循环里更新指标fordevice_idinrange(8):npu_memory.labels(device_idstr(device_id)).set(get_hbm_usage(device_id))npu_util.labels(device_idstr(device_id)).set(get_aicore_util(device_id))forrequestinrequests:inference_latency.labels(modelresnet50).observe(request.latency_ms)request_count.labels(statusrequest.status).inc()# prometheus.ymlglobal:scrape_interval:5sscrape_configs:-job_name:npu_inferencestatic_configs:-targets:[localhost:9090]Grafana看板要关注的几个核心指标AI Core利用率所有卡应该 70%否则有瓶颈HBM内存使用率每张卡应该 90%否则可能OOM推理延迟P99应该 100ms请求成功率应该 99.9%工具链组合定位性能瓶颈的标准流程用这套工具链定位瓶颈分四步走第一步用colt-profiler扫硬件层# 快速扫一遍看Cube利用率和HBM带宽fromcann_colt_profilerimportquick_scan resultquick_scan(model,input_data,duration_s1.0)print(fCube利用率:{result[cube_util]:.1f}%)print(fVector利用率:{result[vec_util]:.1f}%)print(fHBM带宽:{result[hbm_bw]:.1f}GB/s)ifresult[cube_util]50:print(→ 硬件层Cube利用率低)print( → 可能原因算子融合不充分 / tiling不合理)elifresult[hbm_bw]1000:# 接近峰值print(→ 硬件层HBM带宽瓶颈)print( → 可能原因算子太小 / 内存访问模式不友好)第二步用fwkblade定位到具体算子# 如果第一步没定位到用fwkblade看算子层fromfwkbladeimportProfiler profilerProfiler()profiler.start()model(input_data)profiler.stop()# 打印TOP 10最慢的算子foropinprofiler.summary().top_ops(10):print(f{op.name}:{op.duration_ms:.3f}ms ({op.percentage:.1f}%))第三步用msadvisor给出优化建议# 定位到慢算子之后用msadvisor分析优化方向frommsadvisorimportModelAdvisor advisorModelAdvisor(model,input_data)reportadvisor.analyze()# 打印针对这个模型的优化建议forsuggestioninreport.suggestions:print(f[{suggestion.priority}]{suggestion.description})print(f 预计收益:{suggestion.estimated_speedup}x)print(f 操作步骤:{suggestion.action})第四步用tensorboard验证优化效果# 优化前后对比fromtorch.utils.tensorboardimportSummaryWriter writerSummaryWriter(runs/comparison)# 优化前profiler_beforefwkblade.Profile(...)writer.add_scalar(Latency/Before,profiler_before.latency_ms,0)# 优化后profiler_afterfwkblade.Profile(...)writer.add_scalar(Latency/After,profiler_after.latency_ms,0)# 对比improvementprofiler_before.latency_ms/profiler_after.latency_msprint(f优化提升:{improvement:.2f}x)工具选型指南场景工具为什么用它硬件层性能扫盲cann-colt-profiler看CU utilization、HBM带宽算子级瓶颈定位fwkblade看每个算子耗时、依赖关系不知道从哪改msadvisor自动给优化建议训练过程监控TensorBoard看loss曲线、指标趋势生产环境监控Prometheus Grafana实时告警、自动巡检延迟分布分析ais_bench测P50/P90/P99、对比baseline跟官方数据对标ais_bench标准化测试条件可对标迁移前评估ais_bench测GPU vs NPU性能比踩过的坑工具本身的overhead# 坑1开了profiling之后性能测不准# fwkblade本身有overhead会让结果偏慢10-30%# 解决测性能的时候关profiling只在定位问题时才开profilerProfiler()profiler.start()# profiling 开启性能下降model(input_data)# 这次的结果不准profiler.stop()profiler.disable_profiling()# 关掉 profilingmodel(input_data)# 这次的结果才是真实的# 坑2tensorboard写入影响训练速度# 每个step都写tensorboard会很慢# 解决每N个step写一次不要每个step都写forstepinrange(10000):losstrain_step()ifstep%1000:# 每100步写一次writer.add_scalar(Loss,loss,step)# 坑3colt-profiler采集间隔太短会测不准# interval10每10个cycle采一次会让probe本身影响测量# 解决interval100或更长profiler.config(interval100)# 每100个cycle采一次比较准完整的调优闭环发现性能问题 ↓ colt-profiler 扫硬件层 → 定位到Cube/Vector/HBM瓶颈 ↓ fwkblade 定位到具体算子 ↓ msadvisor 给出优化建议 ↓ 应用优化改代码 / 调配置 / 重编译 ↓ ais_bench 测性能提升 ↓ TensorBoard 记录优化前后的对比曲线 ↓ Prometheus Grafana 上线监控 ↓ 发现新的性能问题循环