自动化与脚本
在 Linux 上用 perf 做 CPU…
当需要在 Linux 上对 CPU 做采样剖析、查看热函数、测量 IPC/缓存/分支事件或从 perf 数据生成火焰图时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
在 Linux 上用 perf 做 CP特定
解决思路
- 安装 perf:Debian/Ubuntu 执行 `sudo apt install linux-perf`;Fedora/RHEL 执行 `sudo dnf install perf`。
- 检查权限:执行 `cat /proc/sys/kernel/perf_event_paranoid`;2=仅 CPU stats(不含内核),1=用户+内核,0=全部,-1=无限制。
- 临时降低 perf 权限限制:执行 `sudo sysctl -w kernel.perf_event_paranoid=1`。
- 持久降低 perf 权限限制:执行 `echo 'kernel.perf_event_paranoid=1' | sudo tee /etc/sysctl.d/99-perf.conf`,然后执行 `sudo sysctl -p /etc/sysctl.d/99-perf.conf`。
- 编译目标程序以获取有用 frame 数据:执行 `gcc -g -O2 -fno-omit-frame-pointer -o prog main.c`;`-fno-omit-frame-pointer` 对基于帧指针的栈展开很关键;替代方案是用 DWARF CFI 编译并使用 `--call-graph=dwarf`。
- 使用 `perf stat` 获取基本硬件计数器:执行 `perf stat ./prog`。
- 使用 `perf stat` 指定事件:执行 `perf stat -e cache-misses,cache-references,instructions,cycles,branch-misses ./prog`。
- 使用 `perf stat` 做墙钟比较,运行 N 次:执行 `perf stat -r 5 ./prog`。
- 使用 `perf stat` 附加到已有进程:执行 `perf stat -p 12345 sleep 10`。
- 解读 `perf stat` 输出:IPC(instructions per cycle)< 1.0 表示内存受限或流水线停顿;cache-miss rate > 5% 表示缓存压力显著;branch-miss rate > 5% 表示分支预测器吃力。
- 使用 `perf record` 默认采样:执行 `perf record -g ./prog`,默认以 1000 Hz(cycles 事件)采样。
- 使用 `perf record` 指定采样频率:执行 `perf record -F 999 -g ./prog`。
- 使用 `perf record` 指定事件:执行 `perf record -e cache-misses -g ./prog`。
- 使用 `perf record` 附加到运行中的进程:执行 `perf record -F 999 -g -p 12345 sleep 30`。
- 做 Off-CPU 剖析,查看等待时间:执行 `perf record -e sched:sched_switch -ag sleep 10`。
- 使用 DWARF 调用图,适合没有帧指针的二进制:执行 `perf record -F 999 --call-graph=dwarf ./prog`。
- 将 `perf record` 保存到指定文件:执行 `perf record -o myapp.perf.data -g ./prog`。
- 使用 `perf report` 读取默认 `perf.data`:执行 `perf report`。
- 使用 `perf report` 指定输入文件:执行 `perf report -i myapp.perf.data`。
- 使用 `perf report` 仅看 self time(非累积时间):执行 `perf report --no-children`。
- 使用 `perf report` 按字段排序:执行 `perf report --sort comm,dso,sym`。
- 使用 `perf report` 输出非交互式文本:执行 `perf report --stdio`。
- 在 `perf report` TUI 中导航:`Enter` 展开符号;`a` 注释(显示汇编与命中计数);`s` 显示源码(需要调试信息);`d` 按 DSO(库)过滤;`t` 按线程过滤;`?` 查看帮助。
- 使用 `perf annotate` 查看热点指令:执行 `perf annotate sym_name`;也可在 report 中对某个符号按 `a`;或直接执行 `perf annotate -i perf.data --symbol=hot_function --stdio`;若 `mov` 或 `vmovdqa` 上命中计数很高,说明该 load 可能有 cache miss。
- 使用 `perf top` 实时剖析:执行 `sudo perf top -g`;按进程过滤执行 `sudo perf top -p 12345`。
- 将 perf 数据送入火焰图:执行 `perf script > out.perf`;执行 `git clone https://github.com/brendangregg/FlameGraph`;执行 `./FlameGraph/stackcollapse-perf.pl out.perf > out.folded`;执行 `./FlameGraph/flamegraph.pl out.folded > flamegraph.svg`;用浏览器打开 `flamegraph.svg`。
- 修复 `Permission denied`:原因是 `perf_event_paranoid` 太高;降低 paranoid 级别或使用 `sudo` 运行。
- 修复 `[unknown]` 帧:原因是缺少帧指针或调试信息;用 `-fno-omit-frame-pointer` 重编译,或使用 `--call-graph=dwarf`。
- 修复到处都是 `[kernel]`:原因是内核符号不可见;使用 `sudo perf record`;安装 `linux-image-$(uname -r)-dbgsym`。
- 修复 `No kallsyms`:原因是内核符号不可用;执行 `echo 0 | sudo tee /proc/sys/kernel/kptr_restrict`。
- 修复短程序报告为空:原因是程序退出太快;使用 `-F 9999` 或剖析更长的工作负载。
- 修复 DWARF 展开慢:原因是 DWARF 栈较大;使用 `--call-graph dwarf,512` 限制。
- 列出所有可用事件:执行 `perf list`。
- 使用常见硬件事件:`cycles`、`instructions`、`cache-references`、`cache-misses`、`branch-instructions`、`branch-misses`、`stalled-cycles-frontend`、`stalled-cycles-backend`。
- 使用软件事件:`context-switches`、`cpu-migrations`、`page-faults`。
- 使用 tracepoints(需要 root):`sched:sched_switch`、`syscalls:sys_enter_read`。
- 查看 `references/events.md` 获取计数器参考和解读指南。
- 与相关技能配合:使用 `skills/profilers/flamegraphs` 生成和阅读 SVG 火焰图;使用 `skills/profilers/valgrind` 做缓存模拟和内存剖析;使用 `skills/compilers/gcc` 或 `skills/compilers/clang` 从 perf 数据做 PGO(AutoFDO)。
适用边界 · 注意事项
- 非 Linux 环境,或无法安装/运行 perf 时,不适用此技能。
- 需要缓存模拟、内存泄漏或内存剖析时,应改用 Valgrind 等工具。
- 目标程序无法获得 perf 权限、内核符号或调试符号,且无法提权或重编译时,热点与调用栈分析会受限。