2012-03-03 4 views
2

Visual C++ 6.0에서 VS 2010으로 하나의 프로젝트를 이식 한 결과 코드 (스크립팅 엔진)의 중요한 부분이 현재보다 약 3 배 빠릅니다. 전에. 일부 연구를 마친 후 속도 저하를 유발하는 코드 조각을 추출했습니다. 가능한 한 최소화하여 문제를 재현하는 것이 쉽지 않습니다. 다른 클래스 (String)가 포함 된 복합 클래스 (Variant)와 간단한 유형의 다른 여러 필드의 조합을 할당 할 때 문제가 재현됩니다. 1. 내가 사용하지 않는 클래스 멤버 중 하나, 속도가 증가 주석과 코드가 마침내 빠르게 VS 6.2 2. 준수보다 실행하는 경우 (!)를 다음 예와 재생VS 6.0에서 VS 2010으로 C++ 프로젝트를 더 느린 코드로 가져옴

는 좀 더 "마술을"발견 나는 "노동 조합"래퍼 " (3) 동일은 내가 체크 한 내가 도대체 ​​무슨 일이 일어나고 있는지 아무 생각이없는 신청 1

0의 값을 변경하는 경우는 true 이벤트가있다. 을 제거하는 경우에도 마찬가지입니다 모든 코드 생성 및 최적화 스위치는 성공하지만 아무런 성공이 없습니다.

코드 샘플은 다음과 같습니다. 내 In On 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가 없으면 공용체에 double이 들어 있기 때문에 fld/fstp 명령어로 부동 소수점 복사본을 실제로 만듭니다. 그리고 몇 가지 특정 값을 사용하면이 작업은 실제로 비용이 많이 드는 작업입니다. 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; 

그래서 당신이 할 수있는 것은 단지 노동 조합의 간단한 방어 적이기을하지 변형에 대한 자신의 복사 할당을 정의 할 수 있습니다 :

나는 이것을 확인하는 작은 테스트를했다.

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.com/VisualStudio/feedback/details/238546/Visual Studio 2005-C 컴파일러에서의 잘못된 코드 생성을위한 코드 생성)하지만 VC9 또는 VC10 용으로 수정하지 않은 이유는 무엇입니까? 나를. 그래도 VC11에서 일하는 것 같습니다. – Timo

관련 문제