perf 不是 c++ 的一部分,需编译时加 -g -o2 -fno-omit-frame-pointer 以保留调试信息和帧指针;推荐用 --call-graph dwarf 模式,并用 perf report -n --children 分析真实热点。

perf 不是 C++ 的一部分,它压根不认 C++ 语法或符号——你得让编译器保留调试信息、关掉内联,否则看到的全是 _Z12computeStuffv 或 ???,根本没法定位到具体函数。
编译时必须加 -g -O2 -fno-omit-frame-pointer
perf 依赖 DWARF 调试信息和可靠的调用栈展开。默认 -O2 会内联函数、删帧指针,导致 perf report 显示“inlined function”或栈帧断裂。
-
-g:生成 DWARF,不然 perf 看不到源码行号和函数名 -
-fno-omit-frame-pointer:强制保留%rbp(x86_64),让perf record -g能正确回溯调用链 - 别用
-O3:过度优化会让热函数消失在 inlined frames 里,perf annotate失效 - 如果用了 LTO(
-flto),务必加-grecord-gcc-switches,否则链接后调试信息丢失
perf record -g --call-graph dwarf 比默认 fp 更靠谱
默认的 fp(frame pointer)模式在优化后极易断栈;dwarf 模式读取 .debug_frame,能绕过被优化掉的帧指针,对现代 C++ 更友好。
- 运行命令:
perf record -g --call-graph dwarf -e cycles,instructions ./my_app - 注意:需要 kernel 支持
CONFIG_DEBUG_INFO_DWARF4=y(多数发行版已启用) - 如果提示
failed to open event ... No such file or directory,说明内核没开CONFIG_PERF_EVENTS,不是你代码的问题 -
perf script输出的是原始采样流,适合 grep 函数名,但别直接 human-read
perf report -n --children 看清谁真正吃 CPU
perf report 默认按“采样点所在函数”排序,容易误判——比如 std::vector::push_back 高,实际是上层循环调用它太多次。用 --children 才能看“这个函数及其所有子调用共占多少周期”。
立即学习“C++免费学习笔记(深入)”;
-
perf report -n --children:显示自顶向下累积开销,Children列才是关键指标 -
-n显示采样次数,比百分比更稳定(尤其短时间采样) - 遇到
__libc_start_main占比异常高?大概率是程序跑得太快,perf 没采到有效样本——加perf record -F 99提高采样频率,或用sleep(1)延长热点持续时间 - 如果
perf report里全是地址(如0x4012a3),说明-g没生效,或者二进制被 strip 过
最常被忽略的一点:perf 分析的是整个进程,包括 STL 内部、内存分配器、甚至动态链接器。想聚焦自己的代码,得用 perf report --symbol-filter=my_namespace::my_function 过滤,而不是靠眼睛扫几百行 std:: 调用。











