game loop is causing high CPU usage

game loop is causing high CPU usage

Postby Sauer2 » 18 Jun 2014, 18:52

Hi,

after visiting http://gameprogrammingpatterns.com/game-loop.html a friend of mine and I decided to develop a little game using the fixed time step algorithm and SFML2.

So far we have
{l Code}: {l Select All Code}
        while(window.isOpen()) {
           
            sf::Time currentT = clock.getElapsedTime();
            sf::Time elapsedT = currentT - previousT;
            previousT = currentT;
            lag += elapsedT;
            // todo: validate input here
            while(lag >= msPerUpdate) {
                update();
                lag -= msPerUpdate;
            }

            draw( lag.asSeconds() / msPerUpdate.asSeconds() );

        }

with
{l Code}: {l Select All Code}
sf::Time msPerUpdate = sf::seconds(0.0166);

because 1000 ms / 60 fps ~= 16,6667 ms and that seems to work. At least the sprites have fluid movement.

The problem is the high CPU usage.
Is there a possibility to put in an sf::sleep() somewhere?
Simply putting it behind causes stuttering and doing something like this
{l Code}: {l Select All Code}
            while(lag >= msPerUpdate) {
                update();
                sf::sleep(sf::milliseconds(2));
                lag -= msPerUpdate + sf::milliseconds(2);
            }

only gets 1/2 of the CPU usage, which is still too much, considering the simplicity of the game code.

Edit: Another question is: Is this kind of loop even suitable for low CPU usage?
Thank you in advance.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 18 Jun 2014, 19:47

Fixed timestep is a requirement for stable physics. If your framerate is low, you will get a high CPU load due to multiple updates per frame. Something you maybe don't want.

Maybe something like this would work better

loop:
t0 = clock.getElapsedTime()
update()
draw()
t1 = clock.getElapsedTime()
dt = t1 - t0
st = 0.0166 - dt
if st > 0 sleep(st)
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 18 Jun 2014, 21:18

NaN {l Wrote}:Fixed timestep is a requirement for stable physics. If your framerate is low, you will get a high CPU load due to multiple updates per frame. Something you maybe don't want.

Maybe something like this would work better

loop:
t0 = clock.getElapsedTime()
update()
draw()
t1 = clock.getElapsedTime()
dt = t1 - t0
st = 0.0166 - dt
if st > 0 sleep(st)


Thanks!

When you speak of stable physics, how unstable is this other approach?
I don't need ultra-precise movement, since this won't be a multiplayer game, but will I get remarkable movement glitches?

Also, is your approach a fixed framerate? SFML offers this built-in and we used this as stub before. I just wasn't sure it is was a proper way.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 18 Jun 2014, 22:38

It depends on how you calculate your movement (physics). It shouldn't be a big deal if your fps is somewhat constant (st always > 0). My code example will keep fps <= 60fps, depending on what you are doing in update and draw.

If you need physically correct forces (physical joints, contact constraints and stuff), fixed steps are the way to go, also for things like multiplayer and simulation recording/replay.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 18 Jun 2014, 22:56

Thank you for your help.
Judging from that the game will aprox. be a simple top-down shooter thingy the fixed steps are an overkill.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby Sauer2 » 19 Jun 2014, 01:09

I tested this
{l Code}: {l Select All Code}
        sf::Clock clock;
       
        while(window.isOpen()) {
            sf::Time t0 = clock.getElapsedTime();
           
            update();
            draw();
           
            sf::Time t1 = clock.getElapsedTime();
           
            sf::Time dt = t1 - t0;
           
            sf::Time st = sf::seconds(0.0166) - dt;
            if(st.asSeconds() > 0) sf::sleep(st);
        }

as well as the built-in setFramerateLimit function and both share the same problem: The movement of elements is stuttering.
Do you know why and how this could be fixed? Do I somehow have to pass a time over update()?
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 06:30

What are your frame times? Try to log t0, t1, dt, st to see where the issue comes from. Is the code available somewhere?

Edit:
What are the times with the draw call commented out?
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 19 Jun 2014, 12:44

NaN {l Wrote}:What are your frame times? Try to log t0, t1, dt, st to see where the issue comes from. Is the code available somewhere?

Edit:
What are the times with the draw call commented out?


