perf stat:用硬件计数器量化瓶颈
更新时间:2026-09-19。perf record 用采样告诉你「时间花在哪个函数」,perf stat 不采样调用栈,而是读取 CPU 的硬件性能计数器(PMU),用一组聚合数字回答「程序到底慢在哪类资源」:算力、内存、分支还是调度。基础见 perf,内核子系统微基准见 perf bench。
一、基本用法
bash
perf stat ./prog # 跑一个程序,结束打印计数
perf stat -p <pid> sleep 10 # 对运行中进程统计 10 秒
perf stat -a sleep 5 # 全系统统计 5 秒
perf stat -r 5 ./prog # 重复 5 次给均值/方差(做对比更稳)
perf stat -e cycles,instructions,cache-misses ./prog # 只看指定事件bash
Performance counter stats for './prog':
1024.30 msec task-clock
2,400,000,000 cycles # 2.343 GHz
4,800,000,000 instructions # 2.00 insn per cycle
180,000,000 cache-references # 175.7 M/sec
45,000,000 cache-misses # 25.00% of all cache refs
90,000,000 branches
9,000,000 branch-misses # 10.00% of all branches
120 context-switches
2,300 page-faults二、关键指标与读法
1)IPC(instructions per cycle)= instructions / cycles
- IPC 高(接近或 > 2~4,看 CPU 宽度):CPU 流水线利用率好,多在做计算。
- IPC 低(< 1 甚至更低):CPU 大量周期在等待——等内存、等分支解决。要结合下面的 cache/分支计数区分。
2)cache-misses / cache-references(LLC miss 率)
- 末级缓存未命中比例高(如 > 10%~20% 且是热点)说明内存受限(memory-bound):CPU 在等数据从内存加载。优化方向是数据局部性、缓存友好布局、对齐、避免 false sharing;细查用 Cachegrind。
3)branch-misses / branches(误预测率)
- 比例高(例如 > 5%~10%)说明关键分支难以预测,每次误预测清空流水线(十几~几十周期)。优化方向:减少数据相关分支、likely/unlikely、分支无关化(查表/条件移动)。
4)context-switches / cpu-migrations
5)page-faults
- 启动阶段大量 minor fault 正常(懒分配/页缓存);运行中持续 major fault 说明在换页/缺页读盘,见 free/si-so。
三、怎么定位瓶颈类型
| perf stat 现象 | 瓶颈 | 下一步 |
|---|---|---|
| 高 IPC + 高 cycles 热点 | 计算密集(compute-bound) | 算法/SIMD/多核 |
| 低 IPC + 高 cache-miss | 内存密集 | 局部性/布局/缓存,Cachegrind |
| 低 IPC + 高 branch-miss | 分支误预测 | 分支消除/预测友好化 |
| 高 context-switch、低单核利用 | 线程过多/锁/IO | 减线程、异步、off-CPU 分析 |
| 高 major-fault、si/so | 换页/内存不足 | 减占用/扩内存 |
四、事件与环境注意
- 用
perf list查当前机器支持的事件名(不同微架构事件不同,如L1-dcache-load-misses、mem_load_retired.l3_hit)。 - 计数器数量有限,事件太多时内核会**多路复用(multiplexing)**并按比例缩放,精度下降;关键测量一次少选几个事件。
- 虚拟机/容器里 PMU 可能受限(事件不支持或只读软件事件),云主机常见;此时 cycles/instructions 通常可用,精细的 LLC/分支事件可能缺失。
- 权限:很多硬件事件需要
perf_event_paranoid放宽或 root。
坑
- 只看绝对 cache-miss 数量,不看占 cache-references 的比例和 IPC,无法判断是否真是瓶颈。
- 事件选太多触发 multiplexing,结果被缩放而未察觉。
- 在不支持 PMU 透传的虚拟机里纠结缺失的硬件事件。
- 用单次运行的数字下结论,热缓存/调度抖动会偏差,应用 -r 多次或先预热。
总结
perf stat 读取 PMU 给出 instructions、cycles、cache-misses、branch-misses、上下文切换和缺页等聚合计数,核心是用 instructions/cycles 得到 IPC,再结合末级缓存未命中率判断是否内存受限、用分支误预测率判断是否被分支拖慢、用切换和缺页判断调度与换页问题,从而在不抓调用栈的情况下快速给瓶颈分类,再用 perf record 或 Cachegrind 下钻;测量时注意事件复用、先预热重复运行以及虚拟机的 PMU 限制。