3

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です。
4

2 に答える 2

2

関数ソース コードを見ると、__memcmp_avx2_movbe関数のプロローグがないことがわかります。

__memcmp_avx2_movbeしたがって、バックトレースで の直接の親フレームがスキップされることを期待する必要があります。最も内側のフレームは、命令ポインタからのものとして正しく識別され__memcmp_avx2_movbeますが、フレーム ポインタによって識別されるスタック上のリターン アドレスは祖父母に属します。

stupid_factorial関数がの親である場合__memcmp_avx2_movbe(これら 2 つの間のすべての中間関数がインライン化されているため)、質問から主な問題を説明できます。他の問題は、こちらでlibstdc++説明されているように、フレーム ポインターを使用してコンパイルされた を使用することで解決されます。

于 2021-07-16T16:46:46.020 に答える