ops-simulator
NPU 仿真器技能。提供 CANN Simulator 的使用指导,包括精度仿真、性能仿真、流水线分析。当需要在无 NPU 硬件环境下验证算子功能、分析性能瓶颈、定位精度问题时使用。也用于分析已有的 npusim 性能报告(summary.json)并给出优化建议。
Files14
View on GitHubSKILL.mdops/ops-simulator/SKILL.md
GitHubNPU 仿真器使用指南
概述
CANN Simulator 是一款面向算子开发场景的 SoC 级芯片仿真工具,通过 npusim 命令行工具提供以下能力:
Note: Starting from CANN 9.2.0, the command-line tool has been renamed from
cannsimtonpusim. The oldcannsimcommand still works but is deprecated. Output directories and log files are also renamed (npusim_*/npusim.loginstead ofcannsim_*/cannsim.log). This skill usesnpusimin all examples.
- 精度仿真:输出 bit 级精度结果,协助算子精度验证
- 性能仿真:输出指令流水图,协助定位性能瓶颈
npusim 主命令
npusim 是性能仿真分析的命令行入口,提供两个子命令:
| 子命令 | 功能 | 说明 |
|---|---|---|
npusim record |
执行仿真 | 在仿真环境中运行用户程序,记录仿真数据 |
npusim report |
生成报告 | 基于仿真结果生成性能分析报告和流水线图 |
使用方式:npusim <子命令> [选项]
适用场景
| 场景 | 说明 |
|---|---|
| 无 NPU 硬件环境 | 在没有真实 NPU 硬件的情况下进行算子开发 |
| 精度验证 | 需要 bit 级精度验证的场景 |
| 性能调优 | 需要分析指令流水、定位性能瓶颈 |
| 资源受限 | 芯片资源紧缺时的替代验证方案 |
使用约束
| 约束项 | 说明 |
|---|---|
| 芯片限制 | 仅支持 Ascend 950 芯片架构 |
| 单卡场景 | 仅支持单卡,代码中只能设置为 0 卡 |
| 算子类型 | 仅支持 AI Core 计算类算子(不支持 MC2/HCCL) |
| 架构限制 | 支持 X86,ARM |
使用步骤
1. 执行仿真
# 精度仿真 + 性能仿真(生成报告)
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report
# 指定输出目录
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report -o ./sim_output
# 传递算子自定义参数
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report -u "--shape 1024,1024 --dtype float16"
2. 生成性能报告
# 从仿真结果生成流水线报告(默认当前目录)
npusim report -e ./npusim_Ascend950_*
# 指定输出目录
npusim report -e ./npusim_Ascend950_* -o ./report_output
# 指定查看的 Core ID
npusim report -e ./npusim_Ascend950_* -n 0 # 查看单个 core
npusim report -e ./npusim_Ascend950_* -n 0-2 # 查看 core 范围
npusim report -e ./npusim_Ascend950_* -n 0-2,5,12-14 # 混合格式
npusim report -e ./npusim_Ascend950_* -n all # 查看所有 core
3. 查看输出文件
npusim_output/
├── npusim.log # 仿真执行日志
├── record/ # 仿真原始数据
└── report/
└── results/
└── kernel_*_reports/
├── summary.json # ★ 结构化性能汇总(核心指标源)
├── trace_core0.json # 指令流水图(Chrome Tracing)
└── ...
4. 性能瓶颈定位(Trace 空泡分析)
npusim 生成的 trace_core*.json 是 Chrome Trace Format,包含每个 core 各 pipeline(SCALAR/VECTOR/MTE2/CUBE 等)的指令级周期事件。按 references/pipeline-bubble-analysis.md 的判定标准自主分析:
提示:trace 分析成本高。建议先用
summary.json做快速诊断(见下方"性能分析"章节),仅在需要确认根因时下钻到 trace。
分析目标:定位主 pipeline(VECTOR/CUBE)idle 空泡的根因。
核心方法:
- 空泡分类:按 7 大类 / ~30 子类型标准判定等待原因(DATA_STALL、SCALAR_OVERHEAD、STRUCTURAL 等)
- 因果归因:检查"主 pipeline idle 时谁在 busy",追踪具体阻塞源
- 周期性模式检测:判断空泡是系统性(每个 tile 重复)还是偶发
- 重叠度判定:验证双缓冲是否生效(MTE2 与 VECTOR/CUBE 时间重叠比例)
- 源码定位:对 trace 中的 PC 执行地址→源码行映射,将阻塞指令关联到 AscendC 源码。先确认前置条件:仿真时使用
-g保留 debug/line info、未 strip,且映射 ELF 与仿真运行产物一致
PC 映射要求:保留
-g/ line info、不 strip、使用与仿真运行一致的 ELF;.aicore_binary需先用msobjdump --extract-elf抽取内嵌设备 ELF。详见 references/pc-source-mapping.md。
命令参考
npusim record - 执行仿真
在 AscendOps 仿真环境中运行用户程序,记录仿真数据。
基本语法:npusim record <user_app> -s <SOC_VERSION> [选项]
| 参数 | 简写 | 必填 | 说明 |
|---|---|---|---|
user_app |
- | 是 | 用户编译后的可执行程序路径 |
--soc-version |
-s |
是 | 目标芯片版本(如 Ascend950) |
--gen-report |
-g |
否 | 仿真结束后生成性能报告 |
--output |
-o |
否 | 仿真结果输出目录 |
--user-option |
-u |
否 | 传递给用户程序的自定义参数 |
示例:
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report -o ./sim_output
npusim record ./ascendc_kernels_bbit -s Ascend950 --gen-report -u "--shape 1024,1024"
npusim report - 生成性能报告
基于仿真结果生成可视化的性能分析报告和指令流水线图。
基本语法:npusim report -e <EXPORT_FOLDER> [选项]
| 参数 | 简写 | 必填 | 说明 |
|---|---|---|---|
--export |
-e |
是 | 仿真结果文件夹路径(npusim record 的输出) |
--output |
-o |
否 | 流水线图输出目录 |
--core-id |
-n |
否 | 指定 Core ID(支持 0、0-2、0-2,5、all 等格式) |
示例:
npusim report -e ./npusim_Ascend950_*
npusim report -e ./npusim_Ascend950_* -n 0-2
npusim report -e ./npusim_Ascend950_* -n all -o ./report_output
详细命令参数、输出目录结构、返回值说明见 references/simulator-advanced.md
常见问题
| 问题 | 解决方法 |
|---|---|
| 仿真失败 | 确保代码中只设置 0 卡,仅使用 AI Core 计算算子 |
| 性能报告未生成 | 确保使用 --gen-report 参数 |
| 找不到仿真结果 | 使用 -o 指定输出目录,或检查当前目录下的 npusim_* 文件夹 |
参考资料
| 文件 | 内容 | 何时查阅 |
|---|---|---|
references/simulator-advanced.md |
仿真进阶命令参考 | 需要高级参数或批量仿真时 |
references/troubleshooting.md |
问题排查指南 | 仿真失败或报告未生成时 |
references/pipeline-bubble-analysis.md |
指令流水空泡分类、因果归因、周期性模式检测 | 生成 trace 后,定位性能瓶颈根因时 |
scripts/trace_bubble_analyzer.py |
自动化空泡分析脚本(兼容 msprof/npusim 双格式) | 批量分析多核 trace 或获取预分析报告时 |
scripts/pipeline_bound_analyze.py |
逐流水单元 busy/气泡耗时统计与 bound 类型判定(MTE2/CUBE Bound 等) | 需要量化各 pipe 占比、自动判定瓶颈类型时 |
references/pc-source-mapping.md |
PC 地址→AscendC 源码行映射的前置条件、命令和输出解读 | trace 中已有 PC,需要定位阻塞指令源码时 |
references/performance-metrics-reference.md |
summary.json 字段、阈值、Analysis Priority | 分析 summary.json 时 |
references/performance-issues-general.md |
多核负载不均衡 + Kernel 利用率不足 | 分析 summary.json 时 |
references/performance-issues-aic.md |
AIC: CUBE/MTE2/MTE1/FIXPIPE/SCALAR + L0C→UB | 分析 summary.json 时 |
references/performance-issues-aiv.md |
AIV: VECTOR/MTE2/MTE3/SCALAR + SIMT + SIMD VF Code-Shape (§6) | 分析 summary.json 时 |
references/performance-issues-template.md |
新增 issue 条目的规范 | 维护 |
scripts/map_pc_to_source.py |
PC→源码行映射脚本,封装 llvm-symbolizer |
trace 中已有 PC,需要定位阻塞指令源码时 |
性能分析(Performance Analysis)
分析已有 summary.json(无需重跑仿真),定位瓶颈并给出优化方向。
summary.json vs trace — 如何选择:从这里开始。
summary.json成本很低(几 KB 的聚合指标),下方快速诊断流程能解决大部分问题。只有当 summary 已指明瓶颈类型但未定位具体原因时(例如 overlap 偏低但源码中已开启双缓冲,或需要查看具体哪条指令在何时阻塞流水线),才需要下钻到 trace 级空泡分析(上方 §4,references/pipeline-bubble-analysis.md)。先用 summary,再用 trace 确认因果链。
分析工作流
- 生成报告 — 执行
npusim record --gen-report或npusim report - 读取
summary.json— 位于<npusim_output>/report/results/kernel_*_reports/summary.json - 检查
top_level_diagnosis— 读取dominant_pipeline和imbalance_ratio获得初步判断 - 识别瓶颈类型 — 按下方快速诊断表定位,然后查阅对应的 reference
- 推荐优化方案 — 从对应 issue reference 中提取具体修复动作
- 迭代验证 — 重新运行仿真,对比指标变化
summary.json 结构
summary.json 包含 9 个段落;其中 7 个始终存在,另外 2 个(cache、bandwidth)可能缺失,simd_vf_metrics 始终存在但可能为空 {}。完整的字段定义、阈值和标准的"分析优先级"排序见 performance-metrics-reference.md(唯一可信源)。
快速诊断(Quick Diagnosis)
Step 0 — 核数检查:检查 kernel_info.ai_core_active。如果在多核芯片上 == 1,先确认确实是单核运行:用 blockDim 或 per_core 数组长度核对——若 blockDim > 1 但仅采到一个核的数据,则属于 profiler 采样假象(kernel 实为多核,imbalance_ratio 仍为 1.0、per_core 缺失,真实不均衡仍可能存在),此时不要给出"开满核"的结论,应按多核不均衡走结构化检查。确认确为单核后 — 让所有核都参与计算是最优先的修复,优先级高于下方所有瓶颈类型规则。此时 imbalance_ratio 会是 1.0(只追踪了一个核),不应被理解为"负载均衡";所有接近零的 overlap 都是单核运行的假象,不是双缓冲问题。请跳转到 通用问题 §1.1,在 kernel 变为多核运行之前不要继续执行下方瓶颈类型表。
Step 1 — 多核负载均衡:检查 top_level_diagnosis.imbalance_ratio
> 1.3→ 需要做负载均衡 tiling,按 通用问题 §1 的 "Locating the slow core" 流程用per_core[]定位慢核;也可查看aicore_utilization.json获取逐核活跃时段和利用率百分比> 2.0→ 严重不均衡,应在处理其他问题前优先解决此问题
Step 1.5 — Kernel 利用率合理性检查:如果 dominant_pipeline_util < 0.50 且 所有 pipeline_overlap.* 接近零 且 计算流水空闲 — 对于 Cube 型 kernel AIC_CUBE.mean < 0.10,对于 纯 Vector 型 kernel AIVx_SIMD.mean 与 AIVx_SIMT.mean 均 < 0.05 — 说明 kernel 工作量不足以支撑分析(可能是 blockDim 对 shape 而言过大,或 shape 本身太小)。imbalance_ratio 不是必要条件(均衡但 shape 过小同样适用)。请跳转到 通用问题 §2 Kernel 利用率不足;不要继续执行 Step 2 — 瓶颈类型规则会误判。
For SIMD VF kernels (__simd_vf__ + asc_vf_call): §2's shrink interacts with §6.1 fold — see general §2 Pitfall and aiv §6 General principle. Do not apply §2 blindly — compare kernel_total_clocks across blockDim values.
Step 1.7 — SIMD VF 代码形态检查:如果 summary.json 中 simd_vf_metrics 块非空(kernel 使用了 __simd_vf__ + asc_vf_call),在进入 pipe-bound 诊断(Step 2)之前先检查 AIV §6 SIMD VF Code-Shape Patterns(§6.1–§6.3)。代码形态问题(VF 碎片化、串行依赖、二叉折叠)常表现为 pipe-bound 症状(SCALAR overhead、MTE2 主导)—— 先修复 VF 结构,再重新 profile 并重新诊断新的主导流水线。
Step 2 — 识别瓶颈类型,基于 top_level_diagnosis.dominant_pipeline(下表源自 performance-metrics-reference.md §2 利用率解读 / §3 — 该文件是阈值的唯一可信源):
| 主导流水线 | 瓶颈类型 | 下一步检查的关键指标 | 主要优化动作 |
|---|---|---|---|
AIC_CUBE (mean > 0.80) |
CUBE 瓶颈 | pipeline_overlap.AIC_MTE2_vs_AIC_CUBE、AIC_MTE1_vs_AIC_CUBE |
核间 Cube/Vector 交错;对 L0A/L0B 和 L1 开启双缓冲 |
AIVx_SIMD (mean > 0.50) |
VECTOR 瓶颈 | aiv_vector_instructions.ub_traffic_ratio |
若 ub_traffic_ratio ≥ 1.0,使用 VF RegAPI |
AIVx_SIMT(最高) |
SIMT 瓶颈 | SIMT_ExecIPC、SIMT_BranchIPC |
已是 SIMT 模式;若分支发散(SIMT_BranchIPC 偏低),降低分支发散。参见 AIV §5 |
AIC_MTE2 / AIVx_MTE2 |
MTE2 瓶颈 | bandwidth.*.avg_transaction_gbps |
开启双缓冲;若 DMA 粒度较小,使用 UB 批量搬运 |
AIC_MTE1 |
MTE1 瓶颈 | pipeline_overlap.AIC_MTE1_vs_AIC_CUBE |
对 L0A/L0B 开启双缓冲 |
AIC_FIXP |
FIXPIPE 瓶颈 | pipeline_overlap.AIC_FIXP_vs_AIC_CUBE |
若 < 0.30:CUBE 因排空 L0C 而阻塞 → 增大 N 轴 tile 尺寸 |
AIC_SCALAR / AIVx_SCALAR |
SCALAR 瓶颈 | scalar_instructions.*.load_store_ratio、pipeline_overlap.AIC_SCALAR_vs_AIC_CUBE |
若 ratio ≥ 0.30 则存在溢出;若 SCALAR_vs_CUBE overlap 偏低(< 0.20)则为反压(按 CUBE Bound 处理) |
Step 3 — 带宽/搬运交叉验证(独立于 dominant_pipeline):
- 若
bandwidth存在:扫描是否存在冗余搬运 — 最常见的是AIC_FIXPIPE_L0C_TO_OUT+AIVx_MTE2_OUT_TO_UB搬运相同数据。此特征说明 matmul tile 经由 GM 绕了一圈,可通过 L0C→UB 直连 Fixpipe 消除。 - 若
bandwidth缺失:使用备用信号 — 在一个不应需要 AIV 侧 GM 输入的 kernel 中pipe_utilization.AIVx_MTE2.mean > 0,加上pipeline_overlap.AIC_CUBE_vs_AIVx_VEC = 0。根因相同,修复方法相同。
参见 performance-issues-aic.md §5。
详细诊断树和修复方法:
- performance-issues-general.md — 多核负载不均衡
- performance-issues-aic.md — CUBE / MTE2 / MTE1 / FIXPIPE 瓶颈(AIC)、Cube→Vector L0C→UB 直连、SCALAR 瓶颈(AIC)
- performance-issues-aiv.md — VECTOR 瓶颈、MTE2/MTE3 瓶颈(AIV)、流水线重叠