I've made two log files, both from 5 seconds. There is nothing unusual, as far as I can see.

To be more precise, the stuttering isn't like a lag but rather as if the enemies speed changes for some ms.
This is independent of the direction and totally doesn't make sense, because we use constant speed.

The code is here https://github.com/sauer2/shadowed-shooter - however it's a mess and a build system isn't there.
The movement is written in enemy.cpp in Enemy.move().

Be aware that this is still the fixed step version, so there is still interpolated drawing, whereas my local modified version only has
{l Code}: {l Select All Code}
window.draw(_sprite);

in the method.


The main loop of the modified version is like following:
{l Code}: {l Select All Code}
        while(window.isOpen()) {
            sf::Time t0 = clock.getElapsedTime();
           
            update();
            draw();
           
            sf::Time t1 = clock.getElapsedTime();
           
            sf::Time dt = t1 - t0;
           
            sf::Time st = sf::seconds(0.0166) - dt;
            if(st.asMilliseconds() > 0) sf::sleep(st);
           
            fil << "t0: " << t0.asSeconds() << std::endl;
            fil << "t1: " << t1.asSeconds() << std::endl;
            fil << "st: " << st.asSeconds() << std::endl;
            fil << "dt: " << dt.asSeconds() << std::endl;
            fil << "====================================" << std::endl;
           
            if(clock.getElapsedTime().asSeconds() > 5) {
                fil.close();
                break;
            }
        }
Attachments
log_without_draw.txt
(28.04 KiB) Downloaded 430 times
log_with_draw.txt
(28.22 KiB) Downloaded 428 times
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 13:57

Wow, your dt is tiny.

Frame time seems to be good too (t0 - t0 prev) 0.015 - 0.016 sec.

I'll look at the code a bit later today.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 19 Jun 2014, 14:38

NaN {l Wrote}:Wow, your dt is tiny.

Frame time seems to be good too (t0 - t0 prev) 0.015 - 0.016 sec.

The code does very little. At the moment, 3 sprites are moved.
NaN {l Wrote}:I'll look at the code a bit later today.

Thank you, that's nice.
EDIT: I uploaded a branch with this approach: https://github.com/sauer2/shadowed-shoo ... -framerate
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 15:42

I've had a quick look.

You are moving the enemies by a fixed distance per frame. So their speed will scale with the frame rate.

Looking at the frame times (t0 delta), I've noticed something interesting:
ft: 0.025635 dt: 0.001189 st: 0.01541
ft: 0.005549 dt: 0.000982 st: 0.015617

ft here is last frame time calculated from last and current t0, so it should be >= dt + st.

It seems like sf::sleep is not working as expected.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 15:54

A bit googling shows sleep timer resolution of 15.6ms on Windows 7, which matches very well with my ft numbers :P

even for (0.025635 + 0.005549) / 2 = 15.6ms
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 16:04

"This function causes a thread to relinquish the remainder of its time slice and become unrunnable for an interval based on the value of dwMilliseconds. The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time."

So it does what we want, but we can not control it due to low timer resolution.

Using frame time (ft) in sprite movement calculation should fix this:
sprite_.setPosition(thisPos + speed_ * ft);
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 19 Jun 2014, 16:54

Thank you very much.
That all sounds like ones has basically two options on non-realtime platforms:
Fixed time step for serious game engines and variable time step (which would basically be your method) for games like ours or mobile games.
http://gamedev.stackexchange.com/questi ... -time-step
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 19 Jun 2014, 17:14

Yeah, if you want to save power, you have to live with a variable time step I guess.

PS:
Interestingly enough, the linux/posix equivalent nanosleep() guarantees to be not shorter than the requested time. But also depends on timer resolution.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 19 Jun 2014, 17:23

NaN {l Wrote}:Yeah, if you want to save power, you have to live with a variable time step I guess.

PS:
Interestingly enough, the linux/posix equivalent nanosleep() guarantees to be not shorter than the requested time. But also depends on timer resolution.

Well, close enough. Also, accordings to that stack exchange link, Quake 3 engine, which is often praised as one of the best engines has physics depending on the framerate.
Again, thanks for your help.

