Porting C++ project from VS 6.0 to VS 2010 brought to slower code
-
samedi 3 mars 2012 06:48
I ported one project from Visual C++ 6.0 to VS 2010 and found that a critical part of the code (scripting engine) now runs in about three times slower than in was before.
After some research I managed to extract code fragment which seems to cause the slowdown. I minimized it as much as possible, so it ill be easier to reproduce the problem.
The problem is reproduced when assigning a complex class (Variant) which contains another class (String), and the union of several other fields of simple types.
Playing with the example I discovered more "magic":
1. If I comment one of unused (!) class members, the speed increases, and the code finally runs faster than those complied with VS 6.2
2. The same is true if I remove the "union" wrapper"
3. The same is true event if change the value of the filed from 1 to 0
I have no idea what the hell is going on.
I have checked all code generation and optimization switches, but without any success.
The code sample is below:
On my Intel 2.53 GHz CPU this test, compiled under VS 6.2 runs 1.0 second.
Compiled under VS 2010 - 40 seconds
Compiled under VS 2010 with "magic" lines commented - 0.3 seconds.
The problem is reproduces with any optimization switch, but the "Whole program optimization" (/GL) should be disabled. Otherwise this too smart optimizer will know that out test actually does nothing, and the test will run 0 seconds.
#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; }
- Type modifié Helen ZhaoModerator mardi 6 mars 2012 06:21 for more ideas from more members
Toutes les réponses
-
samedi 3 mars 2012 18:21
Consider these workarounds: move the union to a new structure and make it the base of Variant, or define a separate union and use it as a member of Variant.
Check if it works better in new Visual Studio 11 Beta.
-
mardi 6 mars 2012 06:20Modérateur
Hi Boris,
I have been watching this issue for a while now. And I think there is no exact answer for it. For more ideas from more members, I'd like to change the thread type to "General Discussion".
Thanks for your understanding.
Helen ZhaoHelen Zhao [MSFT]
MSDN Community Support | Feedback to us
-
lundi 12 mars 2012 14:39The solution has been found.
The problem was in default copy constructor generated by the compiler for "union" member.
VC++ 6.0 performs byte-to-byte copying, which is logical, because union members cannot have constructors.
VC++ 2010, seeing that the union contains float member, adds additional copying instruction for this float member (FLD, FSTP).
Since in my example the union uses only __int64 member, the float member contains some denormalized junk value, which causes slow copying.
This explains why setting __int64 member to zero speeds up execution.
I have found that /fp:strict compiler options solves the problem. Writing own copy constructor which do byte-to-byte copying of the union, also solves the problem.
This is similar to to this problem
http://connect.microsoft.com/VisualStudio/feedback/details/238546/incorrect-code-generation-for-union-copy-assignment-in-visual-studio-2005-c-compiler
but I am nor exactly sure.

