Suppose we want to stress-test a server by hitting it with a fixed number of requests per second. Or maybe we want to write a game loop that runs at a fixed number of frames per second. In both cases, we want to run some code at a fixed frequency \(\nu\). More precisely, we want a loop that calls some function, sleeps for a bit, then restarts, and overall, the function is called \(\nu\) times per second.
First, we need a way to time code. The function gettimeofday(2) gives us a timeval, which represents the current time in seconds and microseconds. By bracketing our code in a couple of these, we can find exactly how many microseconds it took to run.
Given that we know the frequency \(\nu\), we also know that our code should take \(1/\nu\) seconds to run. We time our code, and if it runs too quickly, we insert an artificial pause. In other words, if our code runs in \(t\) seconds, and \(t < 1/\nu\), we should pause for \(1/\nu - t\) seconds.
We can use usleep(3) to pause for a given number of microseconds. In our case, we want to usleep for \((1/\nu - t) * 1\_000\_000\) microseconds. Note that usleep is unavailable on some older Unix systems; pselect(2) can be used instead.
Putting it all together, we get the following code:
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
/* How many times per second do we want the code to run? */
const int frequency = 2;
/* Pretend to do something useful. */
void do_work() {
volatile int i;
for (i = 0; i < 10000000; ++i)
;
}
int main(int argc, char *argv[]) {
/* How long should each work unit take? */
long slice = (long)(1.0 / frequency * 1000000);
struct timeval beginning;
gettimeofday(&beginning, NULL);
struct timeval last_tick = beginning;
long total = 0;
int tick;
for (tick = 1; 1; ++tick) {
do_work();
struct timeval now;
gettimeofday(&now, NULL);
/* How much time has passed since the last tick? */
long usec_elapsed = (now.tv_sec - last_tick.tv_sec) * 1000000
+ (now.tv_usec - last_tick.tv_usec);
last_tick = now;
/* How time did we spend working this tick? */
long usec_work = (now.tv_sec - beginning.tv_sec) * 1000000
+ (now.tv_usec - beginning.tv_usec);
total += usec_elapsed;
printf("Worked for %ldus. Average time per tick: %ldus (%ldus since last).\n",
usec_work, total / tick, usec_elapsed);
/* Pause if appropriate. */
long usec_tosleep = slice - usec_work;
if (usec_tosleep > 0) {
printf("Sleeping for %ldus.\n", usec_tosleep);
usleep(usec_tosleep);
}
/* Prepare for the next tick. */
gettimeofday(&beginning, NULL);
}
return 0;
}
The code itself is unsurprising, but it’s easy to get wrong: if, when calculating the length of the pause, you use the time for the entire loop, usec_elapsed, instead of the time for the work part of it, usec_work, you end up waiting alternatively for \(1/\nu\) and \(0\).