17

How do I enable C++ demangling for the perf callgraph? It seems to demangle symbols when I go into annotate mode, but not in the main callgraph.

Sample code (using 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();

build command:

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

perf commands:

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

I've also tried enabling the --demangle option, but that doesn't seem to affect the output.

callgraph missing demangled symbols:

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

annotated disassembly showing demangled calls:

       │
       │    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.29 │      mov    %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.71 │      mov    %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

System info:

  • Ubuntu 15.04 64-bit
  • Intel i5-6600k
  • perf 3.19.8-ckt6
  • clang 3.6.0-2ubuntu1
helloworld922
  • 10,197
  • 3
  • 43
  • 80

2 Answers2

35

I had the same problem on the Ubuntu 15.10 and I found the solution here: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654

Update: works also for Ubuntu 18.10

Here are the steps:

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

There should be also some way to create a new linux-tools-common package to really integrate it into your system. For now to override the official perf with your new one, just set your PATH:

export PATH=~/install/linux-`uname -r | sed 's/-.*//'`/tools/perf:$PATH
Michal Fapso
  • 1,092
  • 13
  • 21
  • 2
    In my case, I could not download the ubuntu Linux Kernel source with apt-get source because the package was not found. Instead, I downloaded it from https://packages.ubuntu.com/ . Then, I could build it by directly executing make in the tools/perf directory of the downloaded package (after installing libiberty-dev binutils-dev as mentioned in the answer but without the apt-get build-dep step). – aleixrocks Nov 17 '17 at 09:07
  • 2
    If downloading the package manually causes too many troubles, you can also try to enable the source PPAs in `/etc/apt/sources.list`. Simply uncomment the `deb-src` lines, save the file, and update the package cache with `sudo apt-get update`. Then the `apt-get source` should work (at least it did for me). – ctitze Jul 11 '18 at 10:12
  • ubuntu16.04, when `make` got `'__NR_perf_event_open' undeclared` error.. – cifer Oct 18 '18 at 17:19
  • I'm having this problem on Ubuntu 18.04. Rebuilding the package (`debuild`) just produces another `perf` command with the same problem, i.e., no demangling. – Kristian Spangsege Nov 14 '18 at 12:40
  • @cli__, are you sure you have whole linux-... source tree? Because that `__NR_perf_event_open` is declared in `./arch` and `./tools/arch`. Did you download the source with `apt-get source ...`? – Michal Fapso Nov 28 '18 at 22:02
  • @KristianSpangsege, when you run `make`, after few lines it shows `Auto-detecting system features:` followed by a list of features. You want to have every feature turned on. If it says `off`, just download that particular library. You can try `sudo apt install libdwarf-dev libaudit-dev libelf-dev libperl-dev libunwind-dev libdw-dev`, then remove your old linux source directory, re-download it and try a new clean build. – Michal Fapso Nov 28 '18 at 22:07
  • 1
    I use alias ```mperf=~/install/linux-`uname -r | sed 's/-.*//'`/tools/perf```, this way your PATH is preserved and you just invoke `mperf` instead of `perf` – Kovalex Jan 28 '19 at 12:25
  • 2
    @cli, to get around the `'__NR_perf_event_open' undeclared` error on 16.04, I had to remove/rename `linux-4.4.0/tools/perf/util/include/asm/unistd_64.h` (it was an empty file, and with it gone the compiler could fine the file it needed). – Paul Brannan Feb 15 '19 at 18:57
  • @aleixrocks could you, please, provide more details about what I should download manually from packages.ubuntu.com – diralik May 07 '19 at 11:03
1

If you don't understand what to download from packages.ubuntu.com (as in the first answer), then you also can download linux kernel sources from git:

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

And modify path (as in the first answer):

export PATH=~/install/linux/tools/perf:$PATH
diralik
  • 3,855
  • 2
  • 20
  • 43
  • Or just download perf targz from https://mirrors.edge.kernel.org/pub/linux/kernel/tools/perf/ – osgx Feb 22 '20 at 08:13