3、perf工具入门:perf list、perf stat、perf record、perf report基本用法
说实话,很多做性能优化的朋友,一上来就喜欢用各种花里胡哨的工具。但我个人觉得,perf 才是 Linux 性能剖析的「基本功」。它就像一把瑞士军刀,轻量、直接、而且几乎无处不在。
我记得刚入行那会儿,遇到一个 CPU 跑满的问题,同事让我用 perf 看看。我当时连 perf list 都不知道,硬着头皮查了半天文档。后来才发现,perf 其实没那么复杂,核心就四个命令:list、stat、record、report。把这四个玩明白了,80% 的性能问题你都能找到方向。
3.1 perf list:看看你的硬件支持什么
perf list 说白了就是告诉你:你的 CPU 能监控哪些事件。不同的 CPU 型号,支持的事件列表是不一样的。比如 Intel 的 CPU 有 L1 缓存命中率、分支预测失败率,ARM 的 CPU 可能就不一样。
用法很简单:
# 列出所有可用事件
perf list
# 只看硬件事件
perf list hw
# 只看软件事件
perf list sw
# 只看缓存相关事件
perf list cache
输出结果会分成几大类:
| 事件类别 | 说明 | 示例 |
|---|---|---|
| 硬件事件 | CPU 硬件计数器 | cpu-cycles, instructions, cache-misses |
| 软件事件 | 内核软件事件 | context-switches, page-faults, cpu-clock |
| tracepoint 事件 | 内核静态插桩点 | syscalls:sys_enter_read, block:block_rq_complete |
perf list hw 看看硬件支持哪些事件。如果发现 cache-misses 不可用,那可能是虚拟机环境或者 CPU 太老,这时候就得换软件事件来分析了。
3.2 perf stat:快速看一眼性能数据
perf stat 就像体检时的「快速筛查」。你不需要深入分析,就想知道程序跑得怎么样——CPU 利用率高不高?缓存命中率行不行?上下文切换频繁不频繁?
用法:
# 统计一个命令的执行情况
perf stat ./my_program
# 统计正在运行的进程(PID 为 12345)
perf stat -p 12345
# 统计多个事件
perf stat -e cycles,instructions,cache-misses ./my_program
输出示例:
Performance counter stats for './my_program':
1,234,567,890 cycles # 3.45 GHz
2,345,678,901 instructions # 1.90 insn per cycle
12,345,678 cache-misses # 5.2% of all cache refs
1,234 context-switches # 0.001 /sec
0.357892345 seconds time elapsed
这里有几个关键指标:
- instructions per cycle (IPC):每个时钟周期执行了多少条指令。IPC 越高,说明 CPU 利用率越好。一般 IPC 低于 1 就要警惕了。
- cache-misses 比例:缓存未命中率。超过 10% 通常意味着内存访问模式有问题。
- context-switches:上下文切换次数。如果这个数字很大,说明你的程序在频繁争抢 CPU。
3.3 perf record:把性能数据录下来
perf stat 只能看个大概,真要定位问题,得用 perf record。它会把采样数据保存下来,供后续分析。你可以把它理解成「性能录像机」。
用法:
# 默认采样 CPU 周期事件
perf record ./my_program
# 指定采样事件和频率
perf record -e cache-misses -F 99 ./my_program
# 采样正在运行的进程
perf record -p 12345 -g -- sleep 10
参数说明:
-e:指定要采样的事件,比如cycles、cache-misses-F:采样频率,单位 Hz。99 表示每秒采样 99 次,适合大多数场景-g:记录调用栈,这个很重要!没有调用栈你根本不知道是哪个函数在消耗资源-- sleep 10:采样 10 秒后自动停止
3.4 perf report:分析采样结果
录完像之后,就该看回放了。perf report 会读取 perf.data 文件,生成一个交互式的分析报告。
用法:
# 默认读取 perf.data
perf report
# 指定输入文件
perf report -i my_perf.data
# 按调用栈排序
perf report -g graph
进入交互界面后,你会看到类似这样的输出:
Samples: 1K of event 'cycles'
Event count (approx.): 1234567890
Overhead Command Shared Object Symbol
45.2% my_prog my_prog [.] compute_heavy
22.1% my_prog libc-2.31.so [.] malloc
10.5% my_prog my_prog [.] parse_input
8.3% my_prog [kernel] [k] do_syscall_64
...
关键解读:
- Overhead:该函数占用的 CPU 时间比例。45.2% 说明 compute_heavy 是热点函数。
- Symbol:函数名。如果是
[.]表示用户态,[k]表示内核态。 - 按
Enter可以展开调用栈,看到是谁调用了这个函数。
Enter 看调用链,找到「罪魁祸首」的调用路径。
3.5 一张图看懂 perf 工作流程
下面这张 SVG 图,把 perf 的核心流程串起来了。你一看就明白:
这张图很直观:先用 perf list 看看武器库,然后用 perf stat 快速扫描,发现问题后再用 perf record 深入采样,最后 perf report 给出分析结果。说白了,就是「先粗后细、层层深入」的思路。
3.6 实战小例子:定位 CPU 热点
光说不练假把式。咱们拿一个实际场景走一遍:
# 1. 先看看程序跑得怎么样
perf stat ./my_app
# 输出显示 IPC 只有 0.8,cache-misses 高达 15%
# 嗯,有问题
# 2. 深入采样,记录调用栈
perf record -e cache-misses -F 99 -g ./my_app
# 3. 分析结果
perf report -g graph
在 perf report 界面里,我发现 hash_lookup 函数占了 40% 的 cache-misses。点进去一看,调用链是 process_request -> hash_lookup。原来是一个哈希表查询频繁 miss。
后来我改成了更紧凑的数据结构,cache-misses 降到了 5%,性能提升了 3 倍。你看,perf 就是这么用的。
想要更多资料,联系可可