Speed Problems with Dual Core please help! :(

Started by
9 comments, last by thre3dee 16 years, 11 months ago
Hey Everyone, I was just making a very simple game not even using DirectX just yet I thought i'll start making a game using normal Windows GDI using bitmaps etc to start getting back into game development. So far my entire game was being developed on whats now my second PC being: AMD Athlon 64 3500+ 1GB DDR RAM GeForce 6800 256MB Windows XP Home Although being a basic 2D windows game i wanted the animation to be as accurate and flowing as possible so I was using QueryPerformanceFrequency and QueryPerformanceCounter for my timing loop. This was perfect when developing on this machine. Now i have upgraded to Intel E6400 2.2Ghz Dual Core 2GB OCZ DDR2 800MHz RAM GeForce 8800GTS 320MB Windows Vista And when i ran the entire code i found that although my seconds counter is still incrementing correctly my entire animation has halved in speed and it was hammering my processor. So after reading quite a bit about query timers and dual core i set thread affinity in my code and now it only uses one core and it still has had no effect except it completely takes up all the core's resources making my processing sit at 50% atleast when the game is running. I'm not sure why, people have reported using SetThreadAffinityMask function which fixes it however these ppl who are reporting this works are all using Windows XP and not Vista. Does anyone know what the problem might be ? My application isnt multi-threaded
Advertisement
how is your main loop structured / how are you using the performance counter?
Hey Hodman,

I'm not very good with windows programming in general just at the moment so the structure of my winmain code is pretty much the same as the example i saw in the course im doing.

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// Assign the application instance
tdAppInst = hInstance;

// Initialize the Game Window will return either true or false
if(!InitGameWindow())
{
// If the initialization failed
MessageBox(0, "Error: Window Creation Failed", "Error", MB_OK);
return 0;
}

// GameRun
return GameRun();
}

Where InitGameWindow() is a function that initializes the window and then it returns this GameRun() function which is a bit larger

int GameRun()
{
// Zero the message
MSG msg;

ZeroMemory(&msg, sizeof(MSG));

// Adding this code in for Dual Core processors, affinity
SetThreadAffinityMask(GetCurrentThread(), 0x01);

// Get the performance timer frequency.
__int64 cntsPerSec = 0;
bool perfExists = QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec)!=0;
if( !perfExists )
{
MessageBox(0, "Error: Performance timer does not exist!", 0, 0);
return 0;
}

double timeScale = 1.0 / (double)cntsPerSec;
// Get the current time.
__int64 lastTime = 0;

QueryPerformanceCounter((LARGE_INTEGER*)&lastTime);

double timeElapsed = 0.0f;

// While no post to quit has come yet (Exit the game)
while(msg.message != WM_QUIT)
{
// Translate and Dispatch Message to Windows Procedure
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
__int64 currTime = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&currTime);

// Compute the differences in time from the last
// time we checked. Since the last time we checked
// was the previous loop iteration, this difference
// gives us the time between loop iterations...
// or, I.e., the time between frames.
double deltaTime = (double)(currTime - lastTime) * timeScale;
timeElapsed += deltaTime;

// Only update once every 1/100 seconds.
if( timeElapsed >= 0.01 )
{
// Update Tower Defence
towerDefence->update(timeElapsed);

// Render Tower Defence
towerDefence->Render(tdBackBuffer->get_DC(), tdSpriteDC);

// Flip the back buffer (Double Buffering)
tdBackBuffer->Flip();

timeElapsed = 0.0;
}

lastTime = currTime;
}
}

return (int)msg.wParam;
}

I hope this is readable if u need anything else let me know. The timer and windows stuff is a little confusing to me still :/
try using [ source ][/ source ] (without spaces)

int WINAPIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){        // Assign the application instance    tdAppInst = hInstance;    // Initialize the Game Window will return either true or false    if(!InitGameWindow())    {        // If the initialization failed        MessageBox(0, "Error: Window Creation Failed", "Error", MB_OK);        return 0;    }    // GameRun    return GameRun();}// Where InitGameWindow() is a function that initializes the window and then it // returns this GameRun() function which is a bit largerint GameRun(){    // Zero the message    MSG msg;    ZeroMemory(&msg, sizeof(MSG));    // Adding this code in for Dual Core processors, affinity    SetThreadAffinityMask(GetCurrentThread(), 0x01);    // Get the performance timer frequency.    __int64 cntsPerSec = 0;    bool perfExists = QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec)!=0;    if( !perfExists )    {        MessageBox(0, "Error: Performance timer does not exist!", 0, 0);        return 0;    }    double timeScale = 1.0 / (double)cntsPerSec;    // Get the current time.    __int64 lastTime = 0;    QueryPerformanceCounter((LARGE_INTEGER*)&lastTime);    double timeElapsed = 0.0f;    // While no post to quit has come yet (Exit the game)    while(msg.message != WM_QUIT)    {        // Translate and Dispatch Message to Windows Procedure        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))        {            TranslateMessage(&msg);            DispatchMessage(&msg);        }        else        {            __int64 currTime = 0;             QueryPerformanceCounter((LARGE_INTEGER*)&currTime);            // Compute the differences in time from the last            // time we checked. Since the last time we checked            // was the previous loop iteration, this difference            // gives us the time between loop iterations...            // or, I.e., the time between frames.            double deltaTime = (double)(currTime - lastTime) * timeScale;            timeElapsed += deltaTime;            // Only update once every 1/100 seconds.            if( timeElapsed >= 0.01 )            {                // Update Tower Defence                towerDefence->update(timeElapsed);                // Render Tower Defence                towerDefence->Render(tdBackBuffer->get_DC(), tdSpriteDC);                // Flip the back buffer (Double Buffering)                tdBackBuffer->Flip();                timeElapsed = 0.0;            }            lastTime = currTime;        }    }    return (int)msg.wParam;}
Thanks thre3dee

I'll remember that for next time
Quote:Original post by amokz0r
I'm not very good with windows programming in general just at the moment so the structure of my winmain code is pretty much the same as the example i saw in the course im doing.



Hmmm... Your code looks fine to me.
Off the top of my head, the only think I can suggest is the removal of the "timeElapsed" variable (and just use deltaTime from the last actual frame instead) as you could be losing too much precision when incrementing timeElapsed by small amounts:
int GameRun(){......	// While no post to quit has come yet (Exit the game)	while(msg.message != WM_QUIT)	{......		else		{...			double deltaTime = (double)(currTime - lastTime) * timeScale;			// Only update once every 1/100 seconds.			if( deltaTime >= 0.01 )			{...				lastTime = currTime;			}		}	}}
Quote:Original post by Hodgman
Quote:Original post by amokz0r
I'm not very good with windows programming in general just at the moment so the structure of my winmain code is pretty much the same as the example i saw in the course im doing.



Hmmm... Your code looks fine to me.
Off the top of my head, the only think I can suggest is the removal of the "timeElapsed" variable (and just use deltaTime from the last actual frame instead) as you could be losing too much precision when incrementing timeElapsed by small amounts:
*** Source Snippet Removed ***

Firstly its a double so the precision is 15-digits. So adding 0.0056 or whatever isnt' going to make it innacurate.

And secondly, if he doesn't have the timeElapsed variable in there itll update the logic on every frame that is over 10 ms long, instead of every 10ms or whatever. So if its running really fast, itll never update; likewise if its running too slow itll always update.

The way you are calculating the 10ms updates is mostly correct, however you shouldn't reset the timeElapsed to zero. Rather, subtract 0.01 from it so that if the frame is 0.013 seconds long, the remainging 3ms is still factored into the next frame update. I used to do it like this until someone pointed this out to me.

double elapsed = 0;double curTime = /* get perf counter */;double prevTime = curTime;bool quit = false;while (!quit) {	/* get window messages... */	else {		curTime = /* get perf counter */;		double delta = curTime - prevTime;		elapsed += delta;		if (elapsed > 0.01) {			/* update */			elapsed -= 0.01; // makes sure that any more than 10ms is caught up in the next frame		}	}}


Another thing to point out is the use of a looping update.

For example, if you want to update every 10ms, but the current frame was 23ms long, you can do a loop like so:

(Though I don't use this method myself because I'm not sure if its a good way to do things especially if your update rate is too fast for the computer)

while (!quit) {	/* get window messages... */	else {		curTime = /* get perf counter */;		double delta = curTime - prevTime;		elapsed += delta;		// use WHILE to keep updating until all the skipped frames are updated (24ms frame would update twice then end up with an extra 4ms on the elapsed time next frame)		while (elapsed > 0.01) {			/* update */			elapsed -= 0.01; // makes sure that any more than 10ms is caught up in the next frame		}	}}
Hey all,

Thanks so far for your replies i will definately try the timing advice you gave me, however i was just wondering would this really be the solution to my app hammering 50% of my CPU (using up one whole core) ?

And also just wondering even with the way i've got it at the moment missing a few milliseconds here and there as u pointed out it seemed to work fine on a single core. I want my app to be as accurate as possible so im really glad u pointed this out to me i will fix it, but it still bugs me out that it was fine on a single core

any ideas to these?

Thanks in advanced
The reason it is hammering a core is that there is nothing to prevent it from using as much CPU as it can. That is expected and is generally (but not always) acceptable.

If you are accurately tracking the elapsed time ("i found that although my seconds counter is still incrementing correctly my entire animation has halved in speed"), then there is probably nothing wrong with the code you posted and the problem is in the animation code.

Are you using multiple threads?
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Well its not multi threaded and i am not very confident with my animation code either, to give you an idea I am basically changing frame whenever the deltaTime can be modulus 15 and return 0. I am unsure of another way of doing it, to give you an idea ill paste my code that does it

int TDActor::update(double deltaTime, int newAction, double totalTime){	if(totalTime >= spawnTime)	{		spawned = true;		// Increase Time		currTime += deltaTime;		// Set The Current Action		currAction = newAction;		// We get the time in milliseconds so we multiply		// To get an integer and modulus by to increase animation		// frame rate (not the best way to do this but works well)		double tmpTime = currTime * 100;		int animTime = (int)tmpTime;		if((animTime % 15) == 0)		{			currFrame++;			// If we have reached the end of animation			// reset the animation			if(currFrame >= 7)				currFrame = 0;		}		// If the character is walking increase the Y position to move		// down the screen		if(currAction == ACTION_WALK)			yPos += 1;		// If reached the end of screen reset to top (temporary)		if(yPos >= 640)		{			yPos = 0;			return ACTION_ESCAPE;		}		// If time has passed 1 second reset to 0		if(currTime >= 1.00)			currTime = 0.0f;	}	return ACTION_WALK;}


I know there is probably a better way of doing this, if there is could someone please enlighten me ? This is the only way I could think of doing it, as in the past any games i made the animation was based on pixel movement as now it has to be time based for the way my game works

Just to add to that this is the simple draw code, keep in mind I have an image which is 579x64 pixels in size as i have 9 frames across (each frame is 64x64pixels) I simply select a region of pixels i want to display which is what currFrame is for

void TDActor::draw(HDC tdBackBuffer, HDC tdSpriteDC){	if(spawned)		sActor->draw(tdBackBuffer, tdSpriteDC, xPos, yPos, MAX_PIXEL_SIZE, 0, currFrame * MAX_PIXEL_SIZE, 0);}

This topic is closed to new replies.

Advertisement