動的分析法
ここでは、いくつかの動的解析方法について説明します。
動的メソッドは実際にプログラムを実行して、呼び出しグラフを決定します。
動的メソッドの反対は静的メソッドであり、プログラムを実行せずにソースのみから判断しようとします。
動的メソッドの利点:
- 関数ポインタと仮想C ++呼び出しをキャッチします。これらは、重要なソフトウェアに多数存在します。
動的メソッドの欠点:
- あなたはプログラムを実行する必要があります、それは遅いかもしれません、またはあなたが持っていないセットアップ、例えばクロスコンパイルを必要とします
- 実際に呼び出された関数のみが表示されます。たとえば、一部の関数は、コマンドライン引数に応じて呼び出されたりされなかったりします。
KcacheGrind
https://kcachegrind.github.io/html/Home.html
テストプログラム:
int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }
int main(int argc, char **argv) {
int (*f)(int);
f0(1);
f1(1);
f = pointed;
if (argc == 1)
f(1);
if (argc == 2)
not_called(1);
return 0;
}
使用法:
sudo apt-get install -y kcachegrind valgrind
# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c
# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main
# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234
これで、多くの興味深いパフォーマンスデータを含む素晴らしいGUIプログラムの中に残りました。
右下の[コールグラフ]タブを選択します。これは、関数をクリックすると、他のウィンドウのパフォーマンスメトリックに相関するインタラクティブな呼び出しグラフを示します。
グラフをエクスポートするには、グラフを右クリックして[グラフのエクスポート]を選択します。エクスポートされたPNGは次のようになります。
それから、次のことがわかります。
- ルートノードは
_start
であり、これは実際のELFエントリポイントであり、glibc初期化ボイラープレートが含まれています
f0
、f1
およびf2
互いに予想どおりに呼び出されます
pointed
関数ポインターで呼び出した場合でも、が表示されます。コマンドライン引数を渡した場合は、呼び出されなかった可能性があります。
not_called
追加のコマンドライン引数を渡さなかったため、実行時に呼び出されなかったため、表示されていません。
クールなこと valgrind
は、特別なコンパイルオプションを必要としないことです。
したがって、ソースコードがなくても実行可能ファイルのみを使用できます。
valgrind
軽量の「仮想マシン」を介してコードを実行することで、なんとかそれを実現します。これにより、ネイティブの実行と比較して実行が非常に遅くなります。
グラフからわかるように、各関数呼び出しに関するタイミング情報も取得され、これはプログラムのプロファイルに使用できます。これは、呼び出しグラフを表示するだけでなく、このセットアップの元の使用例である可能性があります。 Linuxで実行されているC ++コード?
Ubuntu 18.04でテスト済み。
gcc -finstrument-functions
+ etrace
https://github.com/elcritch/etrace
-finstrument-functions
コールバックを追加します、etraceはELFファイルを解析してすべてのコールバックを実装します。
しかし、残念ながら機能させることができませんでした。なぜ「-finstrument-functions」が機能しないのですか?
要求された出力は次の形式です:
\-- main
| \-- Crumble_make_apple_crumble
| | \-- Crumble_buy_stuff
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | | \-- Crumble_buy
| | \-- Crumble_prepare_apples
| | | \-- Crumble_skin_and_dice
| | \-- Crumble_mix
| | \-- Crumble_finalize
| | | \-- Crumble_put
| | | \-- Crumble_put
| | \-- Crumble_cook
| | | \-- Crumble_put
| | | \-- Crumble_bake
特定のハードウェアトレースサポート以外に最も効率的な方法のようですが、コードを再コンパイルする必要があるという欠点があります。