Perf report: shared object names showing up as `(deleted)` in docker

86 Views Asked by At

I profiled two binaries that run the same logical computation, one written in Swift the other in C++. The code is very simple, just does some math computation in a loop. I am using the Swift docker image running with --privileged.

Now, I know that the system libraries libm.so and libc.so are stripped in the docker instance, so symbolification might not be great, but in this case the shared objects are showing up as (deleted) for the C++ code, but not for the Swift code.

The C++ code was compiled with -g -O3 -Wall -Wextra -pedantic -std=c++20 -fwrapv -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer. I recorded using perf record -g, and this is the output of perf report -g 'graph,1.0,caller.

Samples: 187K of event 'cpu-clock:pppH', Event count (approx.): 46774250000                                                                                    
  Children      Self  Command  Shared Object      Symbol                                                                                                       
+  100.00%     0.00%  profile  profile            [.] _start
+  100.00%     0.00%  profile   (deleted)         [.] 0x0000ffff88e274cc
+  100.00%     0.00%  profile   (deleted)         [.] 0x0000ffff88e273fc
+  100.00%     0.00%  profile  profile            [.] main
+   76.43%     8.62%  profile  profile            [.] synthetic
+   32.22%     2.66%  profile  profile            [.] siam100_integrand
+   23.32%     0.00%  profile   (deleted)         [.] 0x0000ffff88fe54e4
+   23.32%    23.32%  profile   (deleted)         [.] 0x00000000000354e4
+   19.79%     0.00%  profile   (deleted)         [.] 0x0000ffff88fe54d8
+   19.79%    19.79%  profile   (deleted)         [.] 0x00000000000354d8
+   17.17%     0.00%  profile   (deleted)         [.] 0x0000ffff88fe88f0
+   17.17%    17.17%  profile   (deleted)         [.] 0x00000000000388f0
+    8.16%     8.16%  profile   (deleted)         [.] 0x00000000000387f4
+    8.16%     0.00%  profile   (deleted)         [.] 0x0000ffff88fe87f4
+    4.92%     4.92%  profile   (deleted)         [.] 0x00000000000354b4
+    4.92%     0.00%  profile   (deleted)         [.] 0x0000ffff88fe54b4
+    3.78%     3.78%  profile  profile            [.] cos@plt
+    2.22%     2.22%  profile  profile            [.] log@plt

profile is the name of the binary. The deleted shared object entries should be mostly libm.so, libc.so, and kernel.kallsyms. But, on stepping into the debugger I cannot set breakpoints at the addresses shown in the perf report output: Cannot access memory at address 0xffff88fe54e4 for example.

Here is the same report for the binary built using swift.

Samples: 54K of event 'cpu-clock:pppH', Event count (approx.): 13628000000                                                                                     
  Children      Self  Command  Shared Object          Symbol                                                                                                   
+   99.97%     0.00%  Run      Run                    [.] _start
+   99.97%     0.00%  Run      libc.so.6              [.] __libc_start_main@@GLIBC_2.34
+   99.97%     0.00%  Run      libc.so.6              [.] __libc_start_call_main
+   99.97%     0.00%  Run      Run                    [.] Run_main
+   43.46%    43.46%  Run      libm.so.6              [.] log@@GLIBC_2.29
+   39.18%     7.92%  Run      Run                    [.] $s7BMDemos9synthetic__9iterCountS2d_SdSitF
+   31.27%    31.26%  Run      libm.so.6              [.] __cos
+    8.41%     8.41%  Run      libm.so.6              [.] __math_invalid
+    5.97%     5.97%  Run      Run                    [.] log@plt
+    2.94%     2.94%  Run      Run                    [.] cos@plt

Another difference between the binaries is that the C++ one jumps directly to log via the procedure linkage table, while the Swift one has to perform some kind of dlsym looking lookup. This I found out when stepping through with the debugger asm line at at time.

So, I have the following questions.

  1. What are the possible causes for this difference between the two reports?
  2. If possible, can the reporting for the C++ code be improved?

Appendix

ldd -v on the C++ binary

