perf record 看不到函数名是因为编译未加 -g(缺失调试信息)或未加 -fno-omit-frame-pointer(优化导致栈展开失败),而非 perf 本身问题。

perf record 采样时为什么看不到函数名?
默认用 perf record 抓不到符号,是因为编译没带调试信息或优化干扰了帧指针。不是 perf 本身有问题,是二进制里没留够线索。
- 编译必须加
-g(生成 DWARF),否则perf report只能显示地址,没法映射到函数 - 加
-fno-omit-frame-pointer,尤其在-O2或更高优化下,否则调用栈会断——perf依赖帧指针做栈展开 - 避免用
-flto(LTO),它会合并/重命名函数,导致符号丢失或错乱 - 运行前确认
/proc/sys/kernel/perf_event_paranoid≤ 2,否则普通用户无法采集内核态事件
gprof 报 “flat profile: no data” 怎么办?
这表示程序根本没生成 gmon.out,不是分析工具坏了,是链接或运行环节漏了关键步骤。
- 编译和链接都得加
-pg:只编译加不行,链接时没-pg会导致监控代码被丢弃 - 程序必须正常退出(比如 return 或 exit()),靠 kill -9 杀掉不会写
gmon.out - 如果用了 fork(),子进程默认不生成
gmon.out;要手动调moncontrol(1)开启 -
gprof只支持 a.out 格式或传统 ELF,对 PIE(-pie)二进制支持差,容易报错或数据为空
perf vs gprof:什么时候该选哪个?
不是“哪个更好”,是“哪个能跑通 + 能回答当前问题”。两者底层机制完全不同,混用会白忙活。
-
perf是基于硬件 PMU 的采样器,开销低(~1%),支持 CPU cycle / cache-miss / context-switch 等多维事件,但只能看热点,不能直接给出函数间调用耗时 -
gprof是插桩(instrumentation),会在每个函数入口/出口埋计数,能出调用图(call graph)和每条调用路径耗时,但开销大(常 >10x),且不支持多线程安全计数 - 想定位 cache line bouncing?用
perf record -e cache-misses;想查某个函数被谁高频调用?gprof -q输出调用关系更直接 -
gprof对 inline 函数、模板实例化、RAII 析构等场景统计失真严重;perf不受这些影响,但看不到 C++ 异常栈展开细节
perf script 输出里出现大量 [unknown] 或 [kernel.kallsyms]?
说明符号解析失败,不是数据丢了,是 perf 找不到对应符号表位置。
立即学习“C++免费学习笔记(深入)”;
- 检查是否用了
strip处理过二进制——strip 会删掉 .symtab 和 .dynsym,perf就只能靠 /proc/kallsyms 或 vmlinux 猜 - 内核模块没加载 debuginfo 包(如
kernel-debuginfo),[kernel.kallsyms] 就没法映射到具体函数 - 用
perf buildid-list确认 build-id 是否匹配;不匹配时perf report --symfs指定符号路径也无效 - 容器环境里,宿主机的
/usr/lib/debug通常没挂进去,得显式 bind mount 或用perf archive打包符号再分析
perf 的 symbol resolution 和 gprof 的插桩时机,都是悄无声息就失效的点。没看到函数名,先别怀疑工具,去翻编译参数和二进制属性。











