Fixed timestep on the server without hogging CPU?

It sounds backwards, but it's the situation I'm currently trying to solve on my dedicated server.

Everything I've read about fixed timestep assumed it was on a client, where you're already running in a loop as fast as you can to render the game, and you are just inserting the fixed timestep updates within that.

Problem is, on the server, that's the only thing being done in the loop, aside from checking for network activity. So my server ends up using 100% CPU, looping needlessly while waiting for the next fixed timestep.

The only way I know to fix this is by adding a sleep to the loop, but I know how inaccurate that delay can be, which would throw off the accuracy of the timesteps.

Is there a better way to keep it from burning CPU? Or is sleep what most dedicated servers are doing anyway?

• What problem are you trying to solve? Why is the server looping faster then it needs to a problem? – Polygnome Aug 5 '18 at 11:11
• @Polygnome it could be that the same server hardware is running multiple jobs, so tying up the CPU in a spin-wait on this one idle wait task would reduce the total productivity you could get from the hardware. If the server is running via a cloud service, then this extra spinning might increase the cost of running the server. – DMGregory Aug 5 '18 at 14:04
• @DMGregory Exactly that. I've run dedicated servers from other games, sometimes on the same box as the client, and they never come close to hogging the CPU. I'm curious what they're doing to prevent that, while still remaining responsive to gamestate updates. – Nairou Aug 5 '18 at 14:12
• Are you sure the inaccuracy of sleep (or multimedia timers, where available) is a deal-breaker here? Most estimates I've seen for variance in sleep timing still peg it at a fraction of a network ping. So the server running its update a few ms early/late according to realtime is not functionally different than your input packet reaching the server a few ms early/late due to the vagaries of internet traffic, and a client couldn't tell which it was. Since you're on a fixed timestep, your timestamps can be sequential integers so they're drift-free, and the error doesn't accumulate/snowball. – DMGregory Aug 5 '18 at 14:29

1 Answer

Sleeping is a valid solution and it's easy to implement. Pick a sleep duration that will use less CPU but still give you acceptable simulation accuracy.

An alternative solution is to use an event loop on your server. An event loop would only wake up the main thread when it's needed, for example at a regular interval, or when a network message arrives.

There are many event loop libraries available in various programming languages. libuv and Boost.Asio are popular alternatives if you use C/C++. If you use one of these libraries, you probably want to have a look at their timer implementations. A timer can run a callback at a regular interval, perfect for your fixed steps. The code below shows you how to create and run a timer using libuv (read more at http://docs.libuv.org/en/v1.x/guide/utilities.html#timers):

#include <stdio.h>
#include <uv.h>

uv_loop_t *loop;
uv_timer_t timer_req;

void callback(uv_timer_t *handle) {
fprintf(stderr, "Running callback!\n");
}

int main() {
loop = uv_default_loop();

uv_timer_init(loop, &timer_req);

// Start the timer after 0ms and run callback at a 30ms interval
uv_timer_start(&timer_req, callback, 0, 30);

return uv_run(loop, UV_RUN_DEFAULT);
}