Sign in to follow this  
Pilex

Locking functions to timers

Recommended Posts

Pilex    122
Heya guys! I and X3non (also a member here)are making a game, and we stumbled upon quite a stupid problem :( I want the game logics and graphic output divided into two "threads" (OMG multi threading!) and i had the idea to lock a function for logics to a timer, meaning the logics would be going on and on without any actual logics code (except the locking to the timer) in the main function (WinMain :P). We're using Open GL, if that's of any help. Oh, and i got this idea from the "Allegro" game library, where I successfully have done this (the function is install_int_ex). So, can anyone assist us with this lil' problem here? HALP!

Share this post


Link to post
Share on other sites
Mike2343    1202
I'm not exactly sure what you're looking for as, to me, it wasn't very clear. You can do it via multi-threading or you could just call your logic loop ever x milliseconds and your render loop as fast as possible. In our engine you can set both to a set time. Our logic updates every 30 times a second while the renderer we, currently, let run maxed out.

Share this post


Link to post
Share on other sites
Pilex    122
Quote:
Original post by Mike2343
...you could just call your logic loop ever x milliseconds and your render loop as fast as possible.


Yes, that was the idea, but do you have any suggestions regarding that?
How can we make our logic loop to be called every x milliseconds, while the rendering loop is "independent".
Can it be done like this:

loop
check if 30 ms have passed, if yes, run the logic
anyway, run the graphics
begin loop from start

The problem here would be if the render would take more than 30 ms, making the game "slower" and complicating the code because we would have to make a "time passed" check to see if we have to put some multipliers in our logics :/
All we wanted were two independent parts of the program: logics and graphics (rendering).
So, any ideas how we could do the idea quoted?

Hope this will clear out some stuff.

Share this post


Link to post
Share on other sites
Structural    328
Sounds like you want to "force" a fixed "framerate" for your game logic so that you do not have to multiply your movement speed and other update logic with a "time-passed" multiplier. Personally I'm not very fond of this because, although the game logic might become a tad easier for you (debatable), it is not robust for the reason you provided: what if rendering takes longer than 30ms, or what if the update somehow, due to heavy processor load, is not finished in 30ms, or what if the logic does not happen exactly on those 30ms?

You have little control over those factors if you run your game on different computers. To make it a bit more robust in such situations you could introduce a real thread that does the logic and lock the whole rendering procedure and logic procedure with a mutex. I believe the Windows default time slicing unit is 25ms (from the top of my head), so if your two threads are the only two that are consuming processor power your logic thread is "guaranteed" to be able to get some processor time every 25ms.
Little trick: throw in a Sleep(0) at the end of your rendering/logic thread to force a context switch for greater precision.

In theory this should have the effect you want: (relatively) fixed logic timing, and relatively robust against your rendering taking more than 30ms. But my gut-feeling still says it's better to multiply any game logic with a time-passed factor every frame because that would make the system also robust against any outside factors influencing the timing.

Share this post


Link to post
Share on other sites
Hnefi    386
Personally, I don't like the idea of multiplying everything with a time factor, because if you are running on specs that are below recommended requirements anyway that will cause the game to run even slower. Sure, things will always move at the correct speed, but your framerate will suffer more.

Since you are apparently using WinAPI, I recommend using WinAPI's timers. This gives you the added bonus of the program only using the CPU time it requires to run full speed, leaving CPU resources to do other stuff while playing the game, should you need it for whatever reason.

Doing so looks something like this:
liDueTime.QuadPart=-100000; //100Hz (max)

hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer");
if (NULL == hTimer)
{
//error handling
}
if (!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0))
{
//error handling
}

while(!done){
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0);
GameLogic();
GameRender();
if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
//error handling
}


Share this post


Link to post
Share on other sites
Antheus    2409
If you don't care about accuracy of timers, then you can get by with single-threaded model.

Create a sorted queue (can be priority queue as well). When you enqueue an event, set its expiry time as (currTime + duration). On each pass through main loop, scan for all the events which have expired (event.expiryTime < currTime), and call their handlers. The sorted property (or priority queue) ensure that you can find which events have expired very efficiently.

This will give you the resolution of one frame for your timers, which should probably be enough for most purposes.

For high resolution accurate timers, locking, threading, asynchronous programming come into play.

Share this post


Link to post
Share on other sites
smr    2468
Quote:
Original post by Hnefi
Personally, I don't like the idea of multiplying everything with a time factor, because if you are running on specs that are below recommended requirements anyway that will cause the game to run even slower. Sure, things will always move at the correct speed, but your framerate will suffer more.


Are you saying that the possible few thousand extra multiplies required would increase the processing time by some significant amount? How many millions of floating point multiplications can any modern FPU accomplish in under one second?

Share this post


Link to post
Share on other sites
Hnefi    386
If it's only a few thousand multiplications, I very seriously doubt that the game will run below 30-50 FPS anyway and the technique becomes irrelevant. For games with many thousands of objects that move in several dimensions, you essentially add one floating point operation to every dimension of freedom of every object and every (temporal) action. That can mount to upwards a million FLOPs - every frame. If it takes even a significant fraction of a second (such as 1/100) to perform those operations on a recommended-specs computer, the results is too much of a performance loss (and gets progressively worse with cheaper computers).

