启用性能分析工具对调用图的符号解析

17

如何在perf callgraph中启用C++符号重整?当我进入annotate模式时,它似乎会对符号进行解析,但在主callgraph中没有。

示例代码(使用Google Benchmark):

#include <benchmark/benchmark.h>
#include <vector>

static __attribute__ ((noinline)) int my_really_big_function()
{
  for(size_t i = 0; i < 1000; ++i)
  {
    benchmark::DoNotOptimize(i % 5);
  }
  return 0;
}

static __attribute__ ((noinline)) void caller1()
{
  for(size_t i = 0; i < 1000; ++i)
  {
    benchmark::DoNotOptimize(my_really_big_function());
    benchmark::DoNotOptimize(i % 5);
  }
}

static __attribute__ ((noinline)) void myfun(benchmark::State& state)
{
  while(state.KeepRunning())
  {
    caller1();
  }
}

BENCHMARK(myfun);

BENCHMARK_MAIN();

构建命令:

clang++ main.cpp -o main -fno-omit-frame-pointer -O0 -lpthread -lbenchmark

性能指令:

perf record -g ./main
perf report -g 'graph,0.5,caller'

我也尝试启用了 --demangle 选项,但似乎没有影响输出。

调用图缺少解码符号:

Samples: 3K of event 'cycles', Event count (approx.): 2946754102
Children      Self  Command  Shared Object      Symbol
+   99.82%     0.00%  main     main               [.] _ZL5myfunRN9benchmark5StateE
+   99.82%     0.00%  main     main               [.] _ZN9benchmark12_GLOBAL__N_111RunInThreadEPKNS_8internal9Benchmark8InstanceEmiPNS0_11ThreadStatsE
+   99.82%     0.00%  main     main               [.] _ZN9benchmark22RunSpecifiedBenchmarksEPNS_17BenchmarkReporterE
+   99.82%     0.00%  main     main               [.] main
+   99.82%     0.00%  main     libc-2.21.so       [.] __libc_start_main
+   99.82%     0.00%  main     [unknown]          [.] 0x7fbe258d4c544155
+   99.75%     0.30%  main     main               [.] _ZL7caller1v
+   99.52%    99.46%  main     main               [.] _ZL22my_really_big_functionv

带注释的反汇编,显示已解析的调用:

       │
       │    0000000000404310 <caller1()>:
       │    _ZL7caller1v():
       │      push   %rbp
       │      mov    %rsp,%rbp
       |    $0x30,%rsp
       |   $0x0,-0x18(%rbp)
       │10:   cmpq   $0x3e8,-0x18(%rbp)
       │    ↓ jae    6f
       │    → callq  my_really_big_function()
       │      lea    -0x1c(%rbp),%rcx
       │      mov    %eax,-0x1c(%rbp)
 14.29mov    %rcx,-0x10(%rbp)
       │      mov    -0x10(%rbp),%rcx
       │      lea    -0x28(%rbp),%rcx
       │      mov    $0x5,%eax
       │      mov    %eax,%edx
       │      mov    -0x18(%rbp),%rax
       │      xor    %esi,%esi
       │      mov    %rdx,-0x30(%rbp)
       │      mov    %esi,%edx
       │      mov    -0x30(%rbp),%rdi
       │      div    %rdi
 85.71mov    %rdx,-0x28(%rbp)
       │      mov    %rcx,-0x8(%rbp)
       │      mov    -0x8(%rbp),%rcx
       │      mov    -0x18(%rbp),%rax
       │      add    $0x1,%rax
       │      mov    %rax,-0x18(%rbp)
       │    ↑ jmpq   10
       │6f:   add    $0x30,%rsp
       │      pop    %rbp
       │    ← retq

系统信息:

  • Ubuntu 15.04 64位
  • Intel i5-6600k处理器
  • perf版本为3.19.8-ckt6
  • clang版本为3.6.0-2ubuntu1

奇怪的是,它总是默认为我解缠(有时这很痛苦,因为解缠后的名称不合适)。 - Marc Glisse
2个回答

36

我在Ubuntu 15.10上遇到了同样的问题,后来在这里找到了解决方案:https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654

更新:对于Ubuntu 18.10也适用。

以下是步骤:

sudo apt-get install libiberty-dev binutils-dev
mkdir ~/install
cd ~/install
# If the following apt-get doesn't work on your system,
# uncomment deb-src lines in your /etc/apt/sources.list,
# as suggested by @ctitze
# or you can download it manually from packages.ubuntu.com
# as @aleixrocks suggested in the comment below
apt-get source linux-tools-`uname -r`
sudo apt-get build-dep linux-tools-`uname -r`
cd linux-`uname -r | sed 's/-.*//'`/tools/perf
make

# now you should see the new "perf" executable here
./perf

同时还应该有一种方式来创建一个新的linux-tools-common包,真正将其集成到您的系统中。目前为了使用你的新执行文件覆盖官方版本,只需设置您的路径即可:

export PATH=~/install/linux-`uname -r | sed 's/-.*//'`/tools/perf:$PATH

2
在我的情况下,我无法通过apt-get source下载ubuntu Linux内核源代码,因为找不到该软件包。相反,我从https://packages.ubuntu.com/下载了它。然后,在已下载软件包的tools/perf目录中直接执行make命令即可构建它(在安装libiberty-dev binutils-dev时按照答案中提到的步骤进行,但不需要进行apt-get build-dep步骤)。 - aleixrocks
2
如果手动下载软件包会带来太多麻烦,您也可以尝试在/etc/apt/sources.list中启用源PPA。只需取消注释deb-src行,保存文件,并使用sudo apt-get update更新软件包缓存。然后apt-get source应该可以工作(至少对我而言是这样)。 - ctitze
我在Ubuntu 18.04上遇到了这个问题。重新构建包(debuild)只会生成另一个具有相同问题的perf命令,即没有解缠缠绕。 - Kristian Spangsege
1
我使用别名mperf=~/install/linux-`uname -r | sed 's/-.*//'`/tools/perf,这样可以保留你的PATH,并且你只需要调用mperf而不是perf - Kovalex
2
为了解决16.04上的“'__NR_perf_event_open'未声明”错误,我不得不删除/重命名linux-4.4.0/tools/perf/util/include/asm/unistd_64.h(它是一个空文件,删除后编译器可以找到所需的文件)。 - Paul Brannan
显示剩余4条评论

3
如果你不理解从packages.ubuntu.com下载什么(就像最初的回答中所说),那么你也可以从git下载linux内核源码。
sudo apt-get install libiberty-dev binutils-dev
mkdir ~/install
cd ~/install
git clone https://github.com/torvalds/linux --depth 1
cd linux/tools/perf
make

# now you should see the new "perf" executable here
./perf
<最初的回答>中提到的方法可以修改路径(即第一个答案中所述):
export PATH=~/install/linux/tools/perf:$PATH

1
或者您可以从 https://mirrors.edge.kernel.org/pub/linux/kernel/tools/perf/ 下载 perf targz。 - osgx

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