Sign in to follow this  
japro

Limiting the load my game produces

Recommended Posts

I wrote this breakoutesque game for a course project last semester and did all the development on Linux. But since it uses SFML I now went ahead and compiled it for windows. The game loop does a physics/logic update every 20ms (50Hz) and linearly interpolates for frames in between. Now on Linux it runs at about 500-550 FPS and only after several minutes of play the fan of my laptop slightly increases it's speed and stays there. But the windows version goes up to 1200-1500FPS and has the fans go to full speed in less than a minute. My questions:

1. What could be the reason for the big difference? I use Nvidia drivers (GTX260M gpu) on Linux and Windows.

2. (the important Question) What is the proper way to keep my program from putting so much load on the system? I clearly don't need 500 or even 1500 FPS to make it look "smooth". At the moment I put something like "Sleep(0.8*(time_to_next_physics_update))" into the game loop, but that seems more like a dirty fix than a proper solution to me.

Share this post


Link to post
Share on other sites
1. Windows drivers are generally much more optimized than their Linux counterpart on behalf of 99.5% of the gamer userbase using it.

2. Sleep is generally the solution to keep the FPS in-check and give the system time to do other things. If you don't tell it you don't need to do anything, how is it supposed to know? There is nothing else to be done so it uses all available processing power on what needs it.

Share this post


Link to post
Share on other sites
[quote name='Vectorian' timestamp='1298023803' post='4775785']
2. Sleep is generally the solution to keep the FPS in-check and give the system time to do other things. If you don't tell it you don't need to do anything, how is it supposed to know? There is nothing else to be done so it uses all available processing power on what needs it.
[/quote]

It's not so much the use of Sleep that I think is a "dirty fix" it's more how I use it :). I mean, this is a pretty standard problem right? So there must be some sort of "canonical solution" that is well understood. But my searching efforts so far didn't lead me anywhere.

Share this post


Link to post
Share on other sites
You can turn on vsync. This will limit the framerate to the update rate of the monitor (almost always 60hz), the actual wait will happen inside your "SwapBuffers" call or similar. This is generally how fast it makes sense to update anyways since any drawn frames in between two monitor refreshes won't display on screen (there still is some point to having vsync turned off since it allows the game to have a frame ready immediately when the buffer becomes available, rather than starting drawing once it becomes available).

Share this post


Link to post
Share on other sites
The solution with VSync is quite elegant and should work for you. The only possible problem will be that you will be limited with a fixed FPS - which will vary by the monitor setting.

I don't see anything dirty on Sleep(). But don't forget that the time you pass to Sleep is not guaranteed to be precisely produced. I think especially short times turn out to be higher in reality, so you can find for example that there is no difference between Sleep(2) and Sleep(20). But that doesn't have to be a problem for you.

Share this post


Link to post
Share on other sites
You should definitely add in either a sleep (for a bit more flexibility) or vsync. When Starcraft 2 came out, they forgot about that for the menus screens. The graphics cards ran at 100% and were causing people's computers to overheat.

Share this post


Link to post
Share on other sites
[quote name='Tom KQT' timestamp='1298032956' post='4775824']I don't see anything dirty on Sleep(). But don't forget that the time you pass to Sleep is not guaranteed to be precisely produced. I think especially short times turn out to be higher in reality, so you can find for example that there is no difference between Sleep(2) and Sleep(20). But that doesn't have to be a problem for you.
[/quote]
To elaborate on what Tom said, I recently ran in to this problem with Sleep() not sleeping for the required time. This caused my engine to update at 30-ish Hz, instead of the desired 50Hz. It wouldn't happen every time, but it happened and was annoying. My solution was to turn on vsync like people have mentioned, and use GetTickCount() to watch the milliseconds. (This is a busy wait for your engine update thread, however).

Share this post


Link to post
Share on other sites
[quote name='japro' timestamp='1298025059' post='4775793']
[quote name='Vectorian' timestamp='1298023803' post='4775785']
2. Sleep is generally the solution to keep the FPS in-check and give the system time to do other things. If you don't tell it you don't need to do anything, how is it supposed to know? There is nothing else to be done so it uses all available processing power on what needs it.
[/quote]

