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.
- What are the possible causes for this difference between the two reports?
- 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
Workaround
For some reason
perf reporttries 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.