コンパイラの最適化により、パフォーマンスが遅くなります
-
02-10-2019 - |
質問
奇妙な問題が1つあります。次のコードがあります:
template<clss index, class policy>
inline int CBase<index,policy>::func(const A& test_in, int* srcPtr ,int* dstPtr)
{
int width = test_in.width();
int height = test_in.height();
double d = 0.0; //here is the problem
for(int y = 0; y < height; y++)
{
//Pointer initializations
//multiplication involving y
//ex: int z = someBigNumber*y + someOtherBigNumber;
for(int x = 0; x < width; x++)
{
//multiplication involving x
//ex: int z = someBigNumber*x + someOtherBigNumber;
if(soemCondition)
{
// floating point calculations
}
*dstPtr++ = array[*srcPtr++];
}
}
}
内側のループは200,000回近く実行され、関数全体が完了に100ミリ秒かかります。 (Aqtimerを使用してプロファイル)
未使用の変数を見つけました double d = 0.0;
外側のループの外で同じものを削除しました。この変更後、突然、この方法は同じ数の実行に500ミリ秒かかります。 (5倍遅い)。
この動作は、さまざまなプロセッサタイプを持つさまざまなマシンで再現できます。 (Core2、デュアルコアプロセッサ)。
最適化レベルのVC6コンパイラを使用しています O2
。フォローは、使用される他のコンパイラオプションです。
-MD -O2 -Z7 -GR -GX -G5 -X -GF -EHa
コンパイラの最適化を疑って、コンパイラの最適化を削除しました /O2
. 。その後、関数が正常になり、100msが古いコードとして取られています。
誰かがこの奇妙な行動に光を当てることができますか?
使用されていない変数を削除したときに、コンパイラの最適化がパフォーマンスを遅くする必要があるのはなぜですか?
注:アセンブリコード(変更前後)は同じように見えました。
正しい解決策はありません
他のヒント
アセンブリコードが変更の前後に同じように見える場合、エラーは何らかの形で関数の時間に接続されます。
VC6は地獄のようにバギーです。いくつかのケースで誤ったコードを生成することが知られており、そのオプティマイザーもそれほど進んでいるわけではありません。コンパイラは10年以上前のものであり、長年にわたってサポートされていません。
本当に、答えは「バギーコンパイラを使用している。特に最適化が有効になっている場合は、バギーの動作を期待してください」です。
モダンなコンパイラにアップグレードすること(または単にコードをテストする)がオプションだとは思わないのですか?
明らかに、生成されたアセンブリは同じではないか、パフォーマンスの違いがないでしょう。
唯一の質問はです どこ 違いはあります。また、バギーコンパイラを使用すると、突然異なってコンパイルされて壊れるのは、コードの完全に無関係な部分である可能性があります。おそらく、この関数のために生成されたアセンブリコードは いいえ 同じ、そして違いはとても微妙で、あなたはそれらに気付かなかった。
宣言する width
と height
const {unsigned} intsとして。 { 署名なし 高さと幅が負のものではないため、使用する必要があります。}
const int width = test_in.width();
const int height = test_in.height();
これにより、コンパイラが最適化するのに役立ちます。値があります const
, 、それらが変更されないことを知って、コードまたはレジスタにそれらを配置できます。また、変数が変化しているかどうかを推測しなければならないというコンパイラが解放されます。
未使用でバージョンのアセンブリコードを印刷することをお勧めします double
そしてなしで。これにより、コンパイラの思考プロセスに関する洞察が得られます。