fp
でコール スタックを収集する方法が気に入っています。perf record
軽量で より複雑ではないからdwarf
です。しかし、プログラムが C++ 標準ライブラリを使用するときに取得するコール スタック/フレームグラフを見ると、それらは正しくありません。
テストプログラムは次のとおりです。
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int __attribute__((noinline)) stupid_factorial(int x) {
std::vector<std::string> xs;
// Need to convert numbers to strings or it will all get inlined
for (int i = 0; i < x; ++i) {
std::stringstream ss;
ss << std::setw(4) << std::setfill('0') << i;
xs.push_back(ss.str());
}
int res = 1;
while(std::next_permutation(xs.begin(), xs.end())) {
res += 1;
};
return res;
}
int main() {
std::cout << stupid_factorial(11) << "\n";
}
そして、ここにフレームグラフがあります:
これは、Docker コンテナー内の Ubuntu 20.04 で次の手順によって生成されました。
g++ -Wall -O3 -g -fno-omit-frame-pointer program.cpp -o 6_stl.bin
# Make sure you have libc6-prof and libstdc++6-9-dbg installed
env LD_LIBRARY_PATH=/lib/libc6-prof/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/debug:${LD_LIBRARY_PATH} perf record -F 1000 --call-graph fp -- ./6_stl.bin
# Make sure you have https://github.com/jonhoo/inferno installed
perf script | inferno-collapse-perf | inferno-flamegraph > flamegraph.svg
これの主な問題点は、すべての関数が の子であるとは限らないことstupid_factorial
です__memcmp_avx2_movbe
。でdwarf
、彼らはです。より複雑なプログラムでは、これらのような関数が outside にあることさえ見てきmain
ました。__dynamic_cast
たとえば、多くの場合、親を持たないものです。
ではgdb
、ここで正しく表示されない関数を含め、常に正しいバックトレースが表示されます。自分でコンパイルせずに正しいfp
呼び出しスタックを取得することは可能ですか (これは大変な作業のようです)?libstdc++
他にも奇妙な点がありますが、Ubuntu 18.04 (Docker コンテナーの外部) では再現できませんでした。
- に未解決の機能があり
libstdc++.so.6.28
ます。 - 私自身のバイナリには
6_stl.bin
、左端に未解決の関数があります。の場合も同様dwarf
です。