linux perf:如何解读和查找热点

mil*_*anw 43 c++ linux performance profiling perf

我今天尝试了linux的perf实用程序,但在解释其结果方面遇到了麻烦.我已经习惯了valgrind的callgrind,这当然是一种完全不同于基于采样的perf方法的方法.

我做了什么:

perf record -g -p $(pidof someapp)
perf report -g -n
Run Code Online (Sandbox Code Playgroud)

现在我看到这样的事情:

+     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 
...

好的,这些功能可能很慢,但我怎样才能找到它们的调用位置?由于所有这些热点都在外部库中,我认为没有办法优化我的代码.

基本上我正在寻找带有累积成本注释的某种调用图,其中我的函数具有比我调用的库函数更高的包容性采样成本.

这可能与perf有关吗?如果是这样 - 怎么样?

注意:我发现"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位系统).

mil*_*anw 39

使用Linux 3.7 perf最终能够使用DWARF信息生成调用图:

perf record --call-graph dwarf -- yourapp
perf report -g graph --no-children
Run Code Online (Sandbox Code Playgroud)

整洁,但与VTune,KCacheGrind或类似的相比,curses GUI是可怕的......我建议尝试使用FlameGraphs,这是一个非常简洁的可视化:http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

注意:在报告步骤中,-g graph使结果输出变得简单,以便理解"相对于总数"百分比,而不是"相对于父"数字.--no-children将只展示自我成本,而不是包容性成本 - 这一点我也觉得非常宝贵.

如果您有一个新的perf和Intel CPU,还可以试用LBR开卷器,它具有更好的性能并产生更小的结果文件:

perf record --call-graph lbr -- yourapp
Run Code Online (Sandbox Code Playgroud)

这里的缺点是与默认的DWARF退绕器配置相比,调用堆栈深度更加有限.

  • 有http://code.google.com/p/jrfonseca/wiki/Gprof2Dot能够将perf输出转换为点图 (9认同)
  • 您可以使用[FlameGraph](http://www.brendangregg.com/flamegraphs.html)对采样调用堆栈时的hapenning进行很好的虚拟化. (2认同)

Ser*_*kov 19

好的,这些功能可能很慢,但我怎样才能找到它们的调用位置?由于所有这些热点都在外部库中,我认为没有办法优化我的代码.

您确定您的应用程序someapp是使用gcc选项-fno-omit-frame-pointer(可能还有其依赖库)构建的吗?像这样的东西:

g++ -m64 -fno-omit-frame-pointer -g main.cpp
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个答案为时已晚,无法得到所有的赞成,因为`-fno-omit-frame-pointer`是分析中最重要的事情. (5认同)

Mar*_*rdy 15

您应该尝试热点:https: //www.kdab.com/hotspot-gui-linux-perf-profiler/

它可以在github上找到:https://github.com/KDAB/hotspot

例如,它可以为您生成火焰图.

flamegraph

  • 确实是的.请注意,我是热点的主要作者:)我抓了自己的痒! (11认同)

Ali*_*Ali 11

您可以获得非常详细的源级别报告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>
[...]
Run Code Online (Sandbox Code Playgroud)

编译代码时不要忘记传递-fno-omit-frame-pointer-ggdb标记.


Mik*_*vey 5

除非你的程序功能非常少,并且几乎不会调用系统函数或I/O,否则采样程序计数器的分析器不会告诉你太多,正如你所发现的那样.实际上,着名的profiler gprof是专门为了解决无自我时间分析的无用性而设计的(并非成功).

实际上工作的是对调用堆栈进行采样(从而找出调用的来源),挂钟时间(从而包括I/O时间),逐行或按指令报告(从而精确定位函数调用)你应该调查,而不仅仅是他们所居住的功能.

此外,您应该查找的统计数据是堆栈上的时间百分比,而不是呼叫数量,而不是平均包含功能时间.特别是不是"自我时间". 如果一个呼叫指令(或非呼叫指令)在38%的时间内在堆栈上,那么如果你可以摆脱它,你会节省多少钱?38%! 很简单,不是吗?

这种分析器的一个例子是Zoom.

关于这个问题还有许多问题需要理解.

补充:@caf让我搜索perf信息,因为你包含了命令行参数,-g它确实收集了堆栈样本.然后,您可以获得呼叫树报告.然后,如果你确定你在挂钟时间上采样(所以你得到等待时间以及cpu时间)那么你几乎得到了你所需要的.

  • `perf`*对*调用堆栈进行采样.只是OP生成的报告只显示了叶子. (10认同)
  • @caf:那我怎么显示整棵树呢? (2认同)