12

I want to improve the performance of a specific method inside a larger application.

The goal is improving latency (wall-clock time spent in a specific function), not (neccessarily) system load.

Requirements:

  1. As I expect a lot of the latency to be due to I/O, take into account time spent waiting/blocked (in other words: look at wall clock time instead of CPU time)
  2. As the program does much more than the fragment i'm trying to optimize. There needs to be a way to either start/stop profiling programmatically, or to filter the output to only show the time between entering and exiting the function i'm optimizing.
  3. Profiling on the method level is acceptable (if it can be done on the instruction level, even better. if it only profiles system calls, that's probably not enough)
  4. This is for a hobby project, so expensive tools are not really an option
  5. Instrumentation (-finstrument-functions) is acceptable
  6. The critical piece of code I'm interested in is hard to interrupt manually (because it is already relatively fast and hard to realistically invoke in a loop), so some kind of automation is necessary.

Tools discarded so far:

  • gprof, oprofile, callgrind (requirement 1)
  • buiding something custom using getrusage (requirement 1)
  • poormansprofiler.org (requirement 2)
  • strace -T,dtrace,http://perf.wiki.kernel.org (requirements 2 and 3)
  • VTune,Zoom (requirement 4)
  • manual call-stack sampling (requirement 6)
  • google-perftools (should be able to measure wall time, but this does not appear to work in my case, presumably because SIGALRM interference.
  • systemtap (my kernel isn't patched to include utrace)

Other options which I haven't further evaluated yet:

  • cprof (doesn't build here out-of-the-box, seems i386-only)
  • manually inserting trace points (e.g. with lttng)

I'd love to hear about:

  • other options
  • perhaps I discarded some tool too soon?
  • whether or not the options I haven't evaluated yet have a chance of working, and if so, how to best do it.

I finally settled for:

The trace produced by this crude tool is hard to interpret, and I can easily imagine some tools for further processing its output making it infinitely more useful. However, this did the job for me for now, so I'm putting that project off until later ;).

4

4 に答える 4

3

この方法を使用します。

これは、最適化の機会を特定するのに非常にシンプルで効果的です。それが CPU バウンド コードであろうと IO バウンド コードであろうとです。

最大の機会が特定の関数またはモジュールにあるというあなたの考えが正しければ、それらを見つけることができます。それらが他の場所にある場合は、それらを見つけます。

あなたが言及して破棄したツールの中で、それは貧乏人のプロファイラーに最も似ていますが、それでもあまり似ていません。

編集:ユーザーの操作によってトリガーされ、完了するまでそれ以上の入力をブロックすると言うので、次のようにします。

まず、デバッガーへの手動割り込み信号をブロックしないと仮定します。そうしないと、無限ループを停止する方法がないからです。次に、問題のルーチンの周りに 10 回、100 回、または 1000 回のループをラップするので、手動で中断するのに十分な時間実行します。

ここで、50% のように、I/O の実行に時間の一部を費やしているとします。それを中断すると、50% の確率で I/O でキャッチされます。そのため、I/O でそれをキャッチすると、コール スタックが通知するので、I/O がどこから要求され、その理由を詳細に確認することもできます。

それは何が起こっているかを示しますが、これはほぼ確実に驚くべきことです。排除する方法を見つけることができるわずか 2 つのサンプルで何かを実行しているのを確認した場合、かなりのスピードアップが得られます。実際、そのアクティビティをなくすと、どれだけの時間を節約できるかを事前に知ることはできませんが、平均して分数F = (s+1)/(n+2)を節約できると期待できます。ここで、nは取得したサンプルの総数、およびsはアクティビティを示したサンプルの数です。 (継承の規則) たとえば、4 つのスタック サンプルを取得し、そのうちの 2 つのアクティビティを確認した場合、平均してF = 3/6 = 1/2を節約できます。これは、 1/(1-Fの高速化係数に対応します。 )または2。

それができたら、もう一度やり直して、他に修正すべき点を見つけることができます。スピードアップ要因は、複利のように一緒に乗算されます。

次に、もちろん、外側のループを削除し、得られたすべてのスピードアップを「現金化」します。

これがプロファイリングとどのように異なるのか疑問に思われる場合は、各スタック サンプルと、場合によっては関連するデータを注意深く調べることで、削除できるアクティビティを認識することができます。何が起こっている。実際に節約できる時間は、測定値に関係なくそのままです。大事なのは問題を見つけることです。プロファイラーがどれだけ正確に測定しても、それを見つけられなければ勝てません。これらのページは、プロファイラーが何を言っているのか理解できない、または修正するものが何もないと言っているように見えると言う人でいっぱいです。それはバラ色のメガネの場合です。

そのすべてについてもっと。

于 2012-08-01T21:40:10.173 に答える
1

Todo: 「perf」をチェックしてください (再度)

于 2016-07-18T12:40:26.783 に答える
0
  • フォーク()
  • execxxx(テスト中のプロセス)
  • 親で:
    • (ループ内)定期的に呼び出します:
    • getrusage(RUSAGE_CHILDREN、...)

getrusage()は、CPU使用率だけでなく、メジャー/マイナーページフォールト、コンテキストスイッチの数なども提供します。残りの時間は、おそらくI/Oの待機に費やされます。これにより、詳細なプロファイリング情報は得られませんが、プロセスごとにvmstatを実行するのに匹敵する、プログラムの動作の全体的なフットプリントがわかりやすくなります。

于 2012-08-01T21:57:26.180 に答える