一、基本用法
# 统计程序运行期间的硬件计数器
perf stat ./my_program
# 输出示例:
# Performance counter stats for './my_program':
#
# 1324.56 msec task-clock # 1.00 CPUs utilized
# 12 context-switches # 9.06 /sec
# 0 cpu-migrations # 0.00 /sec
# 125 page-faults # 94.35 /sec
# 4,285,294,201 cycles # 3.235 GHz
# 2,142,647,100 instructions # 0.50 insn per cycle
# 428,529,420 branches # 323.5 M/sec
# 8,570,588 branch-misses # 2.00% of all branches
# 214,264,710 L1-dcache-loads
# 21,426,471 L1-dcache-load-misses # 10.00% of all L1-dcache accesses
# 107,132,355 cache-references
# 10,713,235 cache-misses # 10.001 % of all cache refs
二、关键指标解读
instructions per cycle (IPC)
含义:每个 CPU 周期执行了多少条指令
理想值:现代 CPU 可以做到 3-4(超标量 + 乱序执行)
IPC > 2:程序运行良好,CPU 利用率高
IPC 1~2:有轻度流水线停顿
IPC < 1:严重停顿,可能是缓存未命中、分支预测失败、指令依赖
❌ 低 IPC 的程序:
[周期][周期][周期][周期][周期][周期][周期][周期]
[指令] [指令] [指令] [指令]
CPU 大部分时间在等待内存或解决依赖
✅ 高 IPC 的程序:
[周期][周期][周期][周期][周期][周期][周期][周期]
[指令][指令][指令][指令][指令][指令][指令][指令]
CPU 利用率接近理论峰值
cache-misses
含义:L3 缓存未命中的次数
理想值:< 5%(如果 < 1% 说明数据访问模式非常好)
> 20%:内存访问模式有问题,需要重构数据结构
常见原因:链表遍历、红黑树中序遍历、跳跃指针
branch-misses
含义:分支预测失败的次数占比
理想值:< 5%
> 10%:分支模式难以预测
常见原因:二分搜索中的随机数据、switch-case 中的均匀分布
优化:用分支友好的算法(如用 cmov 替代分支)、使用 [[likely]]/[[unlikely]]
三、C++ 代码与 perf 计数器的对应
// IPC 低的代码(Cache Miss 严重)
void list_traversal(const std::list<int>& lst) {
// list 的节点散落在堆中,遍历时大量 Cache Miss
// perf 会显示 IPC < 1, cache-misses > 20%
for (auto it = lst.begin(); it != lst.end(); ++it) {
total += *it;
}
}
// IPC 高的代码(缓存友好)
void vector_traversal(const std::vector<int>& vec) {
// vector 连续内存,预取器提前加载
// perf 会显示 IPC > 2, cache-misses < 1%
for (auto x : vec) {
total += x;
}
}
// 分支预测失败的代码
void unpredictable_branch(const std::vector<int>& data) {
long long sum = 0;
for (int x : data) {
// 如果 data 中的正负数随机分布,分支预测失败率 ~50%
if (x > 0) sum += x;
}
}
// 分支预测友好的优化版
void predictable_branch(const std::vector<int>& data) {
long long sum = 0;
std::sort(data.begin(), data.end()); // 排序后正数都在前面
for (int x : data) {
if (x > 0) sum += x; // 前一批全命中,后一批全不命中 → 预测率接近 100%
}
}
如何用 perf 验证优化效果:
# 优化前
g++ -O2 -o test test.cpp && perf stat ./test
# 优化后
# 修改代码,重新编译
g++ -O2 -o test test.cpp && perf stat ./test
# 对比两个输出的 cache-misses 和 IPC,应该明显改善
四、常用 perf stat 组合
# 只看关键指标
perf stat -e cycles,instructions,cache-misses,branch-misses ./program
# 调度器行为分析
perf stat -e context-switches,cpu-migrations,page-faults ./program
# 内存访问分析
perf stat -e L1-dcache-load-misses,LLC-load-misses,LLC-store-misses ./program
# TLB 分析
perf stat -e dTLB-load-misses,iTLB-load-misses ./program