Sign in to follow this  
Gruik

High resolution counter

Recommended Posts

Gruik    100
Hello, In my multiplayer game, i may need that things move at the same speed on each client. So, i'd like to use a seperate thread for moving my objects and displaying. Moving and displaying in the same thread may force my objects to move at the monitor frequency, because directx' Device::Present() waits for vertical retrace before copying backbuffer. Moving things in my game will have a speed expressed in "unit of measure per unit of time" where unit of measure is defined and unit of time may be µs or ms. I'm using C# and hoped to use Environment.TickCount that should return the number of elapsed milliseconds since the beginning of the program. But i've made some tests and its accuracy seem to be computer specific. On my computer, it provides a new value only each 16ms (62,5Hz, quite my monitor frequency). It's the same for TimeDate.Now.Ticks. I've found this win32 function that i could import in my c# code : QueryPerformanceCounter() But i've read this is not available on every systems. Do you know on which kind of systems this is unavailable? or do you know another method to fetch a better counter?

Share this post


Link to post
Share on other sites
Drew_Benton    1861
Here's some information on timers. From that page:
Quote:

The Pentium processor and most PC compatible processors such as AMD support a high-resolution Performance Counter, which can provide a resolution of less than one microsecond.

The QueryPerformanceFrequency function is used to determine the actual frequency of the counter. This is the numeric value that the Performance Counter will increase by in 1 second.

The QueryPerformanceCounter function is used to read the Performance Counter, which may be divided by the counter frequency to determine the time in seconds.

Both of these functions take a pointer to a LARGE_INTEGER union, which will be filled with the requested value if the function is successful.

The function will return 0 on failure, or non-zero on success.


Ideally what you should do is something like this. Have support for two timers in case the QueryPerformanceCounter does not exist. Other than that, that timer is the best you can have. I don't know how much of help that code is begin in C++ format, but hopefully you can get the idea of what to do. Good luck! [smile]

Share this post


Link to post
Share on other sites
nife    235
timeGetTime with a call to timeBeginPeriod(1) in the beginning and timeEndPeriod(1) in the end isn't as accurate as QueryPerformanceCounter which uses the TSC, but is more accurate than the ones you describe, so it could be a good second choice for a timer.

You should be aware of mobile processors that can change their clock frequency, because then your timing won't work if you're using the ones that totally rely on the frequency, like QueryPerformanceCounter. timeGetTime will do the job in those cases, so that should be a good second choice for a timing system.

Share this post


Link to post
Share on other sites
ursus    206
i decided to learn and test timeGetTime throughoutly before turning to QuerryPerformacneCounter but after running some tests on differen machines I noticed the in a longer loop the times vary. i don't really understand why but on one pc it takes the loop 10 sec to execute while on other machines it takes 7 or 15 seconds. the time factor is set to 0.01 second as with lower values differences between times to execute the loop vary much more.

can anyone explain to me this weir behaviour?

reagrds

Share this post


Link to post
Share on other sites
nife    235
Quote:
Original post by ursus
i decided to learn and test timeGetTime throughoutly before turning to QuerryPerformacneCounter but after running some tests on differen machines I noticed the in a longer loop the times vary. i don't really understand why but on one pc it takes the loop 10 sec to execute while on other machines it takes 7 or 15 seconds. the time factor is set to 0.01 second as with lower values differences between times to execute the loop vary much more.

can anyone explain to me this weir behaviour?

reagrds


If the OS is multithreaded anything could happen in between your loop start and end. If you haven't, you should set the priority of your thread to real-time to get the best/most accurate results. I'm assuming that you did shut down all other programs that could be shut down without trouble (anti-virus, firewall, messenger etc.) while you were testing it?

I haven't tested timeGetTime on my computers yet, but I would certainly make sure that my above terms are reached before testing - otherwise it could just as easily be another program(s) that were causing the slowdown.

Share this post


Link to post
Share on other sites
ursus    206
most likely you're right, but if so, can someone explain to me how it's done with pro games? even those short and simple ones appear to run at constant speed (despite changing frame rates) on most pcs?

Share this post


Link to post
Share on other sites
Extrarius    1412
Two things: Don't use QueryPerformance*, because it doesn't work properly on computers that vary their cpu speed. Almost all laptops do this, and most modern pentium 4 processors do as well (and in the future, AMDs will likely do the same).

Next, leave your game's process priority set to normal. To do otherwise will interfere with the operating system in a negative way, and can cause the whole system to become so unresponsibe that the only option for the user is to do a manual reboot (on modern machines that means either holding the power button for a while or pulling the plug).

Finally, it shouldn't matter how long the frame takes as long as you base movement on time. If you're doing straight line movement, then each frame you just do position += velocity * time. For more complicated systems (with things like gravity, acceleration and that kind of thing), you need more advanced systems (called numerical integrators). A popular and rather accurate one is calld RK4

Share this post


Link to post
Share on other sites
ursus    206
Extrarius,

i caould put some example source here, but i'll just resort to famous NEHE 21 tutorial. when i ran it on different pcs it works with differen speed. so it's the question of the code i suppose.

i heard about accumulators. have you got any experience using them? are they worth learning and implementing?

take care

Share this post


Link to post
Share on other sites
Extrarius    1412
The speed of the code itself doesn't matter.
For example, lets say that on PC1, a frame takes 1 second, and on a PC2 it takes 2 seconds.
Also, lets have a monster that travels 10 pixels per second.

If you have the code
monster.position = monster.position + 10;
then it will move differently on PC1 and PC2 because they run at different speeds

If you have
monster.position = monster.position + (10 * frame_length);
then on PC1, frame_length is 1.0 (for 1 second) so the monster moves 10 pixels in 1 second, but on PC2 frame_length is 2.0 (for 2 seconds) so the monster moves 20 pixels in 2 seconds which is equal to 10 pixesl per second. Because you put the amount of time passed into the equation, both computers end up with the monster in the same place.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
"Two things: Don't use QueryPerformance*, because it doesn't work properly on computers that vary their cpu speed. Almost all laptops do this, and most modern pentium 4 processors do as well (and in the future, AMDs will likely do the same)."

Isn't this just an urban legend?

The frequency is the frequency of the timer and not the CPU.
If there was such a problem, would it not be mentioned on msdn?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
"If you have monster.position = monster.position + (10 * frame_length);
then on PC1, frame_length is 1.0 (for 1 second) so the monster moves 10 pixels in 1 second, but on PC2 frame_length is 2.0 (for 2 seconds) so the monster moves 20 pixels in 2 seconds which is equal to 10 pixesl per second. Because you put the amount of time passed into the equation, both computers end up with the monster in the same place."

If you are using floats then they will not end up at the same place. Thats why you should run an app at a certain tickrate.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this