Я перенес один проект из Visual C ++ 6.0 в VS 2010 и обнаружил, что критическая часть кода (механизм сценариев) теперь работает примерно в три раза медленнее, чем была раньше.
После некоторых исследований мне удалось извлечь фрагмент кода, который, кажется, вызывает замедление. Я максимально уменьшил это, так что будет легче воспроизвести проблему.
Проблема воспроизводится при назначении сложного класса (Variant), который содержит другой класс (String), и объединении нескольких других полей простых типов.
Играя на примере, я обнаружил еще одну «магию»:
1. Если я прокомментирую один из неиспользуемых (!) Членов класса, скорость возрастет, и код, наконец, будет работать быстрее, чем те, которые соответствуют VS 6.2
2. То же самое верно, если я удаляю «обертку»
3. То же самое верно и в случае изменения значения поля с 1 на 0
Понятия не имею, что, черт возьми, происходит.
Я проверил все параметры генерации и оптимизации кода, но безуспешно.
Пример кода ниже:
На моем процессоре Intel 2,53 ГГц этот тест, скомпилированный под VS 6.2, выполняется 1,0 секунды.
Составлено под VS 2010 - 40 секунд
Скомпилировано под VS 2010 с прокомментированными «волшебными» строками - 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;
}