CAE 性能分析:CPU、GPU、NUMA、MPI 与 I/O 工具链 / CAE Performance Analysis Across CPUs, GPUs, NUMA, MPI, and I/O
📅 创建时间:2026-07-23
🏷️ 标签:#Profiling #perf #VTune #Nsight #MPI #I/O
📚 前置知识:[[04-solver-data-structures]] [[/02-systems-and-performance/03-parallel-computing/10-performance-engineering]]
📚 相关知识:[[/02-systems-and-performance/02-computer-architecture-and-hardware/11-performance-analysis-tools]] [[/01-cpp/08-build-tooling-and-abi/02-testing-analysis-sanitizers]]
1. 性能分析的目标
性能分析不是生成一张火焰图,而是建立一条可以验证的证据链:
工程目标
→ 可复现基线
→ 最大耗时阶段
→ 热点与等待
→ 硬件或算法原因
→ 优化假设
→ 修改
→ 重新测量
→ 正确性验证没有基线、输入规模和正确性标准的“快了 30%”没有工程意义。
2. 先定义测量合同
每次实验固定:
- 输入模型、网格和时间步;
- 求解器类型、容差和停止准则;
- Release 构建与编译选项;
- CPU/GPU 型号、频率和功耗状态;
- 线程数、MPI Rank 数、绑核和设备映射;
- 软件、驱动、MPI 和依赖库版本;
- 预热、重复次数和统计方法;
- 是否包含读取、初始化、JIT、传输和输出;
- 正确性容差与关键工程量。
至少报告中位数和波动范围。共享集群上还要记录节点、作业调度和其他负载。
3. 自顶向下的诊断顺序
第一级:端到端阶段
先回答时间花在哪里:
读取/网格
初始化
组装或通量
线性求解
非线性/时间迭代
通信
结果恢复
I/O第二级:函数和调用栈
找到阶段内最大的函数、调用路径和等待。
第三级:硬件计数器
判断热点受计算、前端、分支、Cache、内存带宽、NUMA 还是同步限制。
第四级:并行和设备时间线
检查线程空闲、Rank 不均、集合通信、GPU 空洞、传输和同步。
第五级:Kernel 或循环
最后才进入具体循环、指令、Warp Stall 和数据布局。
4. 内部计时先行
外部 Profiler 之前,求解器应有低开销阶段计时:
step=42
assembly=0.31s
linear.setup=0.08s
linear.solve=1.72s
linear.iterations=93
halo=0.19s
output=0.00s建议记录总时间、调用次数、平均值、最大值,并支持按 Step、方程和 Rank 聚合。高频 Kernel 使用采样或批量汇总,避免计时器本身成为热点。
5. 基础命令
Linux time
/usr/bin/time -v ./solver case.yaml关注:
- elapsed wall time;
- user/system CPU time;
- maximum resident set size;
- major/minor page faults;
- context switches。
如果 wall time 很长但 user time 很低,可能在等待 I/O、锁、通信或设备。
多次运行
可使用 Hyperfine,也可以由脚本重复运行并保存原始数据。不要只选最快的一次。
Google Benchmark
适合 SpMV、单元积分、通量和应力恢复等可独立 Kernel。微基准必须阻止编译器消除结果,并使用接近真实的数据规模和分布。
微基准结果不能替代端到端测量。
6. perf stat:先看总体硬件特征
perf stat -r 5 \
-e cycles,instructions,branches,branch-misses,cache-misses \
./solver case.yaml关键解释:
| 指标 | 含义 | 不能直接得出的结论 |
|---|---|---|
| IPC = instructions/cycles | 每周期完成多少指令 | IPC 低不一定就是代码差,可能在等内存 |
| branch-misses | 分支预测失败 | 分支少不代表快 |
| cache-misses | 最后级 Cache 未命中线索 | 需结合访问量和带宽 |
| task-clock | CPU 活跃时间 | 多线程下不能直接当作利用率 |
| context-switches | 调度和阻塞线索 | 少量切换通常不是主因 |
事件名称依 CPU 而异。生产报告应保存实际命令和权限设置。
7. perf record 与火焰图
perf record -g --call-graph dwarf ./solver case.yaml
perf report观察:
- 最宽的栈表示累计 CPU 时间最多;
- 是否在组装、SpMV、预条件、内存分配或文件写入;
- 是否大量时间落在锁、Barrier 或运行时;
- 调用路径是否符合预期。
火焰图适合发现“哪里耗时”,但不能解释 Cache、带宽或 SIMD 为什么差,需要结合计数器。
8. Intel VTune
常用分析:
- Hotspots:函数和调用栈;
- Microarchitecture Exploration:流水线瓶颈;
- Memory Access:带宽、延迟和 NUMA;
- Threading:线程并行度、锁和等待;
- HPC Performance Characterization:向量化和内存特征。
典型判断:
热点明确
├─ Retiring 高:执行了大量有效指令,检查算法工作量
├─ Front-End Bound:指令获取、代码尺寸或分支路径
├─ Bad Speculation:分支预测和错误路径
└─ Back-End Bound
├─ Core Bound:执行端口或长延迟计算
└─ Memory Bound:Cache、DRAM 或 NUMA不要只截取一个百分比,应保存热点函数、输入和线程配置。
9. Intel Advisor 与编译器报告
Advisor 可分析:
- 循环向量化机会;
- SIMD Lane 利用;
- 数据依赖;
- Roofline;
- 内存访问模式。
GCC/Clang 编译器报告示例:
g++ -O3 -fopenmp -fopt-info-vec-optimized \
-fopt-info-vec-missed source.cpp“已向量化”仍需检查:
- 是否只向量化了低占比循环;
- 是否使用 Gather/Scatter;
- Mask 是否让多数 Lane 空闲;
- 对齐修正和尾循环开销;
- 是否已经受内存带宽限制。
10. 内存带宽工具
Intel PCM
可观察 Socket/通道级内存带宽、Cache 和互连流量,适合判断 SpMV、通量循环是否接近平台实际带宽。
LIKWID
提供性能组、线程绑定和 Marker API,可对指定代码区间测量 FLOPS、带宽和 Cache 行为。
Roofline
可达到性能 ≤ min(计算峰值, 内存带宽 × 算术强度)如果已接近带宽屋顶,继续增加浮点流水线不会解决问题;应减少字节数、改善复用或改变算法表示。
11. NUMA 工具
numactl --hardware
numastat -p <pid>
numactl --cpunodebind=0 --membind=0 ./solver case.yaml检查:
- 线程是否跨 Socket 迁移;
- 内存页是否主要位于远端节点;
- 单 Rank 是否跨越多个 NUMA 节点;
- 串行初始化是否破坏 First Touch;
- MPI Rank 和 OpenMP 线程是否与硬件拓扑匹配。
对比实验要保持线程数一致,只改变绑定策略。
12. OpenMP 与线程分析
关注:
- 实际并行区时间;
- 每线程工作量;
- Barrier 等待;
- Critical/Atomic 时间;
- 动态调度开销;
- False Sharing;
- 嵌套并行导致的超额线程。
判断方法:
线程数增加但总 CPU 时间增长、Wall Time 不降
→ 检查带宽饱和、同步、NUMA 和任务粒度CPU 利用率高不能证明并行有效,线程可能都在竞争同一内存带宽。
13. Nsight Systems:系统时间线
nsys profile --trace=cuda,nvtx,osrt,mpi \
--output=solver_timeline \
./solver case.yaml用于观察:
- CPU 线程与 MPI 时间线;
- GPU Kernel 和并发 Stream;
- H2D/D2H 拷贝;
- CUDA API 同步;
- GPU 空闲间隙;
- 初始化、迭代和输出阶段。
典型模式:
| 时间线现象 | 可能原因 |
|---|---|
| Kernel 之间大空洞 | CPU 准备慢、同步或小任务 |
| H2D-Kernel-D2H 反复串行 | 数据未驻留 GPU |
| 大量极短 Kernel | 启动开销,需要融合或批处理 |
| CPU 等 cudaDeviceSynchronize | 隐式同步或调试式计时 |
| MPI 等待同时 GPU 空闲 | 通信和计算未重叠 |
使用 NVTX 标记组装、线性迭代和模型更新,才能把时间线与求解器阶段对应。
14. Nsight Compute:单 Kernel
ncu --set full \
--kernel-name regex:flux \
./solver case.yaml关注:
- Achieved Occupancy;
- Warp Stall 原因;
- Global Memory 吞吐;
- L1/L2 Hit Rate;
- 合并访存;
- 分支发散;
- 寄存器和 Shared Memory 限制;
- Compute/Memory Throughput 相对峰值。
Occupancy 不是越高越好。一个带宽受限 Kernel 即使 Occupancy 很高,也可能无法再提升;一个寄存器较多但复用很好的 Kernel 也可能更快。
AMD 平台可使用 rocprof、rocprofv3 和 Omniperf 完成相似层次的分析。
15. MPI 基础测量
至少计算强扩展:
Speedup(p) = T1 / Tp
Efficiency(p) = Speedup(p) / p还要记录:
- 每 Rank 单元/Cell 数;
- 分区边界实体数;
- 最快、平均、最慢 Rank 的阶段时间;
- Halo 字节数和消息数;
- Allreduce 等集合通信次数;
- 线性迭代数是否随 Rank 改变。
只看平均时间会隐藏 Straggler。
16. mpiP、Score-P 与 Scalasca
mpiP
低开销汇总 MPI 调用,适合先判断 MPI 占比、热点调用和调用栈。
Score-P
为 MPI、OpenMP、CUDA 和用户区域采集统一 Trace/Profile。大型 Trace 需控制采样与过滤,否则数据量可能失控。
Scalasca
在 Score-P 数据上识别等待模式,例如 Late Sender、Barrier 等待和不平衡。
典型流程:
内部计时发现扩展差
→ mpiP 判断 MPI 占比和主要调用
→ Score-P/Scalasca 定位等待发生在哪些阶段和 Rank
→ 回到分区、算法或通信计划处理TAU 和 HPCToolkit 也可用于跨节点调用路径、采样和加速器分析,选择取决于平台支持和团队经验。
17. I/O 分析
iostat
iostat -xz 1观察设备吞吐、队列和等待,但共享文件系统上的客户端指标不一定能解释服务端瓶颈。
strace
strace -c -f ./solver case.yaml用于发现大量小文件、频繁 open/stat、同步写和系统调用异常。不适合长期低开销生产监控。
Darshan
面向 HPC I/O,记录每个文件、Rank、访问大小、共享模式和 MPI-IO 行为。适合回答:
- 是否所有 Rank 在写同一个文件;
- 请求是否过小;
- 是否存在元数据风暴;
- 是否有效使用集合 I/O;
- Checkpoint 是否产生突发拥塞。
18. 正确性工具不是性能工具
ASan、UBSan、TSan、Valgrind Memcheck 用于发现越界、未定义行为、数据竞争和泄漏。它们会显著改变时间和内存行为,不应在其运行结果上报告正式性能。
正确顺序:
正确性构建发现缺陷
→ 修复并通过测试
→ Release 构建进行性能测量19. 性能实验记录模板
目标指标:
输入模型与规模:
正确性标准:
Git 提交与构建选项:
CPU/GPU/内存/网络:
软件、驱动、MPI 版本:
线程、Rank、绑核和设备映射:
基线命令:
基线结果与波动:
阶段占比:
Profiler 证据:
瓶颈假设:
唯一修改:
优化后结果:
迭代次数变化:
数值与工程结果检查:
结论:
下一实验:20. 工具选择速查
| 问题 | 首选工具 |
|---|---|
| 总时间和峰值内存 | internal timers、time |
| CPU 热点 | perf record、VTune Hotspots |
| IPC、分支、Cache | perf stat、VTune |
| SIMD 和 Roofline | Advisor、编译器报告、LIKWID |
| 内存带宽 | PCM、LIKWID、VTune Memory Access |
| NUMA | numactl、numastat、VTune |
| GPU 系统协同 | Nsight Systems |
| GPU Kernel | Nsight Compute |
| MPI 占比 | mpiP |
| MPI 等待模式 | Score-P、Scalasca、TAU |
| 并行 I/O | Darshan |
| 系统调用异常 | strace |
21. 观察、解释与下一步
| 观察到什么 | 说明什么 | 下一步检查什么 |
|---|---|---|
| Wall Time 高而 CPU Time 低 | 进程可能在等待 I/O、锁、MPI 或 GPU | 时间线、系统调用和等待栈 |
| CPU 利用率高但扩展差 | 线程可能竞争带宽或同步资源 | PCM/LIKWID、Barrier 和 NUMA |
| perf 热点集中在 SpMV | 只知道“哪里慢”,尚不知道“为什么” | 带宽、Cache、索引字节和迭代数 |
| Nsight 中 GPU 存在空洞 | 主机准备、传输或同步未被隐藏 | CUDA API、H2D/D2H 和 NVTX 阶段 |
| MPI 平均时间正常但总步很慢 | 少数 Straggler 决定同步完成时间 | 最大 Rank、等待模式和分区权重 |
| 输出步骤周期性尖峰 | Checkpoint 或共享文件系统产生突发等待 | Darshan、请求大小和集合 I/O |
下一篇:[[06-architecture-driven-optimization]]