EDIT: We tried several kinds of update interpolation and still it didn't seem to be as smooth as with fixed timesteps. Since even simple space/top-down shooters like DOVE or violetland use fixed timesteps, we decided to go back to that approach, since our game isn't for mobile devices anyway.
Nonetheless, thanks for your support.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby mdwh » 21 Jun 2014, 16:34

The logs for the variable version show that doing update() + draw() takes 1m or less, with update() alone taking around 0.05ms. So draw() only takes around 1ms.

Going back to the code in the original fixed timestep version, we only accumulate enough to call update() every approx 16 loops, and it's only then that you call sleep. So every 16.6667ms, you sleep for 2ms. So this wouldn't make much difference to the CPU usage at all - in practice, the inaccuracy of the timer may mean it's sleeping for longer, cutting CPU to 50%.

Would it work to simply call sleep in the outer loop - so it's called once per iteration, rather than in the inner update loop (where it may be called 0, or multiple, times in an iteration depending on the times)? Also rather than a fixed constant sleep time, you want to sleep for (fixed_interval - time_elapsed), so effectively you set a max frame rate of say 60fps. E.g., see the "sleep(start + MS_PER_FRAME - getCurrentTime());" example in the gameprogrammingpatterns.com link, or the example NaN gives.

I don't see why doing a sleep shouldn't work for a fixed time step (even if the sleep time is variable, that's no different to a variable render, either way you call update enough times to catch up)... though it's odd that the gameprogrammingpatterns.com link only mentions sleeping in the early simple example, and doesn't cover it for the later variable or fixed timesteps, though it does allude to it in the "How do you manage power consumption?" section.
mdwh
 
Posts: 67
Joined: 13 Aug 2011, 01:53

Re: game loop is causing high CPU usage

Postby NaN » 21 Jun 2014, 17:01

You are right mdwh, assuming very low update() times, the sleep after the draw call should also work with fixed steps.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 21 Jun 2014, 19:27

Well, i tested this:
void Game::loop() {

sf::Clock clock;
sf::Time previousTime = sf::milliseconds(0);
sf::Time lagTime = sf::milliseconds(0);

while(window.isOpen()) {
sf::Time currentTime = clock.getElapsedTime();
sf::Time elapsedTime = currentTime - previousTime;
previousTime = currentTime;
lagTime += elapsedTime;

while (lagTime >= frametime + sf::milliseconds(8)) {
update();
lagTime -= frametime;
}

draw(lagTime.asMilliseconds() / frametime.asMilliseconds());

sf::sleep(lagTime - (previousTime - clock.getElapsedTime()));
}
}


frametime is the 16.66... ms.

It reduces the CPU load, but it isn't equally smooth as the non-sleeping solution.
If I don't put that 8 milliseconds into the inner loop, it has fluid movement, but the CPU core is at 100% again.

EDIT: Given, it will eventually work, what will happen, if the update time grows?
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 21 Jun 2014, 21:03

Well, the worst case I've seen happening, is when your draw() is taking like 30ms and your 60 hz update() 10ms.

You will get something like this:
1 * 10 + 30 = 40 ms frame 1
3 * 10 + 30 = 60 ms frame 2
4 * 10 + 30 = 70 ms frame 3
4 * 10 + 30 = 70 ms frame 4
-> chuck along at 70 ms per frame or 14 fps, think about moving update into separate thread

;)

PS:
It can get even worse if your update is taking the same amount of time as the update time step, then you will get increasing frame times and have to hard limit the number of updates per frame.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 21 Jun 2014, 21:42

Well, I guess it won't get that bad, since the game consists of moving around about 10 elements in a room.
The problem is, I'm not quite sure where to put the sleep function call and which time exactly to put in there, as the above doesn't seem to work.
Putting the sleep call above the inner loop doesn't help.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby NaN » 21 Jun 2014, 23:23

I'll have a look.

PS:
There is something that has been bugging me recently. Let's say the display is running with a fixed frame rate of 60 Hz, the image changing every 16.6 ms, so ideally the display should drive the loop. Enabling vertical synchronization should stall the draw call until the frames are swapped. No need for sleep.

I've tried it on my intel laptop... and it didn't work. Not sure if it is a driver or smfl issue.
NaN
 
Posts: 151
Joined: 18 Jan 2010, 10:32

