This question concerns how to create a timer; This timer is used in the topic of a game program, but no gaming knowledge is necessary to answer.
In the case of a small direct draw game, 30 FPS doesn't require 100% CPU on a really powerful system.
The problem I'm having is that my 'game loop' (which is simply my message loop + my game functions) consumes 100% CPU because I use PeekMessage and while() to wait for 33ms to go by so that I can begin the next iteration. This ensures that I loop 30 times per second (at most)
The thing is, this while loop consumes 100% CPU while it is waiting for 33ms to go by. I don't like this. Here is my loop:
Now, if I used Sleep(), the CPU would barely use 20%, because Sleep doesn't hog the CPU like while() does. The thing is, Sleep() isn't as accurate by the millisecond as GetTickCount is.
I need a way to be able to limit my iterations as efficiently as possible by milliseconds, but WITHOUT consuming more CPU that needed.
Any suggestions?
Andreas Masur
February 3rd, 2005, 03:11 AM
Take a look at waitable timers...for additional information you might take a look at this article (http://www.codeproject.com/system/timers_intro.asp). It is a very comprehensive timer tutorial.
MrDoomMaster
February 3rd, 2005, 01:18 PM
Thanks Andreas! Wow I've never seen you not able to answer a question... how long have you been a programmer? You seem to know it all :)
Andreas Masur
February 3rd, 2005, 02:06 PM
You are welcome...yes, I am doing this for quite some time now...but believe me, there are far more question that I cannot answer than the other way round... :eek:
MrDoomMaster
February 3rd, 2005, 04:21 PM
Hmm, well I read the link and I actually attempted to do this myself, but there is a bit of confusion with the parameters. I made the following function in my class:
You submit a time in miliseconds, and the function blocks for that many miliseconds and returns. Kind of like sleep, but more efficient by the milisecond. The thing is, I don't understand the difference between the second and third parameters. I ran through debug with 1000 miliseconds, and it does NOTHING.
DueTime is a LARGE_INTEGER structure, and hTimer is a HANDLE. I declare these elsewhere in the class.
Andreas Masur
February 6th, 2005, 06:20 AM
Well...haven't used waitable timers for a long time...so, let's see whether I get this straight...
The second parameter is the due time of the timer. The thits parameter is the interval the timer will be signaled.
The due time can be either specified as an absolute (positive) or relative (negative) value. Since it is internally based on the FILETIME you would need to take this into account. In your example, you are setting an absolute value, however, this value is way in the past due to the underlying FILETIME which represents the number of 100-nanosecond intervals since January 1, 1601 (UTC).
So...in order to work with absolute values, you would first need to get the actual time and add the number of 100-nanosecond intervals of your waiting time.
Using a relative value is much easier...in your example...
This assignment opertor, didn't you mean the comparision operator ==? Because otherwise this peace of code would be useless:
Timer = (int)GetTickCount();
Andreas Masur
February 8th, 2005, 04:05 AM
Well...how do you know it is not working...I mean where are you actually waiting on the timer to get notified about it? Take a look at the following example:
std::cout << "Wait for 10 seconds..." << std::endl;
// Set timer
if(!::SetWaitableTimer(hTimer, &liTime, 0, 0, 0, FALSE))
{
std::cout << "Could not set waitable timer (Error "
<< ::GetLastError() << std::endl;
::Sleep(5000);
return -1;
}
// Wait for timer
if(::WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
std::cout << "Could not wait for timer object (Error "
<< ::GetLastError() << std::endl;
else
std::cout << "Time elapsed" << std::endl;
// Wait for keystroke
_getch();
return 0;
}
MrDoomMaster
February 8th, 2005, 12:59 PM
I know its not working because I look at my CPU usage during program execution. It should not be 100%!!
When I test my timer, my game functions are commented out (because I do not need them) so the entire loop completes in less than or equal to 33 ms. So this means it should WAIT 33 ms, but it doesn't.
NoHero:
Let me explain to you how it works....
// Lets assume, in this case, GetTickCount() will return 4456 and Timer is 4455
// First we simplify what is in the parenthesis
// This will give us how much time has passed since the last call to GetTickCount()
if((Timer = 1000 / FPS - ((signed)GetTickCount() - Timer)) > 0)
// Now, we want our loop to execute 30 frames per second.
// There are 1000 ms in 1 second, so to get 30 frames a second
// we divide 1000 by 30. (FPS = 30)
// By subtracting 1 from 33.33, we get how much more time
// we must wait before 1 frame can be allowed to pass.
// Total execution time took 1 ms, so now 32 more ms must wait.
if((Timer = 1000 / 30 - 1) > 0)
if((Timer = 33.333 - 1) > 0)
if((Timer = 32.333) > 0)
// Now, we somehow have to send the amount of time to wait to
// the Sleep function. We do this by over-riding the value in Timer with
// how much time we must wait. This saves from having to declare an
// extra variable.
// We want to make sure the time we have to wait is between 33.33 and 0.
// If it is less than 0, then the frame took as long or longer than it should have.
// We will not tell our function to sleep if our time to wait is less than or equal to 0.
// So, timer is now equal to 32, which is greater than 0.
// So this IF statement evaluates true. We now tell our game
// how long to sleep:
I will repeat myself....where are you actually waiting for the timer to be triggered? You are not passing a callback neither did you mention any call to 'WaitForSingleObject()'...take a look again at the example in my previous post...
MrDoomMaster
February 8th, 2005, 01:52 PM
Oh, ****... I didn't know you had to wait on it :(
I thought the function did the waiting. But okay, it works now! Thank you!
Andreas Masur
February 8th, 2005, 02:18 PM
I thought the function did the waiting. But okay, it works now! Thank you!
No problem...you are welcome... ;)
Amn
February 10th, 2005, 10:58 AM
I usually split the execution into two threads in case where message loop should not intervene with the game. The performance and resource hit is minimal, just understand that even when you play big commercial games there are always programs in the background doing message queue processing looping. Basically you are left with a fully responsive UI and fully responsive separate execution thread :)
indiocolifa
February 16th, 2005, 03:53 PM
And how about using the Multimedia Timer? It runs at pretty high resolution in a separate thread automatically.
JohnW@Wessex
February 17th, 2005, 04:56 AM
Multimedia timers are worth a look if timer accuracy is very important.