[英]linux perf: how to interpret and find hotspots
我今天尝试了 linux 的perf实用程序,但在解释其结果时遇到了麻烦。 我已经习惯了 valgrind 的 callgrind,这当然是与基于采样的 perf 方法完全不同的方法。
我做了什么:
perf record -g -p $(pidof someapp)
perf report -g -n
现在我看到这样的东西:
+ 16.92% kdevelop libsqlite3.so.0.8.6 [.] 0x3fe57 ↑ + 10.61% kdevelop libQtGui.so.4.7.3 [.] 0x81e344 ▮ + 7.09% kdevelop libc-2.14.so [.] 0x85804 ▒ + 4.96% kdevelop libQtGui.so.4.7.3 [.] 0x265b69 ▒ + 3.50% kdevelop libQtCore.so.4.7.3 [.] 0x18608d ▒ + 2.68% kdevelop libc-2.14.so [.] memcpy ▒ + 1.15% kdevelop [kernel.kallsyms] [k] copy_user_generic_string ▒ + 0.90% kdevelop libQtGui.so.4.7.3 [.] QTransform::translate(double, double) ▒ + 0.88% kdevelop libc-2.14.so [.] __libc_malloc ▒ + 0.85% kdevelop libc-2.14.so [.] memcpy ...
好的,这些函数可能很慢,但是我如何找出它们是从哪里调用的呢? 由于所有这些热点都位于外部库中,因此我看不到优化代码的方法。
基本上我正在寻找某种带有累积成本注释的调用图,其中我的函数比我调用的库函数具有更高的包容性采样成本。
这可能与性能有关吗? 如果是这样 - 如何?
注意:我发现“E”打开了调用图并提供了更多信息。 但是调用图通常不够深和/或随机终止,而没有提供有关在哪里花费了多少信息的信息。 例子:
- 10.26% kate libkatepartinterfaces.so.4.6.0 [.] Kate::TextLoader::readLine(int&... Kate::TextLoader::readLine(int&, int&) Kate::TextBuffer::load(QString const&, bool&, bool&) KateBuffer::openFile(QString const&) KateDocument::openFile() 0x7fe37a81121c
这可能是我在 64 位上运行的问题吗? 另请参阅: http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html (我没有使用 Fedora,但似乎适用于所有 64 位系统)。
使用 Linux 3.7 perf 终于能够使用 DWARF 信息来生成调用图:
perf record --call-graph dwarf -- yourapp
perf report -g graph --no-children
整洁,但与 VTune、KCacheGrind 或类似的相比,curses GUI 很糟糕......我建议尝试使用 FlameGraphs,这是一个非常简洁的可视化: http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html
注意:在报告步骤中, -g graph
使结果 output 易于理解“相对于总数”的百分比,而不是“相对于父级”的数字。 --no-children
将只显示自我成本,而不是包含成本——我也发现这个功能非常宝贵。
如果你有一个新的性能和 Intel CPU,也可以试试 LBR unwinder,它有更好的性能并产生更小的结果文件:
perf record --call-graph lbr -- yourapp
这里的缺点是调用堆栈深度与默认的 DWARF 展开器配置相比更加有限。
好的,这些函数可能很慢,但是我如何找出它们是从哪里调用的呢? 由于所有这些热点都位于外部库中,因此我看不到优化代码的方法。
您确定您的应用程序someapp
是使用 gcc 选项-fno-omit-frame-pointer
(可能还有它的依赖库)构建的吗? 像这样的东西:
g++ -m64 -fno-omit-frame-pointer -g main.cpp
你应该试试热点: https://www.kdab.com/hotspot-gui-linux-perf-profiler/
它在 github 上可用: https://github.com/KDAB/hotspot
例如,它能够为您生成火焰图。
您可以使用 perf annotate 获得非常详细的源级报告,请参阅使用perf annotate
的源级分析。 它看起来像这样(无耻地从网站上窃取):
------------------------------------------------
Percent | Source code & Disassembly of noploop
------------------------------------------------
:
:
:
: Disassembly of section .text:
:
: 08048484 <main>:
: #include <string.h>
: #include <unistd.h>
: #include <sys/time.h>
:
: int main(int argc, char **argv)
: {
0.00 : 8048484: 55 push %ebp
0.00 : 8048485: 89 e5 mov %esp,%ebp
[...]
0.00 : 8048530: eb 0b jmp 804853d <main+0xb9>
: count++;
14.22 : 8048532: 8b 44 24 2c mov 0x2c(%esp),%eax
0.00 : 8048536: 83 c0 01 add $0x1,%eax
14.78 : 8048539: 89 44 24 2c mov %eax,0x2c(%esp)
: memcpy(&tv_end, &tv_now, sizeof(tv_now));
: tv_end.tv_sec += strtol(argv[1], NULL, 10);
: while (tv_now.tv_sec < tv_end.tv_sec ||
: tv_now.tv_usec < tv_end.tv_usec) {
: count = 0;
: while (count < 100000000UL)
14.78 : 804853d: 8b 44 24 2c mov 0x2c(%esp),%eax
56.23 : 8048541: 3d ff e0 f5 05 cmp $0x5f5e0ff,%eax
0.00 : 8048546: 76 ea jbe 8048532 <main+0xae>
[...]
编译代码时不要忘记传递-fno-omit-frame-pointer
和-ggdb
标志。
除非您的程序具有很少的功能并且几乎不会调用系统 function 或 I/O,否则对程序计数器进行采样的分析器不会告诉您太多,正如您所发现的那样。 事实上,著名的分析器gprof是专门创建的,以尝试解决仅自我分析的无用性(并不是说它成功了)。
真正起作用的是对调用堆栈进行采样(从而找出调用来自何处),在挂钟时间(从而包括 I/O 时间),并按行或按指令报告(从而查明 function 调用您应该调查,而不仅仅是他们所在的功能)。
此外,您应该查找的统计数据是堆栈时间百分比,而不是调用次数,而不是平均包含 function 时间。 尤其不是“自我时间”。 如果调用指令(或非调用指令)有 38% 的时间在堆栈中,那么如果你可以摆脱它,你会节省多少? 38%! 很简单,不是吗?
此类分析器的一个示例是Zoom 。
在这个问题上还有更多的问题需要理解。
补充: perf
让我寻找性能信息,并且由于您包含命令行参数-g
它确实收集堆栈样本。 然后您可以获得调用树报告。 然后,如果您确保您在挂钟时间进行采样(因此您可以获得等待时间和 cpu 时间),那么您几乎得到了您需要的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.