It's not so much the use of Sleep that I think is a "dirty fix" it's more how I use it :). I mean, this is a pretty standard problem right? So there must be some sort of "canonical solution" that is well understood. But my searching efforts so far didn't lead me anywhere.
[/quote]

There is, and it's pretty much Sleep(). The usual way to do it looks like this in psuedocode:

[code]
int timeUntilNextUpdate = 0;

while(true)
{
timeUntilNextUpdate += 1000 / DESIRED_FPS; // 1000 because sleep uses milliseconds
update();
render();
if(GetSystemTimeInMilliseconds() < timeUntilNextUpdate)
{
Sleep(timeUntilNextUpdate - GetSystemTimeInMilliseconds());
}
}
[/code]

This will make sure you never do more than DESIRED_FPS, and your CPU will spend the rest of the time idling or running other programs. This is exacly what goes on under the hood when you enable vsync, btw. The video drivers puts your thread to sleep until it can flip the buffer synchronously.

Share this post


Link to post
Share on other sites
Note that Sleep does NOT say "sleep for X seconds" it says "sleep for [i]at least X seconds"[/i]. That means you may not wake up for a long time. The default timeslice on your computer under windows is ~15ms. If you sleep for any time between 1 and 15ms, you likely won't wake up for 15ms or longer. This can lead to some undesireable behavior.

Share this post


Link to post
Share on other sites
[quote name='KulSeran' timestamp='1298075542' post='4776161']
Note that Sleep does NOT say "sleep for X seconds" it says "sleep for [i]at least X seconds"[/i]. That means you may not wake up for a long time. The default timeslice on your computer under windows is ~15ms. If you sleep for any time between 1 and 15ms, you likely won't wake up for 15ms or longer. This can lead to some undesireable behavior.
[/quote]

While it's true that it may not sleep for the amount of time you request (or even get close), the sleep loop I posted will automatically correct for that.

Let's say you want a target framerate of 100FPS, that's a target frame length of 10 ms. Let's assume your computer sleeps for a minimum of 15ms. That may seem like it will cause problems, since you'll always sleep for a longer time than you wanted. But it doesn't. If we sleep too much, we just end up doing two (or more) frames right after the other without sleeping between them. That's why I check the actual time against the desired time, and only sleep if we're behind. It forces the loop to keep updating without sleeping until we catch up to the desired time again.

So while you may not be able to run all 100 frames at an even rate, all 100 updates will fire, and the overall result will be that you perceive 60FPS (since 15ms sleeps come out to 60FPS).

[font="Arial"]You can, however use timeBeginPeriod() on Windows to adjust the timer resolution down to 1ms. Only do this if you really need to, though, as it will affect all other processes on the system and can have a negative impact on overall performance, since the thread scheduler will swap threads more frequently. See this link for info: [url="http://msdn.microsoft.com/en-us/library/dd757624%28v=vs.85%29.aspx"]http://msdn.microsoft.com/en-us/library/dd757624%28v=vs.85%29.aspx[/url][/font]

Share this post


Link to post
Share on other sites
Ok, now I tried inserting sleeps in different ways.
[code]
Sleep(time to next update)

Sleep(time to next update * 0.9)

if(time to next update > 15ms)
Sleep(time to next update)
[/code]
the first one gets choppy occasionally, the second and last one kinda work, but produce very inconistent framerates. Somtimes it will run at 1000fps than randomly drop to 200 for a few seconds then stay at 500 for a while...

On windows turning vsync on in SFML works nicely. Animation is fluid, framerate is constant at 60fps and cpu load is really low (I assumed doing brute force polygon-polygon collision and rigid bodies would use up more than 8% of the cpu O_o ). But on linux it looks choppy again. I guess this is some sort of "interference" between the 60hz of the vsync and 50hz update of the game that makes you percieve it more like 30fps than 60...
So what does Vsync do exactely? I assume it doesn't actually use Sleep or otherwise it shouldn't be able to get dead on 60fps with the time quantum almost being in the same as the desired frame interval.

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