0

I'm trying to profile some C/C++ code inside Docker using pprof from gperftools (not pprof for golang).

When running it locally I have no problem. However, when running it in a Docker environment, pprof is unable to find the files/lines of the functions and instructions.

I'm installing gperftools (including pprof) the following way:

FROM debian:11

# Add dependencies
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && apt-get -y install \
  wget git cmake build-essential lsb-release software-properties-common && \
  rm -rf /var/lib/apt/lists/*

# Add libunwind
RUN wget -q https://github.com/libunwind/libunwind/releases/download/v1.6.2/libunwind-1.6.2.tar.gz && \
  tar -xzf libunwind-1.6.2.tar.gz && \
  cd libunwind-1.6.2 && \
  ./configure && \
  make -j $(cat /proc/cpuinfo | grep "cpu cores" | uniq | awk '{print $NF}') && \
  make install && \
  cd .. && \
  rm -rf libunwind-1.6.2 libunwind-1.6.2.tar.gz

# Add pprof
RUN wget -q https://github.com/gperftools/gperftools/releases/download/gperftools-2.10/gperftools-2.10.tar.gz && \
  tar -xzf gperftools-2.10.tar.gz && \
  cd gperftools-2.10 && \
  ./configure && \
  make -j $(cat /proc/cpuinfo | grep "cpu cores" | uniq | awk '{print $NF}') && \
  make install && \
  cd .. && \
  rm -rf gperftools-2.10 gperftools-2.10.tar.gz

Note that I'm installing libunwind manually because the apt installation does not install properly in system paths on Debian.

When profiling a code (compiled with no optimization, no inline, with symbols etc), and running:

pprof --no_strip_temp --text --files myexec prof.out

I get:

Total: 802 samples
     802 100.0% 100.0%      802 100.0% ?

while when doing it outside Docker, I have the proper list of files. However when listing samples for functions, I have a proper output, the functions are properly named and profiled.

When profiling at line level, the file and line which should be on the end of the line is replaced by a question mark

Total: 802 samples
       0   0.0%   0.0%      802 100.0% __libc_start_main@@GLIBC_2.2.5 ?
       0   0.0%   0.0%      802 100.0% _start ?
       0   0.0%   0.0%      802 100.0% main ?
     140  17.5%  17.5%      802 100.0% my_func ?
     130  16.2%  33.7%      130  16.2% my_namespace::Calculator::set_a ?
     130  16.2%  49.9%      130  16.2% my_namespace::Calculator::set_b ?
      47   5.9%  55.7%      114  14.2% my_namespace::Calculator::mul ?
      20   2.5%  58.2%       85  10.6% my_namespace::Calculator::add ?
      70   8.7%  67.0%       70   8.7% recurse ?
      65   8.1%  75.1%       65   8.1% add ?
      65   8.1%  83.2%       65   8.1% mul ?
      28   3.5%  86.7%       62   7.7% my_namespace::Calculator::sub ?
      34   4.2%  90.9%       34   4.2% sub ?
      31   3.9%  94.8%       31   3.9% my_namespace::Calculator::get_a ?
      18   2.2%  97.0%       18   2.2% double addT<double> ?
      14   1.7%  98.8%       14   1.7% double addT<int> ?
       8   1.0%  99.8%        8   1.0% my_namespace::Calculator::get_b ?
       2   0.2% 100.0%        2   0.2% _init ?

However, the file names and lines are present in the symbols:

> objdump -d -l ./myexec
[...]
0000000000001735 <sub>:
sub():
/path/to/my/project/libs/sub/sub.c:4
    1735:       55                      push   %rbp
    1736:       48 89 e5                mov    %rsp,%rbp
    1739:       f2 0f 11 45 f8          movsd  %xmm0,-0x8(%rbp)
    173e:       f2 0f 11 4d f0          movsd  %xmm1,-0x10(%rbp)
/path/to/my/project/libs/sub/sub.c:5
    1743:       f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
    1748:       f2 0f 5c 45 f0          subsd  -0x10(%rbp),%xmm0
    174d:       66 48 0f 7e c0          movq   %xmm0,%rax
/path/to/my/project/libs/sub/sub.c:6
    1752:       66 48 0f 6e c0          movq   %rax,%xmm0
    1757:       5d                      pop    %rbp
    1758:       c3                      retq   
    1759:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

I tried using recent/maintained golang version of pprof, it works and I have the file paths and lines.

However, it does not handle template functions properly (it is impossible to make the difference between 2 implementations of the same C++ template function).

Any clue with this problem?

Or is there a way, with the recent/maintained golang version of pprof to get functions template arguments?

Benjamin Barrois
  • 2,566
  • 13
  • 30

0 Answers0