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?