如何使用Linux perf调用libc6符号(如_int_malloc)以获取父级?

8
我正在使用Linux perf对C++应用程序进行分析,并使用GProf2dot生成了一个不错的控制流图。然而,来自C库(libc6-2.13.so)的一些符号占用了相当大的时间比例,但没有任何入边。
例如:
_int_malloc 占用了8%的时间,但没有任何调用者。
__strcmp_sse42和__cxxabiv1::__si_class_type_info::__do_dyncast共占用了约10%的时间,并且有一个名为0的调用者,该调用者有调用者2d6935c、2cc748c和6,这些调用者没有调用者。
因此,仅使用perf就无法找出哪些例程负责所有这些malloc和动态转换。但是,似乎其他符号(如malloc但不包括_int_malloc)确实有调用父项。
为什么perf在_int_malloc时不显示调用父级函数?我找不到__do_dyn_cast的最终调用者。有没有办法修改我的设置以获取这些信息?我使用x86-64,所以我想知道是否需要带有帧指针的(非标准)libc6。

+1 对于MCMC,欢迎来到SO。 - Mike Dunlavey
2个回答

5
更新:自3.7.0内核以来,可以使用perf record -gdwarf <command>确定系统库符号的调用父级。
使用-gdwarf,无需使用-fno-omit-frame-pointer编译。
原回答: 目前(2012年5月24日)在x86_64上可能需要使用带有帧指针(-fno-omit-framepointer)的libc6。
但是,开发人员正在努力让perf工具使用DWARF展开信息。这意味着在x86_64上不再需要帧指针来获取回溯信息。然而,Linus不想在内核中使用DWARF展开程序。因此,perf工具将保存系统运行时的寄存器,并使用libunwind库在用户空间perf工具中进行DWARF展开。
这种技术已经测试成功地确定了(例如)mallocdynamic_cast的调用者。但是,补丁集尚未集成到Linux内核中,并且需要进一步修订才能准备就绪。

谢谢。在我的机器上,需要使用“--call-graph dwarf”而不是“-gdwarf”。 - Lack
即使使用带有帧指针的libc6编译,这种情况仍会发生。 - nnnmmm

1

_int_malloc__do_dyn_cast正在从无法识别的例程中调用,因为分析器没有它们的符号表信息。

此外,看起来你正在显示自身(独占)时间。这仅对于查找具有大量自身时间且可以修复的例程中的热点非常有用。

Unix原始profil之后创建了性能分析器的原因是真正的软件由几乎所有时间都在调用其他函数的函数组成,您需要能够找到大部分时间都在堆栈上的代码,而不是程序计数器大部分时间所在的代码。

因此,您需要配置perf以进行堆栈采样,并告诉您每个您的例程在堆栈上的时间百分比。如果它不仅报告例程,而且还报告代码行,那就更好了,就像Zoom一样。最好在挂钟时间上进行采样,这样您就不会对IO视而不见。

关于所有这些还有更多要说的。


谢谢Mike。我已经获得了自身时间和调用者时间(我使用perf record -g获取了调用堆栈)。我无法对执行动态转换所花费的时间做太多事情(g++真的会将typeinfo与strcmp进行比较吗?),但我计划确保尽量减少动态转换(和内存分配)的次数。为了做到这一点,知道是什么在调用动态转换和malloc函数会很好。 - BenRI
谢谢Mike。我已经获得了自身时间和调用者时间(我使用了perf record -g)。显然,我无法使malloc或dynamic_cast更快,因此我正在尝试找出哪些例程在调用它们,并首先修复最严重的违规行为。我认为问题在于内核可能在某些情况下(注意,不是所有情况)难以解开堆栈帧,我很好奇为什么内核无法解开堆栈并找到(比如)__strcmp_sse_42的调用者。我猜测这是用于比较typeinfo对象,但如果不知道调用者,很难确定。 - BenRI
1
@BenRI:那个链接讨论了我是如何做到的,而*此链接*则展示了通过找到并解决一系列类似问题,获得约700倍整体加速比的简短幻灯片演示。 - Mike Dunlavey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接