F4 性能调优:数据怎么采、怎么看
编制:观澜|日期:2026-10-06|级别:T2 标准级 层级:F 层 · 场景实战(F 层第 4 课;前接 F1 模型迁移、F2 精度调试、F3 多卡与分布式) 素材来源:昇腾官方《性能调优工具(msProf)》用户指南(快速入门 / msprof 采集命令 / msProf 解析工具 / 性能数据文件参考 / 扩展功能)+《msprof-analyze · 专家建议》+《MindSpeed LLM · FSDP2 后端模型性能优化指南》+《Rec SDK 性能调优》+ 官方案例库 版本口径:CANN 9.2.0-beta.2 为主;MindSpeed 26.1.0、MindStudio 26.1.0 的章节已单独标注
第一段 章前定位
这一课不教你什么
先把边界划清——本课不是 D5。
| D5《可用性、健康与调优》 | 本课 F4《性能调优》 | |
|---|---|---|
| 问的问题 | 服务别挂:进程卡死了没有、健康检查通不通、日志级别对不对 | 跑得慢怎么变快:慢在哪一层、数据怎么采、采完怎么看 |
| 视角 | 服务视角(就绪、自愈、静默故障、KV Cache 亲和调度) | 设备与执行视角(算子、搬运、通信、下发) |
| 触发场景 | 服务起来了但不稳定 | 服务稳定但时延/吞吐不达标 |
一句话分工:D5 管"活着",F4 管"跑得快不快"。 两者都会用 Profiling 这个词,但 D5 关心的是服务级的健康数据,F4 关心的是设备上的时间花到哪去了。
其次,本课也不负责"优化代码本身"
性能调优是一条长链:先看清 → 再判断 → 才动手改。本课重点在前两步:
- 怎么采:把设备上真实发生的事采下来(第一个坑:默认不采);
- 怎么看:把采下来的文件读懂,判断瓶颈属于哪一类(算力 / 带宽 / 通信 / 下发 / 显存)。
改这一步只有原则性的方向(融合、类型、下发方式、并行度),具体改法依赖你的模型与代码——本课给判断依据,不替你改模型。这是诚实的边界,也是避免"讲了一堆技巧但不知道用哪条"的关键。
第三,一条数据纪律先讲明
性能数字极易被编造("调优后提升 3 倍"这类)。本课的原则:
凡官方文档给出阈值/公式的,写明"出处 + 版本";官方没给的,正文里明写「官方未给出,需现场确认」。
一个典型的坑:官方在不同产品、不同场景下给的参考值口径并不统一(例如"未掩盖通信 ≤10%"来自 MindSpeed LLM 的 FSDP2 场景,不是通用红线)。本课会逐条标明它来自哪个场景,避免把一个场景的阈值当普适真理用。
第二段 学习目标
学完这一课,你应该能:
- ✅ 说清一条性能数据的完整链路:采集 → 解析/导出 → 看 → 判瓶颈,以及每一步的产物文件长什么样
- ✅ 知道为什么"不采就什么都看不到"——Profiling 默认不开,这是第一个必须主动做的动作
- ✅ 用
msprof命令行把一次训练或推理的性能数据采下来,并读懂屏幕上那几行[INFO]说明什么 - ✅ 说出 Timeline(时序) 和 Summary(统计) 两类文件各回答什么问题,以及各自该看哪个文件
- ✅ 用指标判断瓶颈类型:
Free时间看 Host 下发、aic_mac_ratio/aic_mte2_ratio看计算还是访存、通信泳道看未掩盖通信、cube_utilization(%)看矩阵单元 - ✅ 说出判据与它的来源(哪个阈值来自哪个场景),并知道哪些阈值官方没给、要自己建基线
- ✅ 采集踩坑时能自查:采集报错、采不到 AI Core 指标、文件过期、解析缺 modelid —— 各查什么
第三段 全景:一条性能数据从哪来、到哪去
3.1 先记住一句话:默认不采
官方原文(《Profiling数据采集与分析》,TensorFlow 商用版 9.0.0):
默认训练过程中不采集 Profiling 性能数据,如需采集、解析性能数据,请参考本节内容。
这句话的后果:你跑得慢,但屏幕上什么额外信息都没有——不是"没数据",是"没采"。所以性能调优的第一个动作永远是主动打开采集,而不是先猜。
⭐ 官方对采 Profiling 的定位(同一篇文档): 其目的是"准确定位系统的软、硬件性能瓶颈……以最小的代价提升业务性能"。 注意"定位"二字——采数据的价值不在数据本身,在于把猜测换成证据。
3.2 四段链路(本课的骨架)
① 采集 谁在跑:msprof 命令行(或框架侧 Profiler 接口)
产出:PROF_XXX 目录(原始数据 + 自动解析件)
② 解析 / 导出 msprof --export=on 或 msprof.py import + export
产出:mindstudio_profiler_output(json + csv)+ msprof_时间戳.db
③ 看数据 两类文件,回答两个不同的问题:
Timeline(时序)——先看谁在等谁
Summary(统计)——再问哪一类最贵
④ 定瓶颈 计算 / 访存 / 通信 / Host 下发 / 显存
纪律:每次只处理一个主瓶颈,改完用同一口径重测
3.3 ③ 里的两个文件族(先分清,再谈分析)
官方(《性能数据文件参考》)把导出结果分成两类:
| 类型 | 长什么样 | 干什么用 | 用什么打开 |
|---|---|---|---|
| Timeline(时序) | msprof_{时间戳}.json |
可视化展示各层级算子的调用关系与执行时序 | chrome://tracing 或 MindStudio Insight |
| Summary(统计) | mindstudio_profiler_output 下的 csv 文件 |
多维度的统计摘要信息,以表格形式汇总运行耗时 | 表格软件 / 文本 |
⭐ 记忆法: Timeline 回答"谁在等谁"(时间轴上的先后与间隙);Summary 回答"哪一类最贵"(按类型聚合的耗时排序)。 顺序上先 Timeline 定方向、再 Summary 定量——反过来容易盯着一个"耗时最高的算子"却看不出它其实是在等别人。
3.4 ④ 的五类瓶颈(名字先记住,第六段给判据)
计算瓶颈 Cube / Vector 单元忙不过来
访存瓶颈 数据搬运(MTE2/MTE3)占了大头
通信瓶颈 多卡场景,通信没被计算掩盖
Host 下发 设备在"饿着"等 CPU 下发任务(Free 时间高)
显存瓶颈 不是慢,是跑不动(OOM 或频繁换入换出)
⚠️ 这五类不是并列选项,而是"排他性诊断":先确定主瓶颈,再谈优化。 官方原话(《Rec SDK 性能调优》):
实际中大部分情况是解决完一个 bound,又会出现另一个 bound,或者混杂到一起的场景;没有出现 bound 可能是 NPU 利用率没有打满,可以先构造压力打满的场景,再分析瓶颈点。
这两句要记住:① 瓶颈会搬家,一次只解决一个;② 看不出瓶颈 ≠ 没有瓶颈,很可能是压力不够,没把设备跑满。
第四段 【如果我来做】——一次真实的性能问题排查路径
这一节是本课的核心。 前三段讲的是"性能数据是什么、有哪几段链路、瓶颈分几类",这一节讲的是: 如果客户把一台"跑得慢"的机器交给我,我按什么顺序做、每一步凭什么判断。
4.0 先亮结论:我会按这个顺序做
为什么顺序不能反:
- 一上来就改代码调参数,改动没有基线可比——改完是快了还是慢了,说不清;
- 一上来就开最高采集等级,采集开销把现象本身掩盖了(官方专门有"性能膨胀"这回事,见第八段);
- 不先确认"设备到底跑满没有",可能花一天调一个根本没在工作的算子。
我会按这个顺序做(顺序 = 我"手伸进去"的顺序):
① 先对齐口径:跟提出需求的人确认指标是什么、目标是多少(时延?吞吐?step 耗时?),以及 batchsize / 数据类型——没有基准就无所谓快慢 ② 先看设备忙不忙:
npu-smi info看利用率,先做一次零成本的粗判 ③ 先确认环境能采:一行验环境的命令先过,不然采集起来也是一堆空数据 ④ 采最小的一份:只采一个稳态 step / 一小段时间窗,能定位问题就够,别一次采全程 ⑤ 先看 Timeline 找"间隙":间隙(设备空闲)比"哪个算子慢"更值得先看 ⑥ 再用 Summary 定量:按总耗时排序,落到具体算子类型或通信操作 ⑦ 定一个主瓶颈:计算 / 访存 / 通信 / 下发 / 显存,只选一个 ⑧ 改动之后用同一口径重测:这是唯一能证明"改对了"的方式 ⑨ 诚实:官方没给的阈值、没给的加速比,明说是自己建的基线,不编数字
下面把中间的每一步展开。
4.1 第 0 步:先把"快慢"定义出来(不做任何操作)
目的:在做任何事之前,先拿到一把尺子。
官方《Rec SDK 性能调优》把需要对齐的指标列得很清楚,我抄下来当清单:
| 要对齐的 | 为什么 | 官方给的例子 |
|---|---|---|
| 时延要求 | 是固定值还是变化值?低负载和高负载的标准一样吗? | 要求某个固定值,或是变化值;以及低/高负载的要求标准 |
| batchsize 分布 | 固定值还是动态值?分布如何? | 固定值,或动态值及分布 |
| QPS | 官方定义:QPS = 请求数 / 秒(req/sec) | — |
| 吞吐量 | 官方定义:吞吐量 = QPS × batchsize | — |
| 数据类型 | float16 / float32 决定算力口径 | float16、float32 或其他 |
| CPU 资源 | 官方明说:多卡场景可能会出现 CPU bound,前期调试需确认 CPU 资源是否已满足 | 单卡按客户配置,Docker 中切分 CPU 资源验证 |
训练场景的口径略有不同,官方《MindSpeed LLM · FSDP2》给的是这四项:
| 指标 | 定义 | 日志字段 |
|---|---|---|
| 稳态单 step 耗时 | 完成一个 optimizer step 的时间(含梯度累积的所有 micro batch) | elapsed time per iteration (ms) |
| 有效 token 吞吐 | 有效 token 数 ÷ step 耗时 | tokens/s |
| MFU | 模型实测 FLOPS ÷ 硬件理论峰值 | mfu(仅在 FLOPS 口径相同的模型间比较) |
| 峰值显存 | — | max_memory_allocated / max_memory_reserved |
⚠️ 这里有一条本课要反复强调的纪律: 官方没有给出"性能达标线" —— 什么算快、什么算慢,官方文档未给出通用数字。 所以第 0 步的产出不是"官方标准",而是你和业务方一起定的目标值。 没有这个值,后面所有"提升了 X%"都无从谈起。
4.2 第 1 步:先看设备忙不忙(零成本粗判)
在采任何数据之前,我先敲一条最简单的命令(见第五段命令 ①)。
决策依据(官方《Rec SDK 性能调优》原文口径):
- 利用率很高 → 很有可能就是 bound(设备被计算/搬运占满,问题在设备内部);
- 单个推理时利用率低、多个推理并行时才超过 80% → 官方说"一般认为这个值就已经很高了";
- ⚠️ 但这条命令的值不能当结论——官方明说:这种方式查看到的值是 cube 核上的 cycle 与时钟频率换算出来的 cycle 的比值,不包含 vector core 的占比,所以只是初步查看,具体要从 profiling 里的 cycle 自行计算。
所以第 1 步的作用只有一个:决定"要不要往下采"。它不能替你定瓶颈。
4.3 第 2 步:先确认环境采得动(不然白采)
采集工具对环境有要求,官方《msProf 快速入门》的前置条件表:
| 项目 | 要求 | 验证方法(官方原表) |
|---|---|---|
| 硬件算力 | Linux 服务器配备至少 1 张 NPU 卡,驱动与固件已安装 | 执行 npu-smi info,确认 NPU 卡状态正常 |
| 容器运行 | 已安装并运行 Docker(建议版本 ≥ 18.0) | 执行 docker ps,无报错即表示服务正常启动 |
| 脚本执行 | 宿主机已安装 Python 3 | 执行 python3 -V |
| 网络通信 | 已安装 curl(任意版本) | 执行 curl -V |
⚠️ 一条重要的适用范围说明(官方原文,必须照实转述): 《msProf 快速入门》这一篇教程 "仅支持在标准化 CANN 容器中执行,不支持直接在裸机、虚拟机或其他非标准容器环境中执行。" 这是"快速入门教程"的适用范围,不是 msProf 工具本身的限制——但在裸机/虚机上照抄快速入门的容器步骤会失败。 裸机环境的采集参数是否可用,需按《msProf 模型调优工具》主文档逐条确认。
再看一眼工具在哪(官方《msProf解析工具》给的两个路径):
msprof命令行本体:${INSTALL_DIR}/tools/profiler/bin(Ascend EP 场景)msprof.py脚本:${INSTALL_DIR}/tools/profiler/profiler_tool/analysis/msprofget_msprof_info.py:${INSTALL_DIR}/tools/profiler/profiler_tool/analysis/interface
其中 ${INSTALL_DIR} 官方给了替换口径:若安装的是 Toolkit 软件包、以 root 安装,安装后文件存储路径为 /usr/local/Ascend/cann。
4.4 第 3 步:采一份"最小"的数据
为什么不采全程:官方专门有一篇案例讲"性能膨胀"(profilingcase_007,见第八段)——开启 Profiling 后 step 耗时会变长,两者差值就是膨胀时间;膨胀程度与采集设置强相关。
我的默认策略:
先采最小 → 能定方向就不加项 → 定不了再加(stack / memory / shape)
训练场景官方 MindSpeed LLM 给了一个"最小 trace 采集"的范式(见第五段命令 ③ 的对照表), 核心两个参数就是"采哪几个 step"和"采哪几个 rank":
--training.profile_step_start 5/--training.profile_step_end 6(官方明确:采集区间是左闭右开[start, end))--training.profile_ranks 0(首轮只采 0 号 rank)- 官方提示:定位性能问题时开启 stack、memory 和 shape 采集会使数据体积增大,并引入额外采集开销。
推理/单机场景则直接用 msprof 命令行把程序包起来采(第五段命令 ②)。
4.5 第 4 步:先看 Timeline 的"间隙",不要先看"谁最慢"
这是本课最容易被做错的一步。 多数人拿到 Timeline 第一反应是找"最长的那个色块", 但设备空着的那些间隙(Free)往往比某个慢算子更值得先看。
官方《MindSpeed LLM · FSDP2》把单步时间拆成三项,这是理解 Timeline 的钥匙:
step_time = computation_time
+ unhidden_communication_time
+ device_free_time
官方原话:
Free表示 Device 既未执行计算也未执行通信的时间段。其占比应小于 3%;若占比偏高,通常表明 NPU 在等待 Host 下发任务。
为什么先看 Free:如果设备大量时间在"等人喂任务",那么你优化任何算子都不会变快——因为瓶颈根本不在这里。这就是"先定方向、再谈细节"。
再看三件事(官方给的 Timeline 常用泳道):
| 泳道 | 看什么 |
|---|---|
| Python / CANN 泳道 | Host 侧在干什么:API 调用、下发是否密集 |
| Ascend Hardware(NPU 层) | 设备侧计算、通信任务的执行时序 |
| Communication(通信) | 通信事件与 Ascend Hardware 的通信子泳道一一对应 |
| Overlap Analysis(覆盖分析) | 把计算、通信任务垂直投影,得到计算、通信和空闲时间的拆分 |
| AI Core Freq | 是否降频(降频会导致该时间段性能必然下降) |
⭐ Overlap Analysis 是通信场景的"第一眼":它把"计算、通信、空闲"三者拆开, 是不是通信没被掩盖住,一眼就能看出来,不必先去逐个算通信算子。
4.6 第 5 步:用 Summary 定量,落到具体算子
定完方向,再用统计文件把它量化。官方两篇文档给了同一套看法:
| 文件 | 官方定义 | 怎么看 |
|---|---|---|
op_statistic_*.csv |
按算子类型聚合统计,(关键性概括)各类算子的调用总时间、总次数 | 按 Total Time(us) 降序排列,优先关注耗时占比高的算子类型 |
op_summary_*.csv |
记录每个算子任务的执行明细 | 按 Task Duration(us) 降序定位耗时较长的任务,再结合 Task Type 查看 AI Core 和 AI CPU 上的任务分布 |
⭐ 两个文件的区别一句话:
op_statistic是"按类型汇总"(哪一类贵);op_summary是"按任务明细"(哪一个贵)。 官方在快速入门里给的顺序也是这个:先看 statistic 定类型,再看 summary 定实例。
4.7 第 6 步:落到"是计算还是访存"——看 Kernel 明细的指标字段
这一层是 F4 与"看一眼就知道"的分水岭。官方《MindSpeed LLM · FSDP2》把字段给全了(需配置 aic_metrics=PipeUtilization 且 profiler_level >= Level1):
Cube(AI Core)算子重点看两个:
| 字段 | 含义 |
|---|---|
aic_mac_ratio |
MAC(矩阵乘加)单元耗时占比;高值表示计算密集型算子的计算资源利用率较高 |
aic_mte2_ratio |
MTE2(从 DDR/L2 读数据到 L1)耗时占比;高值可能表示内存带宽瓶颈 |
Vector(AI Vector Core)算子重点看两个:
| 字段 | 含义 |
|---|---|
aiv_vec_ratio |
Vector 单元占比;高值表示向量计算密集 |
aiv_mte2_ratio |
Vector MTE2 占比;高值可能表示内存带宽瓶颈 |
官方的判据原话(照抄):
通过分析 MAC/MTE2 占比,可以判断算子是计算 Bound 还是访存 Bound:MAC 占比高通常表示计算 Bound,MTE2 占比高通常表示访存 Bound。 对于 Cube 算子,期望
aic_mac_ratio较高、aic_mte2_ratio较低;对于 Vector 算子,期望aiv_vec_ratio较高、aiv_mte2_ratio较低。⭐ 这就是本课最值钱的一句判据:"计算还是访存"不用猜,看 MAC 与 MTE2 的占比对比即可。 另外还有一个直接字段
cube_utilization(%)(矩阵乘单元利用率),也可作参考。
4.8 第 7 步:只改一个瓶颈,然后用同一口径重测
官方给的是四类瓶颈的"推荐尝试顺序"(《MindSpeed LLM · FSDP2》"按瓶颈选择优化方向"表), 本课把它当作动手顺序的模板(注意:这些特性面向 MindSpeed LLM 训练,其他场景只借"顺序",不照搬特性名):
| 瓶颈类型 | 典型现象 | 推荐尝试顺序 | 官方点名的"不应优先做的事" |
|---|---|---|---|
| 计算瓶颈 | Attention、Norm、RoPE 等算子耗时高 | 模型专用融合 → Flash Attention → Fused RMSNorm/RoPE → MoE GroupedMatMul | 未确认热点算子就增加切分或卸载 |
| 显存瓶颈 | logits、激活、参数或优化器状态占用过高 | ChunkLoss → CP/EP 切分 → 激活重计算 → 异步激活卸载 → Swap Optimizer | 未区分显存来源就启用 offload 或 swap |
| 通信瓶颈 | 未掩盖通信时间过长 | FSDP 前向/反向预取 → fused dispatcher → EP MC2 → 检查并行组与拓扑 | 只调整并行度,不检查专家负载和通信重叠 |
| Host 下发瓶颈 | Device Free 时间偏高 | 任务队列 → CPU 绑核;小算子过多时同时评估计算类融合特性 | 通过 offload 引入更多 Host/Device 拷贝和调度 |
⚠️ 官方的一条硬提醒:除任务队列和 CPU 绑核外,其余特性均需要先针对模型完成相应的代码适配。 命令行或 YAML 参数只用于开启已适配的特性实现,不能代替模型代码适配。 —— 这句话直接否掉了"抄一串参数就能变快"的想法。
4.9 第 8 步:收口与出证据
- 改动前后各采一次,用同一口径(同样 step、同样 rank、同样采集等级)对比;
- 官方建议的观测项是端到端:step 耗时、Kernel 数量、峰值显存、精度结果一起看——官方原话是"启用后需对比端到端 step 耗时、Kernel 数量、峰值显存和精度结果,确认实际收益";
- 验收证据:改前/改后的两份 Profiling 目录 + 一页说明(改了什么、哪一类指标变了、变成了多少)。
4.10 第 9 步:诚实——哪些地方我要明说"官方没给"
一份可信的调优报告,一定包含"我不知道的部分":
| 我做不到的 | 为什么 |
|---|---|
| 给一个"利用率应该到多少"的通用红线 | 官方未给出通用阈值;只有场景级参考值(如 MindSpeed 的 Free < 3%、未掩盖通信 ≤10%),口径不同不能混用 |
| 给"调优后能提升几倍"的预测 | 官方未给出这类加速比数字,本课也不编 |
| 承诺"这套参数在你的模型上也有效" | 官方明说特性需先完成代码适配;换模型即换适配,需现场确认 |
| 告诉你在裸机上跑快速入门那套容器命令 | 官方快速入门仅支持标准化 CANN 容器;裸机路径需现场确认 |
第五段 怎么确认就位:可照抄的采集与分析命令
本节命令全部来自官方文档,逐条标注出处;每条给「含义 / 拆解 / 用法 / 期望 / 不过会怎样」五项。 命令用行内码书写,参数含义见方括号内说明。
命令 ① npu-smi info
命令 npu-smi info
含义:查 NPU 设备信息与利用率——这是采集前唯一的"零成本粗判" 拆解:
npu-smi(昇腾设备管理工具)+info(显示设备信息) 用法:直接敲;官方快速入门把它列为"硬件算力"前置条件的验证方法(确认 NPU 卡状态正常) 期望:一张表,列出每张卡的型号、温度、显存、进程等;官方《Rec SDK》口径:利用率很高则"很有可能就是 bound",多个推理并行时利用率超过 80%被认为很高 不过会怎样:命令不存在 → 驱动没装(回 A1);有输出但看不到卡 → 权限问题; ⚠️ 官方明确:这里显示的利用率只含 cube 核、不含 vector core,所以仅供参考,不能当结论——具体要用 profiling 里的 cycle 自行计算
命令 ② msprof --application="python3 ${HOME}/train.py" --output=${HOME}/prof_output
命令 msprof --application="python3 ${HOME}/train.py" --output=${HOME}/prof_output
含义:用 msProf 拉起训练脚本并一键完成采集与自动解析 拆解:
msprof(性能数据采集工具)+--application="..."(要被采样的用户程序及其参数)+--output=(性能数据存放路径) 用法:官方快速入门的写法;${HOME}/train.py换成你的脚本,${HOME}/prof_output换成你的输出目录 期望:屏幕打印[INFO] Start profiling....,训练日志正常输出,末尾出现[INFO] Profiling finished.与[INFO] Process profiling data complete. Data is saved in /home/prof_output/PROF_000001_...(后者表明数据已落盘) 不过会怎样:报Init platform by driver faild!→ 驱动库路径没进LD_LIBRARY_PATH,见第八段官方案例case_941011; 脚本提示"没有空闲 NPU" → 结束其他 NPU 任务或换空闲卡;超过 5 分钟不完成,可能是 NPU 异常或被抢占(官方提示)
命令 ③ msprof --output=/home/projects/output --ascendcl=on --runtime-api=on --task-time=on --aicpu=on --ai-core=on /home/projects/MyApp/out/main
命令 msprof --output=/home/projects/output --ascendcl=on --runtime-api=on --task-time=on --aicpu=on --ai-core=on /home/projects/MyApp/out/main
含义:按需打开若干采集开关,采一份较完整的 AI 任务运行性能数据(这条是官方"采集AI任务运行性能数据"章节的使用示例原文) 拆解:
--ascendcl(acl 接口性能数据,默认 on)+--runtime-api(Runtime API 数据,默认 off)+--task-time(算子下发耗时与算子执行耗时,涉及task_time、op_summary、op_statistic等文件)+--aicpu(AICPU 算子详细信息)+--ai-core(AI Core 数据采集开关)+ 末尾直接跟用户程序(官方推荐方式一) 用法:想采 AI Core 性能指标再加--aic-metrics=PipeUtilization(多数型号的默认值);只要更精准的耗时、不要算子基本信息,则把--task-time配成l0(官方:不采集算子基本信息数据,采集时性能开销较小) 期望:--output指定目录下生成PROF_XXX目录,内含自动解析后的性能数据; 目录通常有host/data、device_{id}/data、msprof_{时间戳}.db、mindstudio_profiler_output/不过会怎样:--aic-metrics用了某型号不支持的取值(如PipelineExecuteUtilization在 Atlas 推理系列/训练系列/A2/A3/950 上均标注"不支持")→ 采集项为空;--output路径含特殊字符(官方列了一串禁止字符,含%、>、<、|、&、$、;、反引号等)→ 落盘失败
命令 ④ msprof --export=on --output=/home/profiler_data/PROF_XXX
命令 msprof --export=on --output=/home/profiler_data/PROF_XXX
含义:解析并导出已有性能数据——官方明确"对于常规性能数据导出场景,建议优先使用
msprof --export=on,该命令为默认入口" 拆解:--export=on(解析并导出,默认 off)+--output=(须指定为PROF_XXX目录或它的父目录) 用法:默认导出 text(json + csv + db);只要一个汇总 db 文件给 MindStudio Insight 看,加--type=db(配db时仅支持--output,不支持其他参数);省空间加--clear=on(导出后删device_{id}下的 sqlite 目录) 期望:在PROF_XXX下生成mindstudio_profiler_output目录和msprof_*.db;mindstudio_profiler_output内含msprof_*.json、step_trace_*.json、一批*.csv和README.txt不过会怎样:报解析失败或文件无法落盘 → 磁盘或用户目录空间已满(官方"数据落盘约束"原文); 找不到命令 →msprof不在 PATH,回第 2 步查${INSTALL_DIR}/tools/profiler/bin; ⚠️ 官方权限约束:使用前请确保执行用户的umask ≥ 0027,且本工具不应使用 root 等高权限账户,建议普通用户执行;本工具为开发调测工具,不建议在生产环境使用
命令 ⑤ python3 msprof.py query -dir /home/profiler_data/PROF_XXX
命令 python3 msprof.py query -dir /home/profiler_data/PROF_XXX
含义:查询性能数据文件信息,拿到 iteration(Iteration ID)/ model(Model ID),便于后续只导出某一段 拆解:
msprof.py(msProf 解析工具的脚本封装,官方:"日常使用建议优先用msprof命令行入口;msprof.py主要用于脚本化集成")+query(查询)+-dir(必选,PROF_XXX目录或其父目录) 用法:执行前需先python3 msprof.py import -dir <dir>解析,否则查询结果无意义(官方注意事项); 脚本所在目录:${INSTALL_DIR}/tools/profiler/profiler_tool/analysis/msprof期望:屏幕打印表格,字段含 Job Info / Device ID / Dir Name / Collection Time / Model ID / Iteration Number / Top Time Iteration / Rank ID——其中Top Time Iteration是"耗时最长的 5 个迭代",这是选采样区间的直接依据 不过会怎样:没先import→ 查询结果无意义; 采样数据是单算子场景或只采了系统数据(没配--application)→ 官方明确 这些场景不支持--iteration-id和--model-id参数
命令 ⑥ python3 get_msprof_info.py -dir /home/1/PROF_000001_20220129014731273_KEDKPORHMAGPGD/device_0
命令 python3 get_msprof_info.py -dir /home/1/PROF_000001_20220129014731273_KEDKPORHMAGPGD/device_0
含义:从已采集的 Profiling 数据里回查设备信息——用来确认"这份数据是哪台设备、什么版本、采了多少迭代" 拆解:
get_msprof_info.py(官方脚本,路径.../analysis/interface)+-dir(必选:非集群场景须指定为PROF_XXX下的host或device_{id}目录;集群场景须指定为PROF_XXX的父目录) 用法:集群场景-dir指到父目录,结果会生成/query/cluster_info.json期望:非集群场景直接打印字段,含AI Core Number、AI CPU Number、Control CPU Number、Host CPU 信息,以及version_info(analysis_version/collection_version/drv_version驱动版本);集群场景生成cluster_info.json(含Rank Id/Prof Id/Models) 不过会怎样:-dir指到了PROF_XXX根目录 → 非集群场景取不到(官方要求指到host或device_{id}); 报路径不存在 → 该目录不存在或根本没采到对应侧数据
命令 ⑦ msprof-analyze advisor all -d /path/to/profiling_data/
命令 msprof-analyze advisor all -d /path/to/profiling_data/
含义:自动分析性能数据并输出调优建议——官方 msprof-analyze 的"专家建议(advisor)"功能 拆解:
advisor(子命令,含all/computation/schedule三个)+-d(必选,性能数据目录)+ 可选-o(输出目录)、-bp(基准数据,computation和schedule不支持)、-l en(英文)、--force(跳过属主与文件大小限制) 用法:不确定瓶颈来源就用all;重点查 AICPU、动态 Shape、Block Dim、算子瓶颈、融合算子图、AI Core 降频 → 用computation;重点查 GC、亲和 API、aclopCompile、SyncBatchNorm、流同步 → 用schedule期望:在当前目录(或-o指定目录)保存分析结果,覆盖 Overall Summary(计算/通信/空闲维度拆解)、环境变量设置推荐、slow rank 慢卡、slow link 慢链路、通信小包检测、字节对齐检测、内存申请释放异常 等功能点 不过会怎样:⚠️ 官方两条约束必看——CANN 8.0RC1 之前仅支持 text 格式文件分析,8.0RC1 及之后支持 text 和 db; Ascend 950 系列产品的 CCU 场景下不支持采集通信矩阵和通信算子带宽数据,因此该工具 slow rank / slow link / communication 的分析功能不具参考意义
命令 ⑧ export TASK_QUEUE_ENABLE=2
命令 export TASK_QUEUE_ENABLE=2
含义:Host 下发瓶颈的标准优化手段(官方:将任务异步下发到 Device,提升 Host/Device 并行度) 拆解:
TASK_QUEUE_ENABLE是 TorchNPU 侧环境变量,取值2为官方在"Host 下发瓶颈"场景给出的配置 用法:官方给的启用前置条件是"Host Bound 明显时"——即先确认Free时间占比偏高(Device 在等下发),再开 期望:作用在下一轮训练/推理里,表现为 Device Free 时间下降、Host 与 Device 并行度提高 不过会怎样:⚠️ 两个官方明说的副作用—— ①ASCEND_LAUNCH_BLOCKING=1会强制关闭任务队列,使本配置失效; ②TASK_QUEUE_ENABLE=2会提高内存访问并发度,可能增加运行期间的 NPU 峰值显存(峰值显存本就是官方要一起观测的指标之一)
命令 ⑨ export CPU_AFFINITY_CONF=2
命令 export CPU_AFFINITY_CONF=2
含义:配置 CPU 亲和性(绑核),减少线程迁移与跨 NUMA 访问,提高下发稳定性 拆解:取值
0/未配置 = 禁用绑核;1= 粗粒度绑核(把单张 NPU 关联的所有线程绑到指定 CPU 核心区间);2= 细粒度绑核(把主要线程分别绑到独立 CPU 核);扩展写法npu0:0-1,npu1:2-5(仅在mode不为 0 时生效) 用法:官方给了三种示例——export CPU_AFFINITY_CONF=1(粗粒度)、=2(细粒度)、=1,npu0:0-1,npu1:2-5,npu3:6-6(自定义) 期望:作用在下一轮运行;适用场景是官方列的"任务调度能力不足、跨 NUMA 访问或快慢卡问题突出" 不过会怎样:⚠️ 官方约束原话——"需结合服务器 CPU 拓扑设置;错误绑核可能降低性能"; 所以先查清本机 CPU 拓扑再绑,不要照抄示例里的核号
⭐ 命令 ⑩(预览用,不在产线跑):chrome://tracing
命令 chrome://tracing
含义:官方指定的 Timeline 打开方式(在 Chrome 地址栏输入,再把
msprof_*.json拖进去) 拆解:不是 shell 命令,是浏览器内部页;官方另给快捷键:w放大、s缩小、a左移、d右移 用法:打开后开启 Flow events 下的选项,可用连线查看"应用层算子 → NPU 算子"的下发到执行对应关系(官方列的对应关系有async_npu、MsTx、async_task_queue、HostToDevice、fwdbwd) 期望:看到 timeline 分层:应用层 / CANN 层(Runtime 与 Node)/ 底层 NPU(Ascend Hardware 各 Stream、Communication、Overlap Analysis);点色块看详细信息 不过会怎样:文件太大打不开 → 官方提供性能数据文件分片(msprof_slice.json,slice_switch默认off); 注意官方限制:开启分片且文件 > 20GB 会导出失败;文件 < 200MB 不触发分片; 大文件更推荐直接用 MindStudio Insight 打开
第六段 判据:怎么算"看懂了数据"
⚠️ 先看这一行:下列阈值全部是"场景级参考值",不是通用红线。 每条都标了来源与口径。 官方未给出跨场景通用的"性能达标线"——通用阈值官方未给出,需现场建基线。
6.1 平台级参考值(来源:MindSpeed LLM 26.1.0《FSDP2 后端模型性能优化指南》)
| 关键路径项目 | 官方参考范围 | 官方"需要关注" | 官方给的常见原因 |
|---|---|---|---|
| 未掩盖通信 | ≤ 10% |
> 20% |
all-gather / reduce-scatter / all-to-all / send-recv 无法被计算掩盖 |
| Free 时间 | < 3% |
≥ 3% |
Host 下发慢、CPU 争用、频繁小算子、同步 API 或线程配置不当 |
| 计算 | 通常是主要部分 | 利用率低且空隙多 | 未使用融合算子、shape 不友好、负载过小、专家不均衡 |
口径提醒(很重要):这一整张表来自 MindSpeed LLM 的 FSDP2 分布式训练场景, 官方原文还专门声明"本文不适用于在线推理、KV Cache、推理量化和服务化调度;推理性能不能直接套用本文的指标和结论"。 所以要把它当"方法与量级",不当"拿来即用的红线"。
6.2 算子级参考值(来源:Rec SDK 26.1.0《性能调优》)
| 判据 | 官方口径 |
|---|---|
| 访存 bound 初判 | 直接看 aiv_mte2_ratio 字段是否超过 0.8;"如果有大量超过 0.8 的算子出现,则这一部分是需要进行优化的" |
| 非对齐导致带宽低 | 排查搬运数据量是否非 32 byte 对齐,"非对齐场景也会导致带宽低" |
| Cube 利用率手算公式 | 利用率 = CUBE 总 cycle 数 ÷ (总耗时(s) × AI Core 数 × 频率(MHz) × 10⁶) |
| 公式的拆解(官方给的一例) | aic_total_cycles 求和得总 cycle;总耗时取按 start time 排序后首尾时间戳之差(单位 us,除以 10⁶ 换成秒);示例芯片的 AI Core 数为 20、频率 1650 MHz;官方在该例中算出的 Cube 整体利用率为 78.9% |
| 谁占大头 | 各流程占比"直接用时间可以算出来";官方例子:mte2 耗时占比为 ai_core 总耗时的 70.18%,据此推断"ai_core 上的耗时内存搬入占大头" |
⚠️ 公式里的"AI Core 数"和"频率"是随芯片变的(官方示例用的是 20 与 1650)—— 具体到你的卡是多少,官方未在该处给出,需现场确认(可用命令 ⑥ 的
get_msprof_info.py看AI Core Number)。
6.3 通信/链路级参考值(来源:CANN 9.2.0-beta.2《性能调优工具 · 扩展功能》)
| 指标 | 官方定义 / 阈值 |
|---|---|
| 等待时长比例 Wait Time Ratio | 等待时长 / (等待时长 + 通信时长);官方给的建议判据:一个迭代内是否存在该比例 > 阈值 0.2 的卡 |
| 传输前同步时长比例 | 传输前同步时长 / (传输前同步时长 + 通信时长);大于 0.2 时怀疑存在慢卡 |
| 带宽使用率 | 大于 0.8 说明带宽使用正常,全网链路无瓶颈 |
| 通信包比例 | 大于 0.8 说明通信包尺寸无异常;若通信包尺寸过小,则"每次通信传输的包太小,导致带宽使用率不高,存在带宽的瓶颈" |
| 慢链路输出条件 | 链路带宽小于平均带宽 20% 时输出最慢链路相关信息 |
6.4 采集/环境级判据(自查用)
| 项 | 判据 |
|---|---|
| 采集完成 | 屏幕出现 [INFO] Profiling finished. 且打印了 Data is saved in .../PROF_XXX |
| 数据可解析 | PROF_XXX 下已生成 mindstudio_profiler_output 与 msprof_*.db(或经 --export=on 生成) |
| AI Core 指标存在 | 采到了 aic_* / aiv_* 字段 且 不是全 0 —— 全 0 或缺失见第八段 profilingcase_002 |
| 采集没把现象改掉 | 对比开/关采集时的 step 耗时差值(膨胀),官方案例 profilingcase_007 的判别口径 |
第七段 出问题怎么查
排查原则:先分"采不到"和"看不懂"两类,再往下查。
采不到(数据链) ── 采不到数据 / 采到了但缺项 / 解析失败 / 文件过期
看不懂(分析链) ── 采到了、也能解析,但判断不出瓶颈属于哪一类
7.1 先看现象 → 先查什么(排查顺序)
| 现象 | 大概是什么 | 先查什么 |
|---|---|---|
msprof 一拉起就报 Init platform by driver faild! |
驱动库没进环境 | echo $LD_LIBRARY_PATH 看有没有驱动目录(第八段 case_941011) |
| 屏幕上显示解析数据,但没有 AI Core Metrics | 采集开关的下发时机被代码顺序破坏了 | 看 Host 侧日志 $HOME/ascend/log/plog;检查代码里 aclInit 是否在 aclrtSetDevice 之前(第八段 profilingcase_002) |
有 PROF_XXX 但没法解析 |
数据被"老化"删了 | 看是否配了 --storage-limit 或磁盘快满(第八段 topic_0000001538203562) |
| 解析后文件异常,缺 modelid 或 iterid | 解析参数/版本问题 | 官方案例 case_941012(第八段) |
| Timeline 打开卡到打不开 | 文件太大 | 用 msprof_slice.json 分片,或改用 MindStudio Insight;注意官方限制:>20GB 导出失败、<200MB 不触发分片 |
| 开了采集后模型本身变慢 | 性能膨胀,正常现象 | 看 with_stack 是否开着(官方:性能影响巨大,可用 with_modules 替代)、profiler_level 是否过高 |
| NPU 没跑满,看不出 bound | 压力不够 | 官方建议:先构造压力打满的场景(如本地压测脚本、多流大压力跑本模型),再分析瓶颈 |
| 设备侧有大段空隙 | Host 下发瓶颈 | 看 Free 占比(>3% 看第八段优化方向);查 HostToDevice 连线是否密集且接近垂直、CPU 绑核与争用、小算子数量、同步调用 |
| 某个算子耗时异常高 | 计算瓶颈,但先别急着融合 | 看 aic_mac_ratio vs aic_mte2_ratio:MAC 高 = 计算 bound;MTE2 高 = 访存 bound |
| 多卡时个别卡拖慢整体 | 慢卡 / 慢链路 | 用 msprof-analyze advisor 的 slow rank / slow link;手工看 Wait Time Ratio > 0.2 |
| 结果对不上但"也能跑" | 这一般不是性能问题 | 回 F2 精度调试 |
7.2 按"瓶颈类型"排的排查顺序(分析链)
① 先量 Free(设备空闲)
├─ Free 高(≥3%) → Host 下发瓶颈 → 命令 ⑧/⑨,并查小算子与同步调用
└─ Free 低
├─ ② 再看 Overlap Analysis:通信有没有被掩盖
│ ├─ 未掩盖通信高 → 通信瓶颈 → 查通信泳道带宽、慢卡、慢链路
│ └─ 通信没问题
│ └─ ③ 最后看算子:MAC 与 MTE2 谁占比高
│ ├─ MAC 高 → 计算 bound → 融合 / 类型 / 图优化
│ └─ MTE2 高 → 访存 bound → 对齐、融合、减搬运
└─ ④ 若始终看不出 bound → 压力可能不够,先打满再分析
⚠️ 一条判断法(本课自用,非官方表述): "先看等着的时间,再看忙着的算力。" 设备大量在等 → 优化算力没用;设备确实在忙 → 才轮到谈算子怎么优化。
7.3 慢的时候,还有一个最容易漏的检查:是不是设备在降频
官方《性能数据文件参考》专门讲了 AI Core Freq 层级:
在 148089.72045898438 时刻下,AI Core 处于高频状态,而在 170178.44116210938 时刻频率降低,那么在该时间段下 AI 任务的性能必然下降。 AI Core 芯片可能因温度升高,触发保护机制,降低频率;也可能因当前无 AI 任务运行,AI Core 进入低功耗状态而降频。
并且官方给了一个精度提醒:
在发生变频时,实际变频时间与软件监测到的时间存在 0~1ms 的延时,该延时可能导致变频前后统计出的算子执行时间与实际不符。
⭐ 这条的价值:如果你发现"计时的口径和实际观感对不上",先排除变频与时间同步误差,不要一口咬定是算子的问题。 官方在 Flow events 那节也提示过:由于软件测量的频率与真实频率有误差、Host 与 Device 有时间同步误差,可能出现下层算子因错位而无法连线。
第八段 常见报错清单
检索口径(沿袭 E1):到官方案例库
https://www.hiascend.com/document/caselibrary按报错里的稳定特征词检索, 不要按"性能调优"这种泛词检索。下表里的案例编号均为官方真实编号,另附浏览量供参考。
| 报错 / 现象 | 官方案例编号 | 查看量 | 根因与做法(官方原文口径) |
|---|---|---|---|
msprof 拉起应用失败:Init platform by driver faild! |
case_941011 |
914 | 未添加驱动环境变量至 LD_LIBRARY_PATH;先 echo $LD_LIBRARY_PATH 排查,再补 export LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH |
| 执行 msprof 后未采集到 AI Core Metrics 数据 | profilingcase_002 |
880 | 代码里aclInit 调在 aclrtSetDevice 之后,导致 Runtime 无法下发 AI Core 性能数据采集开关任务;调整代码使 aclInit 最先调用后重编重采 |
| Profiling 数据老化导致无法正常解析数据 | topic_0000001538203562 |
792 | 数据超过 storage_limit 限定值或剩余磁盘空间较小时,工具会自动老化删除最早的 Profiling 数据;采集前先看清盘 |
| msprof 解析后输出文件异常,缺少 modelid 或 iterid | case_941012 |
1197 | 官方案例:解析后文件缺 modelid/iterid;按该案例步骤处理 |
| PyTorch 场景如何采集最小膨胀数据(开采集后 step 变慢) | profilingcase_007 |
1373 | 官方给出"推荐配置"与"最小膨胀配置"两套 Profiler 写法;影响膨胀的因素按程度排序:with_stack(性能影响巨大,可用 with_modules 替代)> profiler_level > activities > 其余采集开关 |
| Profiling 里出现 format 为 NHWC 的算子且性能较低 | topic_0000001539375010 |
756 | 官方案例:NHWC 算子性能较低;结合格式转换类分析(可参考官方优化案例中的 TransData 占比高处理方向) |
网络调测时 ReduceSum 算子性能差 |
topic_0000001261263136 |
980 | 官方定位口径:Profiling 里看该算子block_dim 字段值为 1,说明该算子未开启多核并行计算 |
| AI Core 算子执行时间超时导致网络运行失败 | topic_0000001308583121 |
1404 | 执行模型推理时返回模型执行失败,Device 侧日志有 ERROR 级别打印;按官方案例定位(注意这是"跑失败"不是"跑得慢",别混为一类) |
| 部署 DeepSeek 服务化,性能不佳 | topic_0000002193154190 |
7969 | 拉起后实测性能较差,与预期差异较大;这是服务化场景,与本课单机性能分析口径不同,注意区分 |
装了 --sys-hardware-mem 采集 memory 数据可能触发 glibc 已知 Bug |
官方文档明示(非案例编号) | — | 官方原文:在 glibc < 2.34 的环境上采集 memory 数据,可能触发 glibc 的已知 Bug 19329,通过升级环境的 glibc 版本可解决 |
⚠️ 两条本课要明说的"没有答案":
- 没有"Profiling 采集一次固定花多长时间"的官方数字——采集开销与采集项、模型、硬件有关,官方未给出,只能用"开关采集前后各测一次 step 耗时取差值"的办法现场量化。
- 没有"什么利用率算合格"的通用官方红线——官方给的都是场景级参考(见第六段),通用阈值官方未给出。
第九段 小结与下一课
这一课要带走的三句话:
- 默认不采——"跑得慢"这件事,不主动打开 Profiling,屏幕上什么证据都不会有; 性能调优的第一个动作永远是采,不是猜。
- 先看等着的时间,再看忙着的算力——
Free时间与Overlap Analysis告诉你设备在等谁; 确认设备真在忙,才轮到用aic_mac_ratio/aic_mte2_ratio分"计算还是访存"。 - 阈值要带出处——
Free < 3%、未掩盖通信≤10%来自 MindSpeed LLM 的 FSDP2 场景,aiv_mte2_ratio > 0.8来自 Rec SDK;通用红线官方未给出,要自己建基线。
一次完整排查的动作顺序(串联本课):
对齐口径(时延/QPS/吞吐/step 耗时 + batchsize + 数据类型)
→ npu-smi info 粗判设备忙不忙
→ 确认环境采得动(卡/驱动/工具路径/磁盘)
→ 采最小的一份(少量 step、少量 rank)
→ Timeline 先看间隙(Free / Overlap Analysis)
→ Summary 定量(op_statistic 定类型 → op_summary 定实例)
→ 定一个主瓶颈(计算/访存/通信/下发/显存)
→ 改一处 → 同口径重测 → 出证据
→ 官方没给的,明说"这是我建的基线"
下一课预告(F5): 到这里,迁移(F1)、精度(F2)、多卡(F3)、性能(F4)四件"单场景"的能力都齐了。 F5 把零件串成一条完整链路:从单卡推理这一件事出发,把"装好 → 跑通 → 结果对 → 性能达标 → 交出证据" 整条链路完整走一遍——那是 F 层把前面几层真正"用起来"的一课。
附录 A · 本课引用的官方出处
| 内容 | 来源文档(版本) |
|---|---|
msProf 是什么、快速入门五步、前置条件表、容器的适用范围声明、msprof --application= 示例与 [INFO] 输出、PROF_XXX 目录结构、op_statistic / op_summary 的"分析方法举例" |
《msProf 模型调优工具 · 快速入门》(CANN 9.2.0-beta.2 · 调试与分析工具 · 性能调优工具) |
msprof [options] <app> 两种方式、--output / --type / --environment / --storage-limit、路径禁止字符列表 |
《msprof采集通用命令》(同上) |
--ascendcl / --runtime-api / --task-time(l0/l1/l2/l3/on/off) / --aicpu / --ai-core / --aic-mode / --aic-metrics(含各取值与型号支持表、默认值 PipeUtilization)/ --sys-hardware-mem / --l2 / --ge-api / --task-memory / --task-block、完整采集示例 |
《采集AI任务运行性能数据》(同上) |
msprof --export=on 为推荐入口、msprof.py 的 import/query/export、get_msprof_info.py、设备信息字段表、性能数据文件分片(msprof_slice.json)、权限/落盘/兼容性约束、工具路径 |
《msProf解析工具》+《扩展功能》(同上) |
Timeline 四区域、chrome://tracing、Flow events 连线关系(async_npu / MsTx / async_task_queue / HostToDevice / fwdbwd)、AI Core Freq 与 0~1ms 变频延时、SIO、QoS、分片限制 |
《性能数据文件参考》(同上) |
| 性能调优建议(通信耗时分析、Wait Time Ratio > 0.2、带宽使用率 > 0.8、通信包比例 > 0.8、慢链路 < 平均带宽 20%) | 《扩展功能 · 性能调优建议》(同上,官方注明该功能已不再演进,改用 msprof-analyze) |
推理场景"采集&解析性能数据"、默认采集文件表、json/csv 打开方式、按 Total Time / Task Duration 排序的分析法 |
《模型推理性能调优建议 · 采集&解析性能数据》(CANN 9.2.0-beta.2) |
msprof-analyze advisor 三个子命令、速查表、参数(-d / -bp / -o / -l / --force / -cv / -tv / -pt)、完整功能点表、两条约束 |
《msprof-analyze · 专家建议》(MindStudio 26.1.0) |
单 step 时间三分解、核心指标(step 耗时 / tokens/s / MFU / 峰值显存)、关注项与参考范围(未掩盖通信 ≤10%/>20%、Free <3%/≥3%)、采集等级 Level0/Level1、性能数据文件清单、Timeline 泳道表、op_statistic.csv 与 kernel_details.csv 字段定义、AI Core / AI Vector 指标与判据、四类瓶颈的推荐顺序与特性表、TASK_QUEUE_ENABLE=2、CPU_AFFINITY_CONF、显存瓶颈、常见优化案例(TransData、冗余代码、allow_internal_format) |
《MindSpeed LLM · FSDP2 后端模型性能优化指南》(MindSpeed 26.1.0) |
性能调优流程与需对齐指标(时延 / batchsize / QPS=请求数÷秒 / 吞吐量=QPS×batchsize / 数据类型)、npu-smi info 利用率粗判与"不含 vector core"的口径、Cube 利用率计算公式与 78.9% 示例、mte2 占比 70.18%、aiv_mte2_ratio > 0.8、非 32 byte 对齐、cube/vector bound 优化手段、访存/Pcie 分析方向、案例分享 |
《Rec SDK · 性能调优》(MindSDK 26.1.0) |
案例 case_941011、profilingcase_002、profilingcase_007、case_941012、topic_0000001538203562、topic_0000001539375010、topic_0000001261263136、topic_0000001308583121、topic_0000002193154190 |
官网 案例库(https://www.hiascend.com/document/caselibrary/detail/<案例编号>) |
| 默认不采集 Profiling、借助 Profiling"准确定位系统的软、硬件性能瓶颈" | 《Profiling数据采集与分析》(TensorFlow 商用版 9.0.0;含 TensorFlow / Keras / Estimator / sess.run 与"环境变量方式"的采集写法) |
本课未写的东西(数据纪律:官方未给出,故不编)
- 任何加速比 / 提升倍数 / 耗时绝对值——官方文档未给出可迁移的数字,本课一个都不编。
- 通用"性能达标线"——官方只有场景级参考值(第六段已逐条标注来源与口径),通用阈值官方未给出。
aic_metrics的通用最优取值——官方给的是"默认值 + 各型号支持情况"表;选哪个取决于你要查什么(本课给的是选择依据,不是推荐值)。- Profiling 采集的固定耗时/膨胀比例——官方未给数字,只给"影响膨胀的因素排序"。
- Cube 利用率公式里各芯片的 AI Core 数与频率——官方示例用的是 20 与 1650,你的卡是多少需现场确认。
- 裸机/虚拟机场景下的完整采集流程——官方《msProf 快速入门》明确仅支持标准化 CANN 容器;裸机路径须按主文档逐条确认。
附录 B · 命令与代码逐条详解
B.1 msprof 的两种调用方式(官方原文)
| 方式 | 写法 | 官方说明 |
|---|---|---|
| 方式一(推荐) | msprof [options] <app> |
在 msprof 命令末尾直接传入用户程序或执行脚本 |
| 方式二 | msprof [options] --application=<app> |
通过 --application 参数传入 |
官方给的一条重要提醒:
若 parameter 中存在异常符号时将无法识别参数,因此推荐使用方式一传入用户程序。 使用方式一时,若配置的用户程序命令中存在配置参数值需要加引号的情况, 请将命令写入 Shell 脚本后,通过执行 Shell 脚本的方式在 msprof 命令上添加用户程序命令。
⭐ 实践含义:命令里参数带引号、带空格、带重定向 → 先写成
.sh,再让 msprof 跑这个脚本,别硬塞。
B.2 采集侧关键参数速查
| 参数 | 取值 | 官方要点 |
|---|---|---|
--output |
路径 | 优先级高于 ASCEND_WORK_PATH;路径不能含特殊字符(官方列了一长串:换行、%、>、<、|、&、$、;、反引号等) |
--type |
text(默认)/ db |
text = 解析出 json、csv 和 db;db = 只出一个汇总 .db,配 db 时仅支持 --output |
--environment |
"K=V;K2=V2" |
采集时需要的自定义环境变量 |
--storage-limit |
[200, 4294967295] MB,如 200MB |
到限或剩余总空间 ≤20MB 时,老化删除最早的文件;未配置时,采集前若可用空间 < 20MB 则不落盘 |
--task-time |
l0 / l1 / l2 / l3 / on(=l1,默认)/ off |
采"算子下发耗时 + 算子执行耗时";l0 不采算子基本信息,开销较小、耗时更精准;l1/l2 支持采集集合通信算子数据;l3 为试用特性,不支持用于生产 |
--ai-core |
on / off |
默认值随 --task-time 变:on/l1 时默认 on;off/l0 时默认 off |
--aic-mode |
task-based(默认)/ sample-based |
采集粒度;前提是 --ai-core=on;官方建议 AI 任务场景用 task-based |
--aic-metrics |
见 B.3 | 前提是 --ai-core=on |
--sys-hardware-mem |
on / off(默认 off) |
片上内存读写速率、QoS 带宽、LLC 三级缓存带宽、加速器带宽、SoC 传输带宽、组件内存占用;不同型号采集内容略有差异 |
--sys-hardware-mem-freq |
[1,100] Hz,默认 50 |
前提是 --sys-hardware-mem=on;⚠️ 官方:A2 / A3 / 200I·500 A2 采集结束后不建议改频率,否则可能丢数据 |
--l2 |
on / off |
L2 Cache、TLB 页表缓存命中率;aclgraph 场景执行模型阶段开启则不生效;A2/A3 分析 AI Core 命中 L2 官方推荐用 --aic-metrics=L2Cache |
--ge-api |
off(默认)/ l0 / l1 |
采动态 Shape 算子在 Host 调度阶段的耗时 |
--task-memory |
on / off |
CANN 算子级内存占用,用于优化内存使用 |
B.3 --aic-metrics 的取值(这一项直接决定你能看到哪些指标)
| 取值 | 采什么 |
|---|---|
ArithmeticUtilization |
计算类指令耗时占比 |
PipeUtilization |
计算类和搬运类指令耗时和占比(多数型号的默认值) |
Memory |
内存读写带宽速率 |
MemoryL0 / MemoryUB |
L0 / UB 读写带宽速率 |
ResourceConflictRatio |
资源冲突占比 |
L2Cache |
L2 Cache 命中率 |
PipelineExecuteUtilization |
计算类和搬运类指令耗时和占比(⚠️ Atlas 推理系列 / 训练系列 / A2 / A3 / Ascend 950PR·950DT 均标注"不支持") |
MemoryAccess |
⚠️ Atlas 200I·500 A2 / Atlas 推理系列 / Atlas 训练系列 / Ascend 950PR·950DT 均标注"不支持" |
Custom:0x..,0x.. |
自定义 PMU 寄存器;最多 8 个,范围 [0x1, 0x7FFFFFFF];无对应寄存器的值采集结果可能为 0 |
B.4 为什么 kernel_details.csv 里那些 aic_* / aiv_* 字段看不到
官方写明:这些字段需配置 aic_metrics=PipeUtilization 且 profiler_level >= Level1。
两条不满足任一条,指标列就是空的——这跟"采到了但没用"不是一回事。
B.5 采集等级与"能看哪些界面"(MindSpeed LLM 口径)
| 采集等级 | 生成的额外文件 | 能看的界面 | 官方说明 |
|---|---|---|---|
ProfilerLevel.Level0 |
trace_view.json、msprof_*.json、operator_details.csv、kernel_details.csv(无 AI Core 性能指标)、memory_record.csv、operator_memory.csv |
时间线、内存、算子 | 基础级别,不采通信数据和 AI Core 性能指标 |
ProfilerLevel.Level1 |
Level0 全部 + communication.json、communication_matrix.json、kernel_details.csv(含 AI Core 性能指标) |
Level0 全部 + 概览(Summary)、通信 | 中等级别,额外采通信数据和 AI Core 性能指标 |
⭐ 一句话记法:要看"计算还是访存",至少 Level1 + PipeUtilization。 只想看时序和算子耗时,Level0 更省开销。
B.6 op_statistic.csv 字段("哪一类贵")
| 字段 | 含义 |
|---|---|
Device_id |
设备 ID |
Model Name |
模型名称(默认或单算子场景可能不显示) |
OP Type |
算子类型 |
Core Type |
Core 类型:AI_CORE / AI_VECTOR_CORE / AI_CPU 等 |
Count |
算子调用次数 |
Total Time(us) |
算子调用总耗时(us)——按它降序就是分析入口 |
Avg Time(us) / Min Time(us) / Max Time(us) |
平均 / 最小 / 最大耗时(us) |
B.7 kernel_details.csv 关键字段("哪一个贵、贵在算还是搬")
| 字段 | 说明 |
|---|---|
Name / Type |
算子名称 / 算子类型(如 Conv2D、MatMulV2、TransData) |
Accelerator Core |
加速器核心:AI_CORE / AI_VECTOR_CORE / DSA_SQE / MIX_AIV |
Start Time(μs) / Duration(μs) / Wait Time(μs) |
开始时间 / 持续时间 / 等待时间(通信场景的 Wait Time Ratio 就取它) |
Input/Output Shapes、Input/Output Data Types、Input/Output Formats |
形状 / 数据类型 / 数据格式(如 NCHW、NC1HWC0、FRACTAL_Z、FORMAT_ND) |
aicore_time(μs)、aic_total_cycles、aic_mac_time(μs)、aic_mac_ratio、aic_scalar_ratio、aic_mte1_ratio、aic_mte2_ratio、aic_fixpipe_ratio、aic_icache_miss_rate |
AI Core(Cube)侧指标 |
aiv_time(μs)、aiv_total_cycles、aiv_vec_time(μs)、aiv_vec_ratio、aiv_scalar_ratio、aiv_mte2_ratio、aiv_mte3_ratio、aiv_icache_miss_rate、cube_utilization(%) |
AI Vector 侧指标 |
每个 _ratio 的本质都是同一个式子:该单元耗时 ÷ 总耗时。所以看 _ratio 就是看时间被谁吃掉了。
B.8 官方给的一段可直接照抄的 Profiler 采集配置(案例 profilingcase_007)
官方原话:该配置用于"采集性能数据推荐配置——使用推荐配置可获取一般性能分析问题所需的 Host 和 Device 侧数据"。
experimental_config = torch_npu.profiler._ExperimentalConfig(
export_type=torch_npu.profiler.ExportType.Text,
aic_metrics=torch_npu.profiler.AiCMetrics.PipeUtilization,
profiler_level=torch_npu.profiler.ProfilerLevel.Level1,
l2_cache=False,
data_simplification=False
)
with torch_npu.profiler.profile(
activities=[
torch_npu.profiler.ProfilerActivity.CPU,
torch_npu.profiler.ProfilerActivity.NPU
],
schedule=torch_npu.profiler.schedule(wait=1, warmup=1, active=2, repeat=2, skip_first=10),
on_trace_ready=torch_npu.profiler.tensorboard_trace_handler("./result"),
experimental_config=experimental_config) as prof:
for step in range(steps):
train_one_step(step, steps, train_loader, model, optimizer, criterion)
prof.step()
同一案例给的"最小膨胀"配置(官方用途:一般用于和 GPU 性能数据对比使用):
with torch_npu.profiler.profile(
activities=[torch_npu.profiler.ProfilerActivity.NPU],
schedule=torch_npu.profiler.schedule(wait=1, warmup=1, active=1, repeat=1, skip_first=20),
on_trace_ready=torch_npu.profiler.tensorboard_trace_handler("./npu-profling-least-inflation")
) as prof:
for step, x in enumerate(train_dataloader): # train_one_step
...
prof.step()
两段的差别值得琢磨:最小膨胀那段只采集 NPU 一个 activity、
active=1 repeat=1; 官方给的影响膨胀的因素排序第一位是with_stack(性能影响巨大,可用with_modules替代)—— 所以"对比 GPU"就用最小膨胀配置,"查瓶颈"才上推荐配置,两者目的不同,不要混用。
B.9 训练场景 Profiler 的步数与 rank 控制(MindSpeed LLM)
| 参数 | 官方示例值 | 作用 |
|---|---|---|
--training.profile_step_start / profile_step_end |
5 / 6 |
采集区间是左闭右开 [start, end) |
--training.profile_ranks |
0 |
采哪些 rank;首轮只采 0 号 |
--training.profile_level |
level1 |
采集等级(见 B.5) |
--training.profile_with_cpu |
true |
同时采 CPU 与 NPU |
--training.profile_with_stack |
true |
定位热点算子的代码位置用;增加开销与体积 |
--training.profile_with_memory |
true |
分析算子显存申请用 |
--training.profile_record_shapes |
true |
记录 shape(深采才加) |
--training.profile_save_path |
./profile_fsdp2_rank0 |
落盘路径 |
官方提醒:确认通信或慢 rank 问题后,再选择少量代表 rank 或所有 rank;深采的三个开关会增加采集开销和结果体积。
B.10 落盘约束与安全提示(官方原文,采集前必读)
- 权限:执行用户
umask ≥ 0027;不应使用 root 等高权限账户,建议普通用户;为开发调测工具,不建议在生产环境使用;性能数据应保存在不含软链接的当前用户目录下。 - 落盘:解析过程中若落盘路径磁盘或用户目录空间已满,会解析失败或文件无法落盘。
- 版本:工具支持 Python 3.7.5 及以上;如需复现快速入门样例,建议 Python 3.9 及以上。
- 路径:需要指定路径的参数,不得包含特殊字符(官方列了完整清单)。