4

kcachegrind/callgrind が奇妙な結果を報告するモデル コードがあります。一種のディスパッチャー機能です。ディスパッチャーは 4 つの場所から呼び出されます。各呼び出しは、実行する実際のdo_J関数を示します(したがって、first2呼び出しのみdo_1などdo_2

ソース (これは実際のコードのモデルです)

#define N 1000000

int a[N];
int do_1(int *a) { int i; for(i=0;i<N/4;i++) a[i]+=1; }
int do_2(int *a) { int i; for(i=0;i<N/2;i++) a[i]+=2; }
int do_3(int *a) { int i; for(i=0;i<N*3/4;i++) a[i]+=3; }
int do_4(int *a) { int i; for(i=0;i<N;i++) a[i]+=4; }

int dispatcher(int *a, int j) {
    if(j==1) do_1(a);
    else if(j==2) do_2(a);
    else if(j==3) do_3(a);
    else do_4(a);
}

int first2(int *a) { dispatcher(a,1); dispatcher(a,2); }
int last2(int *a) { dispatcher(a,4); dispatcher(a,3); }
int inner2(int *a) { dispatcher(a,2); dispatcher(a,3); }
int outer2(int *a) { dispatcher(a,1); dispatcher(a,4); }

int main(){
    first2(a);
    last2(a);
    inner2(a);
    outer2(a);
}

でコンパイルgcc -O0; コールグラインドvalgrind --tool=callgrind; kcachegrindedkcachegrindqcachegrind-0.7.

以下は、アプリケーションの完全なコールグラフです。do_J へのすべてのパスはディスパッチャーを通過します。これは適切です (do_1 は速すぎるとして隠されていますが、実際にはここにあり、do_2 に残されています)。

満杯

誰がそれを呼び出したかに注目しdo_1て確認しましょう (この図は正しくありません)。

ここに画像の説明を入力

そして、これは非常に奇妙だと思いますが、すべてではfirst2ありません。outer2do_1

callgrind/kcachegrind の制限ですか? 重み付きで正確なコールグラフを取得するにはどうすればよいですか (すべての関数の実行時間に比例し、その子の有無にかかわらず)。

4

1 に答える 1

1

はい、これは callgrind 形式の制限です。完全なトレースは保存されません。親子通話情報のみを保存します。

pprof/libprofiler.so CPU プロファイラーを使用した google-perftools プロジェクトがあります ( http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html ) 。libprofiler.soコールトレースでプロファイルを取得でき、すべてのトレースイベントを完全なバックトレースで保存します. pproflibprofile の出力をグラフィック形式または callgrind 形式に変換するコンバータです。完全なビューでは、結果は kcachegrind と同じになります。ただし、pprof のオプション focus を使用した do_1 など、いくつかの関数に焦点を当てる場合。関数に焦点を当てると、正確なコールツリーが表示されます。

于 2011-10-30T09:52:20.557 に答える