2012-03-03 6 views
2

Visual C++ 6.0からVS 2010へのプロジェクトを1つ移植したところ、コード(スクリプトエンジン)の重要な部分が、前。 いくつかの調査の後、私は減速の原因と思われるコード断片を抽出することができました。私はできるだけそれを最小化したので、問題を再現するのは簡単ではありません。 別のクラス(String)を含む複雑なクラス(Variant)と単純型の他のいくつかのフィールドの和集合を割り当てると、問題が再現されます。 (!)私は未使用のクラスメンバー、速度が上昇すると、コードのいずれかをコメントする場合は、最終的に高速VS 6.2 2.ザ・遵守したものよりも動作します 1:例と遊ぶVS 6.0からVS 2010へのC++プロジェクトの移植速度が遅い

は、私はより多くの「魔法」を発見しました同じことが、私は「労働組合」を削除した場合、私は地獄は何が起こっているか見当がつかない0

に1から提出されたの値を変更した場合、ラッパー」 3.同じことが真のイベントです本当です。 私がチェックしていますすべてのコード生成と最適化のスイッチは、成功しません。

コードサンプルは以下の通りです: On My In tel 2.53 GHz CPUこのテストは、VS 6.2でコンパイルされ、1.0秒実行されます。 VS 2010 - 40秒の間にコンパイル VS 2010の下でコンパイルされ、 "magic"行がコメントされました - 0.3秒。

問題は最適化スイッチで再現されますが、「全体最適化」(/ GL)は無効にする必要があります。そうしないと、このスマートなオプティマイザは、実際にテストが何もしないことを知り、テストは0秒間実行されます。

#include  <windows.h> 
#include  <stdio.h> 
#include  <stdlib.h> 

class String 
{ 
public: 
    char *ptr; 
    int  size; 

    String() : ptr(NULL), size(0) {}; 
    ~String() {if (ptr != NULL) free(ptr);}; 
    String& operator=(const String& str2); 
}; 

String& String::operator=(const String& string2) 
{ 
    if (string2.ptr != NULL) 
    { 
     // This part is never called in our test: 
     ptr = (char *)realloc(ptr, string2.size + 1); 
     size = string2.size; 
     memcpy(ptr, string2.ptr, size + 1); 
    } 
    else if (ptr != NULL) 
    { 
     // This part is never called in our test: 
     free(ptr); 
     ptr = NULL; 
     size = 0; 
    } 

    return *this; 
} 


struct Date 
{ 
    unsigned short   year; 
    unsigned char   month; 
    unsigned char   day; 
    unsigned char   hour; 
    unsigned char   minute; 
    unsigned char   second; 
    unsigned char   dayOfWeek; 
}; 


class Variant 
{ 
public: 
    int    dataType; 
    String   valStr; // If we comment this string, the speed is OK! 

    // if we drop the 'union' wrapper, the speed is OK! 
    union 
    { 
     __int64  valInteger; 

     // if we comment any of these fields, unused in out test, the speed is OK! 
     double  valReal; 
     bool  valBool; 
     Date  valDate; 
     void  *valObject; 
    }; 

    Variant() : dataType(0) {}; 
}; 


void TestSpeed() 
{ 
    __int64    index; 
    Variant    tempVal, tempVal2; 

    tempVal.dataType = 3; 
    tempVal.valInteger = 1; // If we comment this string, the speed is OK! 

    for (index = 0; index < 200000000; index++) 
    { 
     tempVal2 = tempVal; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    int   ticks; 
    char  str[64]; 

    ticks = GetTickCount(); 

    TestSpeed(); 

    sprintf(str, "%.*f", 1, (double)(GetTickCount() - ticks)/1000); 

    MessageBox(NULL, str, "", 0); 

    return 0; 
} 

答えて

0

これは面白かったです。最初は、リリースビルドの遅さを再現することができませんでした。デバッグビルドでのみです。 SSE2の最適化を無効にし、実行時間を40秒にしました。

問題はコンパイラがVariantのコピー割り当てを生成しているようです。 SSE2がなければ、実際にはfld/fstp命令で浮動小数点コピーが実行されます。これは、共用体にdoubleが含まれているためです。そして、いくつかの特定の値では、これは明らかに非常に高価な操作です。 64ビットの整数値1は、非正規化数である4.940656458412e-324#DENにマップされており、これは問題を引き起こすと考えています。 tempVal.valIntegerを未初期化のままにすると、より速く動作する値が含まれている可能性があります。

私はこれを確認するために小規模なテストをした:

union { 
    uint64_t i; 
    volatile double d1; 
}; 
i = 0xcccccccccccccccc; //with this value the test takes 0.07 seconds 
//i = 1; //change to 1 and now the test takes 36 seconds 
volatile double d2; 

for(int i=0; i<200000000; ++i) 
    d2 = d1; 

だから何あなたができることは、単に労働組合の簡単なのmemcpyを行うバリアントのための独自のコピー代入を定義しています。

Variant& operator=(const Variant& rhs) 
{ 
    dataType = rhs.dataType; 
    union UnionType 
    { 
     __int64  valInteger; 
     double  valReal; 
     bool  valBool; 
     Date  valDate; 
     void  *valObject; 
    }; 
    memcpy(&valInteger, &rhs.valInteger, sizeof(UnionType)); 
    valStr = rhs.valStr; 
    return *this; 
} 
+0

ティモ、私はこの方向で検索しませんでした。 –

+0

これで/ fp:strictオプションも役立つことが判明しました。 これは、デフォルトで単純なバイト割り当てによって共用体がコピーされたことを確信していたので、非常に奇妙です。今は必ずしもそうではないことは明らかです。 しかし、「bool」と「String」のメンバーを削除すると問題が解決するのはなぜですか?おそらくコンパイラは、小さな構造と大きな構造のために異なるコードを生成するでしょうか? –

+0

@Boris L:そうですね、私はコンパイラの動作を理解していません。私はunionから 'Date'を削除し、' bool'や 'void * 'を削除するまで実際には問題はありませんでした。 MSはそれがバグであることを確認しました(http://connect.microsoft。Visual Studio/2005/Visual Studio/feedback/details/238546/Visual Studio 2005-cコンパイラでの不正コピーコード生成の不正コード生成)、なぜVC9やVC10用に修正しなかったのか私。しかしVC11で働くように思える。 – Timo

関連する問題