You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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包
  • 默认栈回溯方式的局限性: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 00:47:52