Re: game loop is causing high CPU usage

Postby Sauer2 » 22 Jun 2014, 10:36

NaN {l Wrote}:I'll have a look.

That's really nice. Also, thank you too, mdwh. However, no need to put too much efforts in this. It's nice to have, but not more. ;)

NaN {l Wrote}:PS:
There is something that has been bugging me recently. Let's say the display is running with a fixed frame rate of 60 Hz, the image changing every 16.6 ms, so ideally the display should drive the loop. Enabling vertical synchronization should stall the draw call until the frames are swapped. No need for sleep.

I've tried it on my intel laptop... and it didn't work. Not sure if it is a driver or smfl issue.

From what I hear about the quality of OpenGL drivers these days, I wouldn't be surprised about driver issues. It's not a story full of heroism.
A fast search showed that the driver can somehow decide to keep vsync disabled/enabled.

EDIT: Do you have some kind of control center? Maybe it's deactivated for all applications.
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: game loop is causing high CPU usage

Postby mdwh » 22 Jun 2014, 13:40

> sf::sleep(lagTime - (previousTime - clock.getElapsedTime()));

Shouldn't this be frameTime (or some fixed constant anyway - whatever you want to cap the max frame rate at), rather than lagTime? lagTime will be anything from 0 to frameTime-1, causing a variable sleep each time.

I'm not sure if that's the cause of being non-smooth, or why ading 8ms to the loop affects things, but I'd try fixing up the sleep, then see what effect that has...

And yes, a slow update is one of the problems with fixed step. In the worse case, you get the "death spiral" where update takes longer than the time step, so you get stuck in an infinite loop - a fix is to limit the number of iterations so on slow machines, the game rate slows (which isn't ideal, but things are still stable and predictable).

But I've seen less discussion on what to do where the update time takes a significant proportion of the time step. E.g., in the example NaN gives, a variable step version would only have to call update() once, and could get 30+10=40ms, i.e., 25fps. But having to call update() multiple times in the fixed step version significantly slows things down.

Ideally update() should never be the bottleneck - perhaps some things don't need to run every time, and can run at a slower rate (e.g., AI, or update for things that aren't in the player's vicinity).

These are all complications (also the difficulties of calling render() with interpolation) why I've yet to implement fixed step :) An approach I've taken is to put a maximum on the time used in the variable update - the idea being that instability becomes much more a problem when time steps become large. So on slow machines, the game rate slows rather than becoming unpredictable, but otherwise it behaves with a variable step. But then I've yet to do games with any significant physics - if you don't have things like acceleration, gravity, bouncing etc, I think instability is less likely to be an issue.
mdwh
 
Posts: 67
Joined: 13 Aug 2011, 01:53

Re: game loop is causing high CPU usage

Postby ginkgo » 06 Jul 2014, 16:03

Sauer2 {l Wrote}:From what I hear about the quality of OpenGL drivers these days, I wouldn't be surprised about driver issues. It's not a story full of heroism.
A fast search showed that the driver can somehow decide to keep vsync disabled/enabled.


Yes you can force enable/disable VSync of applications in the graphics driver settings. This is an option that many users like to have, however.

Like other's probably already said in this thread: Sleep functionsd on't guarantee how long they will set a process to sleep and might even busy-wait for short intervals. They also won't help you with syncing to the screen to avoid tearing.

You should make use of VSync to avoid all of this. If a user manually disables VSync, then this means he's willing to put up with high CPU utilization and tearing for a slightly lower input latency.

So what you should do in your main loop is to measure the amount of time elapsed since the last swap and use that to increment your simulation. As has been mentioned, it's often preferrable to do simulation at a fixed timestep. This doesn't mean that you have to render your images at that timestep, though. Let's say you simulate at 50Hz, so every 20ms. If you have a frame render time of 8ms this would mean that you increment the simulation every 2 frames or so. You can interpolate object positions inbetween (This is what bullet does) If you have a framedrop to 10Hz, then you have to do 5 simulation steps at once (this is of course problematic, since this might slow down your game even more - Most games limit the number of simulations that can be done per frame and have the program just slow down)
ginkgo
 
Posts: 15
Joined: 14 Dec 2009, 17:10

Who is online

Users browsing this forum: No registered users and 1 guest

cron