Linux下perf栈回溯跳过函数/显示调用_init的问题求助
perf采样栈回溯错误的排查与解决咨询
环境与测试设置
我编写了一个简单C++程序,使用编译参数-O0 -g -fno-omit-frame-pointer -fno-inline编译,运行环境为Ubuntu系统+Intel 9900K处理器。
全系统采样录制命令如下:
timeout 3 perf record -a -g -F 99 -- ./program perf script > out.perf && ../FlameGraph/stackcollapse-perf.pl out.perf > out.folded
测试程序代码:
#include <cmath> #include <cstdlib> #include <iostream> #include <cstdint> double a(double aa) { return sqrt(aa); } int main() { double aa = drand48(); for (size_t i = 0; i < UINT64_MAX; i++) { if (a(aa) == 0) { std::cout << std::endl; // 带副作用的操作 } } return 0; }
不同unwind策略下的错误栈回溯
DWARF策略
a_39391_[003]__3819.799248:;__libc_start_call_main;main;__sqrt 91016627 a_39391_[003]__3819.817492:;__libc_start_call_main;main;a 71222327 a_39391_[003]__3819.831741:;__libc_start_call_main;main;__ieee754_sqrt 62644598 a_39391_[003]__3819.844274:;__libc_start_call_main;main;a 58633093
问题:第1、3行显示main直接调用__sqrt/__ieee754_sqrt,跳过了中间的a函数。
LBR策略
a_40294_[000]__4306.958241:;_start;__libc_start_main@@GLIBC_2.34;__libc_start_call_main;main;a;_init 69630243 a_40294_[000]__4306.972230:;_start;__libc_start_main@@GLIBC_2.34;__libc_start_call_main;main 63241775 a_40294_[000]__4306.984884:;_start;__libc_start_main@@GLIBC_2.34;__libc_start_call_main;main;a;_init 59031331 a_40294_[000]__4306.996696:;_start;__libc_start_main@@GLIBC_2.34;__libc_start_call_main;main;a 56209420
问题:倒数第2行显示main调用a后指向_init,而非预期的sqrt。
FP(帧指针)策略
a_40380_[001]__4360.292014:;__libc_start_call_main;a 84184457 a_40380_[001]__4360.308855:;__libc_start_call_main;a 70243465 a_40380_[001]__4360.322906:;__libc_start_call_main;main;__sqrt 63725332
问题:最后一行显示__sqrt,缺失了a函数的调用层级。
代码调用关系验证
反汇编片段证明main确实调用a,a再调用sqrt:
00000000000011c0 <_Z1ad>: ... 11d2: e8 59 fe ff ff call 1030 <sqrt@plt> ... 00000000000011e0 <main>: ... 1211: e8 aa ff ff ff call 11c0 <_Z1ad>
确认函数未被内联或优化为jmp尾调用。
疑问
- 如何配置才能获取正确的栈回溯?
- 是否是因为perf异步采样时栈正在被修改,导致unwind错误?
- Linux下有没有工具能在采样时暂停目标线程,避免栈状态不一致?
内容的提问来源于stack exchange,提问作者meisel
相关产品推荐
相关产品推荐