One exception is applications that are completely GPU-bound, of course. But then, why not let the extra CPU be used for other applications instead of worrying about people with underspeced computers being able to run the app at full speed?

Another exception, one that is legitimate, is synched real-time P2P games that, as part of the game design philosophy, should not be slowed down by one crappy client. But that's a pretty rare exception.

Share this post


Link to post
Share on other sites
jpetrie    13104
Quote:

If it's only a few thousand multiplications, I very seriously doubt that the game will run below 30-50 FPS anyway and the technique becomes irrelevant. For games with many thousands of objects that move in several dimensions, you essentially add one floating point operation to every dimension of freedom of every object and every (temporal) action. That can mount to upwards a million FLOPs - every frame. If it takes even a significant fraction of a second (such as 1/100) to perform those operations, the results is too much of a performance loss.

This is completely silly. Pretty much all games out there that are nontrivial used some kind of elapsed-time-based mechanism that involves multiplications you're talking about. They run perfectly well.

Even if this becomes an issue (it is highly unlikely, about one step removed from completely impossible, as it is far more likely that any more complex updating mechanism would vastly overshadow the "cost" of a the multiplication by the elapsed time factor), the solution is not to make the multiplication faster but to do less multiplication (that is, update less objects by improving your algorithm).

Piddling about in this fashion is premature micro-optimization. The benefits in simulation scalability and stability you gain from elapsed-time-based updates far aways the minuscule performance impact they have. The only reasons not to use such mechanisms are if you are lazy or if they are unsuitable (as in physics, where fixed time steps help preserve the stability of the integrator).

Share this post


Link to post
Share on other sites
Hnefi    386
Quote:
Even if this becomes an issue (it is highly unlikely, about one step removed from completely impossible, as it is far more likely that any more complex updating mechanism would vastly overshadow the "cost" of a the multiplication by the elapsed time factor), the solution is not to make the multiplication faster but to do less multiplication (that is, update less objects by improving your algorithm).

Doing less multiplications is a separate issue. Obviously, that's more important, but it doesn't have anything to do with this particular situation.

Also, the alternative to keeping track of elapsed time is not a "more complex updating mechanism", but rather the opposite. The example I showed above is much simpler than calculating a timeslice and multiplying everything by it. You do, of course, need other methods to deal with interacting objects (collision detection that is independent of the size of a tick) but you need that with your method too.

As far as I can see, the only advantage to calculating and multiplying timeslices is that you don't experience logic slowdowns on low-end computers. The cost is maintainability, simplicity and (arguably) performance.

Quote:
Piddling about in this fashion is premature micro-optimization. The benefits in simulation scalability and stability you gain from elapsed-time-based updates far aways the minuscule performance impact they have. The only reasons not to use such mechanisms are if you are lazy or if they are unsuitable (as in physics, where fixed time steps help preserve the stability of the integrator).

Apart from the exception mentioned in my previous post, I don't see how you can claim to improve stability with that method. The point of scalability I will accept though. I also don't see how my method is "piddling about" - it is the very opposite. 4 function calls and you're done.

Share this post


Link to post
Share on other sites
jpetrie    13104
You've misunderstood the focus of my arguments. Let me try to clarify:

Quote:

Also, the alternative to keeping track of elapsed time is not a "more complex updating mechanism",

Correct, it isn't. The "more complex updating mechanisms" (I actually meant to use "machinery" which might have helped to disambiguate; I don't know) I was referring to were not related to timeslicing, but rather to other operations that would need to be performed on a given object to "update" it (testing and setting state, checking logic against other objects state, collision test and response, et cetera). Things that need to be done regardless of whether or not you use a fixed-step or delta-step method and whose computational complexity is much larger than a couple trivial multiplications.

Quote:

The cost is maintainability, simplicity

Both of these are arguable as well. Maintainability depends heavily on what the game needs to be doing and the context that its running in (and on). The amount of code involved for (correct) fixed-step updates and variable-step updates is pretty much the same. For similar reasons, the simplicity argument only holds unarguably if you don't include any timeslice control, in which case the updates become entirely CPU-bound (and will run slower on slower machines and faster on faster machines, to the point of being too slow or too fast, which is obviously not desirable).

Quote:

I also don't see how my method is "piddling about"

Your method isn't, but the general concept of being prematurely concerned about the overhead of an extra floating-point multiply per calculation is. There's nothing wrong with the example you posted (near as I can tell); what I'm taking issue with is your implication that updating objects based on an elapsed time is too slow for a large set of objects (as this is done in a vast majority of games, and every game and software product I've worked on, and the bottleneck always turned out to be elsewhere).

I don't have a problem with the update step locking method you posted at all (what I would have a problem with is no update step control at all, as I mentioned briefly above). Just the performance "impact" issue.

Share this post


Link to post
Share on other sites
Hnefi    386
Ah, ok. I see we're not really in disagreement at all, we just focus on different things. I admit I overstated the potential impact on performance, probably because it was the primary reason I started using fixed timing once upon a time.

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