C ++プロファイリング(google cpu perf tools)は正確に何を測定しますか?
-
05-07-2019 - |
質問
CPUを集中的に使用するアプリケーションのプロファイルを作成するために、Google Perf Toolsの使用を開始しようとしています。 「ofstream」を使用して各ステップをファイルにダンプする統計計算です。私はC ++の専門家ではないので、ボトルネックを見つけるのが面倒です。最初のパスで結果が得られます:
Total: 857 samples 357 41.7% 41.7% 357 41.7% _write$UNIX2003 134 15.6% 57.3% 134 15.6% _exp$fenv_access_off 109 12.7% 70.0% 276 32.2% scythe::dnorm 103 12.0% 82.0% 103 12.0% _log$fenv_access_off 58 6.8% 88.8% 58 6.8% scythe::const_matrix_forward_iterator::operator* 37 4.3% 93.1% 37 4.3% scythe::matrix_forward_iterator::operator* 15 1.8% 94.9% 47 5.5% std::transform 13 1.5% 96.4% 486 56.7% SliceStep::DoStep 10 1.2% 97.5% 10 1.2% 0x0002726c 5 0.6% 98.1% 5 0.6% 0x000271c7 5 0.6% 98.7% 5 0.6% _write$NOCANCEL$UNIX2003
実際の計算はすべてSliceStep :: DoStepで行われるため、これは驚くべきことです。 <!> quot; _write $ UNIX2003 <!> quot; (これがどこにあるのかはどこで確認できますか?)出力ファイルの書き込みから来ているようです。今、私を混乱させているのは、すべてのoutfile << "text"
ステートメントをコメントアウトしてpprofを実行すると、95%がSliceStep::DoStep
にあり、「_ write $ UNIX2003」がなくなるということです。ただし、合計時間で測定すると、アプリケーションは高速化されません。全体の速度は1%未満です。
不足しているものは何ですか?
追加:
outfile <<
ステートメントなしのpprof出力は次のとおりです。
Total: 790 samples 205 25.9% 25.9% 205 25.9% _exp$fenv_access_off 170 21.5% 47.5% 170 21.5% _log$fenv_access_off 162 20.5% 68.0% 437 55.3% scythe::dnorm 83 10.5% 78.5% 83 10.5% scythe::const_matrix_forward_iterator::operator* 70 8.9% 87.3% 70 8.9% scythe::matrix_forward_iterator::operator* 28 3.5% 90.9% 78 9.9% std::transform 26 3.3% 94.2% 26 3.3% 0x00027262 12 1.5% 95.7% 12 1.5% _write$NOCANCEL$UNIX2003 11 1.4% 97.1% 764 96.7% SliceStep::DoStep 9 1.1% 98.2% 9 1.1% 0x00027253 6 0.8% 99.0% 6 0.8% 0x000274a6
これは、目に見えるパフォーマンスの向上が見られない(10秒の計算で.1秒)ことを除いて、私が期待するもののように見えます。コードは基本的に次のとおりです。
ofstream outfile("out.txt");
for loop:
SliceStep::DoStep()
outfile << 'result'
outfile.close()
更新:boost :: timerを使用して、プロファイラーの開始位置から終了位置までのタイミングを計ります。私はスレッドや派手なものを使用しません。
解決
私のコメントから:
プロファイラーから得た数字は、printステートメントを使用しない場合、プログラムは約40%高速になるはずだと言っています。
ただし、ランタイムはほぼ同じです。
明らかに、測定値の1つが間違っている必要があります。つまり、より多くのより良い測定を行う必要があります。
まず、もう1つの簡単なツールであるtimeコマンドから始めることをお勧めします。これにより、時間を費やしている場所の大まかなアイデアが得られます。
結果がまだ決定的でない場合、より良いテストケースが必要です:
- より大きな問題を使用する
- 測定前にウォームアップを行います。ループを実行し、その後測定を開始します(同じプロセスで)。
ティリスタン:すべてユーザーです。私がやっていることは非常に簡単です、私は思う...ファイルが常に開いているという事実は何を意味しますか?
これは、プロファイラーが間違っていることを意味します。
Pythonを使用してコンソールに100000行を印刷すると、次のような結果になります。
for i in xrange(100000):
print i
コンソールへ:
time python print.py
[...]
real 0m2.370s
user 0m0.156s
sys 0m0.232s
対:
time python test.py > /dev/null
real 0m0.133s
user 0m0.116s
sys 0m0.008s
私のポイント: 内部測定および時間は、出力を無効にしても何も得られないことを示しています。 Google Perf Toolsは、そうすべきだと言っています。誰が間違っているのですか?
他のヒント
_write $ UNIX2003は、おそらく端末に出力するwrite
POSIXシステムコールを参照しています。 I / Oは他のほとんどの場合と比べて非常に遅いため、かなりの出力を書き込んでいる場合、プログラムがそこに多くの時間を費やしていることは理にかなっています。
出力を削除してもプログラムが高速化されない理由はわかりませんが、与えられた情報だけを推測することはできません。コードの一部、またはcoutステートメントが削除されたときのperftoolsの出力を見ることは素晴らしいことです。
Google perftoolsは呼び出しスタックのサンプルを収集するため、必要なのはそれらの可視性を取得することです。
ドキュメントによると、ステートメントまたはアドレスの粒度でコールグラフを表示できます。これで、知っておくべきことがわかります。