5

最近、OProfileを使用してアプリケーションのプロファイリングを試みました。収集されたデータはすでに私にとって非常に貴重ですが、その正確な解釈に苦労しています。oprofileを設定して実行してアプリを実行した後、レポートを生成して次の情報を取得しました。

root @ se7xeon:src#opreport image:test -l -t 1
オーバーフロー統計は使用できません
CPU:P4 / Xeon、2つのハイパースレッド、速度3191.66 MHz(推定)
カウントされたGLOBAL_POWER_EVENTSイベント(プロセッサが停止していない時間) 0x01のユニットマスク(必須)カウント750000
サンプル%シンボル名
215522 84.9954 cci :: Image :: interpolate(unsigned char *、cci :: Matrix const&)const
17998 7.0979 cci :: Calc :: diff(unsigned char const *、unsigned char const *)
13171 5.1942 cci :: Image :: getIRect(unsigned char *、int、int)const
5519 2.1765 cci :: Image :: getFRect(unsigned char *、double、double)const

さて、私の補間関数は、アプリケーションの(長すぎる)実行時間の84%を占めています。それからそれを調べるのは良い考えのようです:

root @ se7xeon:src#opannotate image:test --source
[...]

/* cci::Image::interpolate(unsigned char*, cci::Matrix<cci::Point2DF> const&) const total: 215522   84.9954 */  
1392  0.5529 :void Image::interpolate(CCIPixel *output, const Matrix<Point2DF> &inputPoints) const throw()  
4  0.0016 :{  
[...]  
:                col0 = static_cast<int>(point[idx].x);  
3  0.0012 :      col1 = col0+1;  
629  0.2498 :    row0 = static_cast<int>(point[idx].y);  
385  0.1529 :    row1 = row0+1;  
56214 22.3266 :  if (col0 < 0 || col1 >= m_width || row0 < 0 || row1 >= m_height)  
:                {  
:                        col0 = row0 = col1 = row1 = 0;  
:                }  

私が正しく理解していれば、if条件はプログラムの実行時間の22%以上を占めています。冒頭の中括弧と関数宣言には時間がかかるようですが、これは関数呼び出しのオーバーヘッド(「スタック、ジャンプ、ポップパラメーターのプッシュパラメーター」シーケンス)に対応するはずですか?

ソース内のいくつかの変更(ifを最適化する方法がわからなかったため、後のボトルネックに関連)、再コンパイル、oprofileの再実行(opcontrol --resetを忘れないでください)。これで、注釈付きのコードは同じ場所で次のようになります。

6  0.0024 :     curPx = point[idx].x;  
628  0.2477 :   curPy = point[idx].y;  
410  0.1617 :   col0 = static_cast<int>(curPx);  
57910 22.8380 : col1 = col0+1;  
:               row0 = static_cast<int>(curPy);  
:               row1 = row0+1;  
:               if (col0 < 0 || col1 >= m_width || row0 < 0 || row1 >= m_height)  
:               {  
:                   col0 = row0 = col1 = row1 = 0;  
:               }  

今回はifは基本的に全く時間がかからず(?)、最も高価な命令は「col1 = col0 + 1」であり、時間のかかるブロック全体が上にシフトしているようです。どうすればいいの?これは、ソースのボトルネックを特定するためにまったく信頼できますか?

もう1つの疑問点は、opcontrolを設定したときに、トレースされたイベントをGLOBAL_POWER_EVENTSとして入力し、サンプル数が750kであったことです。出力では、補間関数は84%を占めるように見えますが、その中に記録されたサンプルの数は200kを少し上回っています。それは要求された数の50%でもありません。残りの約500kのサンプルは、出力にリストされていないアプリケーション(カーネル、Xorgなど)によって取得されたことを理解していますか?

4

2 に答える 2

3

最適化されたコードをプロファイリングする場合、正確なソースコード行に頼ることはできません。コンパイラーは物事を動かしすぎます。

正確な画像を得るには、コード逆アセンブラの出力を確認する必要があります。

于 2010-10-27T15:01:54.187 に答える
2

OProfile can (they tell me) get stack samples on wall-clock time (not CPU), and it can give you line-level percentages. What you are looking for is lines that are contained on a large percent of stack samples.

I wouldn't turn on compiler optimization until after I finished hand-tuning the code, because it just hides things.

When you say the interpolate routine uses 84% of the time, that triggers a question. The entire program takes some total time, right? It takes 100% of that time. If you cut the program's time in half, or if you double it, it will still take 100% of the time. Whether 84% for interpolation is too much or not depends on whether it is being done more than necessary.

So I would suggest that you not ask if the percent of a routine is too much. Rather you look for lines of code that take a significant amount of time and ask if they could be optimized. See the difference? After you optimize the code, it can make a large reduction in overall run time, but it might still be a large percent, of a smaller total. Code isn't optimal when nothing takes a large percent. Code is optimal when of all the things that take a large percent, none can be improved.

I don't care for things that just give numbers. What I want is insight. For example, if that routine accounts for 84% of the time, then if you took 10 samples of the stack, it would be on 8.4 of them. The exact number doesn't matter. What matters is to understand why it was in there. Was it really really necessary to be in there so much? That's what looking at the stack samples can tell you. Maybe you're actually doing the interpolation twice as often as necessary? Often people find out, by analyzing the why, that the routine they're trying to speed up didn't need to be called nearly as much, maybe not at all. I can't guess in your case. Only the insight from examining the program's state can tell you that.

于 2010-10-27T20:56:44.190 に答える