Limiting Cpu Usage

Started by
9 comments, last by captain_crunch 7 years, 8 months ago

I have a Monogame-based game that uses variable timestep. The variable timestep causes the game to gobble up all the CPU time it can. The game is a CPU-intensive realtime simulation game. But sometimes it seems the game uses too much CPU, especially when it's on a menu or is paused (even though the player can perform actions while paused) and not much is going on. Some players have noticed this also.

I guess what I want in those instances is to lower the framerate and the number of Update calls the game receives. I can do that quite successfully by inserting the statement Thread.Sleep(50) in the Update method.

But, how can I regulate it so only high performance CPUs are affected, but not the ones which are struggling to keep up. Can I use the IsRunningSlowly flag? Or should I regulate it with the measured framerate?

Advertisement
The cheap and easy thing is to vsync your renderer and not let your simulation run ahead of that.

Otherwise, you can measure how many frames you've simulated in the past second. If it's above some threshold, say, 60, then use sleep or whatnot to slow you down. Figuring out how many milliseconds to sleep based on your target framerate should just be a little algebra.

Note that you will want to slow down a tiny bit across many frames, rather than a lot on one frame. That'll smooth things out and avoid hitches on high-perf machines.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

So it sounds like I should slowly increase number of milliseconds slept, and track the FPS at the same time. And if the FPS goes way down, I immediately stop executing Sleep()?

You can do that, sure, but by the time FPS rate drops, it's too late. You should try and predict how long your next frame will take, based on the past, and "pad" your frame time accordingly.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

OK. If I want to look up algorithms that can do that, what would be the best search terms?

Ideally you would decouple your logic and render loops so that the logic updates occur in discrete timesteps, while the rendering occurs as fast as it can (usually constrained by vsync).

If you're looking for an algorithm to predict framerate, you could maintain a list of the update times for the last x number of updates, and then average those times to predict the future update time. You could even go a step further and track changes to the scene (adding new sprites, deleting old sprites, any other state changes that would change the update time), and then add some adjustment to the predicted time based on those state changes.

However, it doesn't make sense that you would experience notably heavier CPU usage while in a menu gamestate. Obviously I have no idea how you handle your logic updates, but maybe the excessive CPU usage you're seeing in those situations is a sign that you should rewire your update logic calls in those states to only update the portions of the game logic that are relevant to the current state?

I'm not doing unnecessary work in Update(). But I can't control the number of Update or Draw calls the framework makes, only calling Sleep() has an effect.

At the beginning of your update:

while time since last update started < 1/max_framerate then sleep(0) end

At the beginning of your update:

while time since last update started < 1/max_framerate then sleep(0) end

Sleep(0) would probably not work since the program is single threaded?

"If the value of the millisecondsTimeout argument is zero, the thread relinquishes the remainder of its time slice to any thread of equal priority that is ready to run. If there are no other threads of equal priority that are ready to run, execution of the current thread is not suspended."

Generally, there is nothing wrong with a simulation gobbling up 100% CPU as long as there is something to do. The best (both fastest and most energy efficient) way of doing processing is to consume 100% CPU, work off everything that is there to be done, and then sync, doing zero work which puts the CPU into a low-power state (happens very quickly, few hundred cycles, in hardware, on modern processors). Used to be you could just continue sucking up 100% CPU without ever blocking on sync or such, and people would be happy although they couldn't really see the extra frames, but in a time with mobile devices and batteries this is no longer the case (at least not generally). Thus, one will usually by default want to wait on vsync rather than produce as many frames as possible. That still doesn't mean that you shouldn't consume 100% CPU, only just... don't artificially slow down as long as there is something to do. When the game is paused, CPU usage should be zero (or almost zero). There is no work to be done, no updates, so no CPU should be consumed. When you are in the menu ("fullscreen main menu outside game play"), CPU load should naturally drop since there is very little work being done, just responding to some mouse events and drawing a couple of quads. But nothing "special" should be necessary to achieve that. Of course, if you open some kind of config menu (even a fullscreen menu) while the game is running and while the realtime simulation is going on (not paused), the same amount of work is being done as otherwise. It's no surprise that the simulation still consumes CPU, this is a healthy, normal condition. Using sleep is almost always a bad idea. Not only is it unreliable and inaccurate, but it also doesn't do what is intended. You open a big can of worms and add a lot of problems which you really don't want to deal with (over-estimating, over-sleeping, scheduler jitter and other scheduling issues, under Unix there's even under-sleeping, etc). Blocking on vsync works, and it's a proven thing (no pain, still gain!). Blocking on an event/mutex/semaphore/whatever if you have several threads is a proven thing. Sleep is just... trouble ahead.

This topic is closed to new replies.

Advertisement