为何gdb回溯比perf调用栈显示的细节更丰富?
问题描述
我用perf分析一段示例代码的热点,得到如下结果:
- 63.93% 0.10% bonds libc.so.6 [.] __GI___fstatat64 63.82% __GI___fstatat64 - 63.82% 63.82% bonds [unknown] [k] 0xffffffffa90001a2 __GI___fstatat64 + 5.32% 0.00% bonds [unknown] [.] 0000000000000000
可见大部分耗时集中在glibc的__GI___fstatat64函数中。但使用gdb调试时,能获取到完整的调用栈回溯:
(gdb) bt #0 __GI___fstatat64 (fd=fd@entry=-100, file=file@entry=0x7ffff59bb46b "/etc/localtime", buf=buf@entry=0x7fffffffd440, flag=flag@entry=0) at ../sysdeps/unix/sysv/linux/fstatat64.c:154 #1 0x00007ffff591d706 in __GI___stat64 (file=file@entry=0x7ffff59bb46b "/etc/localtime", buf=buf@entry=0x7fffffffd440) at ../sysdeps/unix/sysv/linux/stat64.c:29 #2 0x00007ffff58eb174 in __tzfile_read (file=file@entry=0x7ffff59bb46b "/etc/localtime", extra=extra@entry=0, extrap=extrap@entry=0x0) at tzfile.c:159 #3 0x00007ffff58ead24 in tzset_internal (always=<optimized out>) at tzset.c:405 #4 0x00007ffff58eaf23 in __tz_convert (timer=1681057207, use_localtime=1, tp=0x7ffff59fd660 <_tmbuf>) at tzset.c:577 #5 0x00007ffff6da62ae in QuantLib::Date::todaysDate () at /mnt/hdd1/sandbox/temp/QuantLib/ql/time/date.cpp:770 #6 0x00007ffff67e4a35 in QuantLib::Settings::DateProxy::operator QuantLib::Date ( this=0x7ffff7e238a0 <QuantLib::Singleton<QuantLib::Settings, std::integral_constant<bool, false> >::instance()::instance>) at /mnt/hdd1/sandbox/temp/QuantLib/ql/settings.hpp:136 #7 QuantLib::Bond::isExpired (this=0x7fffffffda00) at /mnt/hdd1/sandbox/temp/QuantLib/ql/instruments/bond.cpp:107 #8 0x000000000040eb9c in QuantLib::Instrument::calculate (this=0x7fffffffda00) at /usr/local/include/ql/instrument.hpp:148 #9 0x00000000004103fa in QuantLib::Instrument::NPV (this=this@entry=0x7fffffffda00) at /usr/local/include/ql/instrument.hpp:185 #10 0x000000000040e272 in go () at /mnt/hdd1/sandbox/work/cpp/quantlib/bonds.cpp:93
我使用-Og -ggdb3编译代码,通过perf record -g ./bonds和perf report -g执行perf分析,为何无法在perf中看到同样完整的调用栈?
原因及解决办法
glibc缺少调试符号:系统默认安装的glibc通常不带调试符号,导致perf无法解析
__GI___fstatat64上层的调用栈。需要安装对应系统的glibc调试包:- Debian/Ubuntu系:安装
libc6-dbg包 - RHEL/CentOS系:安装
glibc-debuginfo和glibc-debuginfo-common包
- Debian/Ubuntu系:安装
默认栈回溯方式的局限性:
perf record -g默认使用帧指针(fp)回溯,但glibc本身可能是用更高优化级别编译并移除了帧指针,导致栈回溯中断。改用dwarf方式采样可以解决这个问题:perf record -g dwarf ./bonds之后用
perf report -g dwarf查看结果,该方式依赖调试信息,能更精准地回溯调用栈。内核空间地址解析问题:结果中的
[unknown] [k] 0xffffffffa90001a2是内核空间地址,perf在用户态与内核态切换时可能丢失栈信息。若需要解析内核栈,需安装内核调试符号,或在采样时明确指定dwarf方式覆盖全栈解析。QuantLib库的调试符号缺失:如果QuantLib是预编译安装的,可能没有包含调试符号。若为自行编译,需确保编译时添加
-g或-ggdb3参数,且不要执行strip操作移除符号表。
内容的提问来源于stack exchange,提问作者imrichardcole
相关产品推荐
相关产品推荐

