perf record 看不到函数名是因为二进制缺少调试信息(需编译加 -g),导致符号无法解析,表现为 [unknown] 或 __libc_start_main,应检查 debuginfo 是否存在、未被 strip、build-id 是否完整,并确保 cmake 构建类型为 relwithdebinfo。

perf record 采样时为什么看不到函数名?
默认编译没带调试信息,perf 只能拿到地址,没法映射到符号。不是 perf 有问题,是你的二进制缺 -g 或 -gdwarf-4。
- 编译必须加
-g(推荐-g -O2,调试信息和优化不冲突) - 如果用 CMake,确认
CMAKE_BUILD_TYPE不是Release(它默认关-g),改用RelWithDebInfo - 动态库也要单独带调试信息,否则
perf report进不去 SO 里的函数 - 检查是否被 strip 过:
file your_binary输出里要有 “with debug_info”
perf report 显示的开销集中在 [unknown] 或 [.] __libc_start_main
这是符号解析失败的典型表现,常见于内联函数、JIT 代码或未加载 debuginfo 的系统库。
- 先运行
perf buildid-list -i perf.data看有没有缺失的 build-id;再用perf buildid-cache -v --add /lib/x86_64-linux-gnu/libc.so.6补全 - 若程序用了
std::function或 lambda,GCC/Clang 默认会内联,perf就只看到调用点,看不到实际逻辑 —— 加-fno-inline-functions临时编译可验证 - 容器环境要注意:宿主机跑
perf record -p $(pidof your_app),但容器里没装debuginfod或没挂载/usr/lib/debug,也会显示[unknown]
怎么只分析某个函数的 CPU 时间,而不是整个进程?
perf record 本身不支持函数级过滤,得靠 --call-graph + 后处理,或者用 perf probe 打点。
- 最稳的方法:用
perf record -e cycles,instructions -g --call-graph dwarf -- ./your_program,然后perf report --no-children -g --sort comm,dso,symbol,再用/搜索目标函数名 - 想精确卡住某函数入口/出口,用
perf probe 'your_namespace::your_function'(需有调试信息),再perf record -e probe:your_function* - 注意:
perf probe对模板实例化函数支持有限,比如std::vector<int>::push_back</int>很可能找不到,优先试具体实现函数(如__gnu_cxx::new_allocator::allocate)
perf 跟踪多线程程序时,CPU 占用率虚高或线程 ID 对不上?
perf record 默认按线程采样,但线程复用、pthread_create 后快速退出等情况会让 perf script 输出的 tid 和你 ps 看到的不一致。
立即学习“C++免费学习笔记(深入)”;
- 加
-t参数显式指定 tid:perf record -t -p $(pgrep -f "your_binary"),避免父进程干扰 - 多线程高频锁竞争场景,
cycles事件会严重失真(大量停顿在futex_wait_queue_me),换用cpu/event=0x02c4,umask=0x20,name=stalls_ldm_full/(Intel)这类微架构事件更准 -
perf record -e task-clock,context-switches,page-faults是比单纯看 cycles 更可靠的吞吐视角
实际调优时,最常被跳过的一步是验证「问题是否复现」:同一份 perf.data 在不同机器上 perf report 结果可能不同,因为 kernel 版本、perf 版本、甚至 /proc/sys/kernel/perf_event_paranoid 设置都影响符号解析深度。别急着改代码,先确认你能稳定看到那个热点函数。