linux-vdso.so.1 (0x0000ffff9a112000)
    libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000ffff99e90000)
    libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000ffff99df0000)
    libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff99c40000)
    /lib/ld-linux-aarch64.so.1 (0x0000ffff9a0d9000)
    libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffff99c10000)

    Version information:
    ./profile:
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libstdc++.so.6 (GLIBCXX_3.4.9) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.11) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /lib/aarch64-linux-gnu/libstdc++.so.6
    /lib/aarch64-linux-gnu/libstdc++.so.6:
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.25) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.18) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.32) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libgcc_s.so.1 (GCC_4.2.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_4.5.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
    /lib/aarch64-linux-gnu/libm.so.6:
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
        libc.so.6 (GLIBC_PRIVATE) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /lib/aarch64-linux-gnu/libc.so.6:
        ld-linux-aarch64.so.1 (GLIBC_PRIVATE) => /lib/ld-linux-aarch64.so.1
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /lib/aarch64-linux-gnu/libgcc_s.so.1:
        libc.so.6 (GLIBC_2.35) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6

ldd -v on the Swift binary

linux-vdso.so.1 (0x0000ffff8b009000)
    libswiftCore.so => /usr/lib/swift/linux/libswiftCore.so (0x0000ffff8a960000)
    libswift_Concurrency.so => /usr/lib/swift/linux/libswift_Concurrency.so (0x0000ffff8a8e0000)
    libswift_StringProcessing.so => /usr/lib/swift/linux/libswift_StringProcessing.so (0x0000ffff8a800000)
    libswift_RegexParser.so => /usr/lib/swift/linux/libswift_RegexParser.so (0x0000ffff8a6e0000)
    libswiftGlibc.so => /usr/lib/swift/linux/libswiftGlibc.so (0x0000ffff8a6b0000)
    libBlocksRuntime.so => /usr/lib/swift/linux/libBlocksRuntime.so (0x0000ffff8a690000)
    libdispatch.so => /usr/lib/swift/linux/libdispatch.so (0x0000ffff8a610000)
    libswiftDispatch.so => /usr/lib/swift/linux/libswiftDispatch.so (0x0000ffff8a5c0000)
    libFoundation.so => /usr/lib/swift/linux/libFoundation.so (0x0000ffff89d40000)
    libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000ffff89ca0000)
    libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff89af0000)
    libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000ffff898c0000)
    libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffff89890000)
    /lib/ld-linux-aarch64.so.1 (0x0000ffff8afd0000)
    libicuucswift.so.65 => /usr/lib/swift/linux/libicuucswift.so.65 (0x0000ffff89680000)
    libicui18nswift.so.65 => /usr/lib/swift/linux/libicui18nswift.so.65 (0x0000ffff89360000)
    libicudataswift.so.65 => /usr/lib/swift/linux/libicudataswift.so.65 (0x0000ffff878a0000)

    Version information:
    .build/release/Run:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
    /usr/lib/swift/linux/libswiftCore.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.32) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.27) => /lib/aarch64-linux-gnu/libm.so.6
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libstdc++.so.6 (GLIBCXX_3.4.17) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (CXXABI_1.3.11) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.21) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.29) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.18) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.14) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (CXXABI_1.3) => /lib/aarch64-linux-gnu/libstdc++.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /usr/lib/swift/linux/libswift_Concurrency.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.32) => /lib/aarch64-linux-gnu/libc.so.6
        libstdc++.so.6 (GLIBCXX_3.4.11) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (CXXABI_1.3) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.21) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.18) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.29) => /lib/aarch64-linux-gnu/libstdc++.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /usr/lib/swift/linux/libswift_StringProcessing.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /usr/lib/swift/linux/libswift_RegexParser.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /usr/lib/swift/linux/libswiftGlibc.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.27) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.35) => /lib/aarch64-linux-gnu/libm.so.6
    /usr/lib/swift/linux/libBlocksRuntime.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /usr/lib/swift/linux/libdispatch.so:
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.32) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /usr/lib/swift/linux/libswiftDispatch.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /usr/lib/swift/linux/libFoundation.so:
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libm.so.6 (GLIBC_2.35) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3.1) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /lib/aarch64-linux-gnu/libm.so.6:
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
        libc.so.6 (GLIBC_PRIVATE) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /lib/aarch64-linux-gnu/libc.so.6:
        ld-linux-aarch64.so.1 (GLIBC_PRIVATE) => /lib/ld-linux-aarch64.so.1
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
    /lib/aarch64-linux-gnu/libstdc++.so.6:
        ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.25) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.18) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.32) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libgcc_s.so.1 (GCC_4.2.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_4.5.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
    /lib/aarch64-linux-gnu/libgcc_s.so.1:
        libc.so.6 (GLIBC_2.35) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /usr/lib/swift/linux/libicuucswift.so.65:
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libstdc++.so.6 (GLIBCXX_3.4.11) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (CXXABI_1.3) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4.30) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
    /usr/lib/swift/linux/libicui18nswift.so.65:
        libgcc_s.so.1 (GCC_3.0) => /lib/aarch64-linux-gnu/libgcc_s.so.1
        libstdc++.so.6 (CXXABI_1.3) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libstdc++.so.6 (GLIBCXX_3.4) => /lib/aarch64-linux-gnu/libstdc++.so.6
        libm.so.6 (GLIBC_2.29) => /lib/aarch64-linux-gnu/libm.so.6
        libm.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libm.so.6
        libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6
1

There are 1 best solutions below

1
loonatick On

Workaround

For some reason perf report tries to look for the executable with (deleted) appended to it. Creating a copy of the profiled executable with the name <executable name> (deleted) ends up working just fine.

A better alternative would be to create a symbolic link to the binary so that recompilations do not result in the alias becoming outdated.