Oversleeping: errors in delays

QNX SDP8.0Programmer's GuideDeveloper

The tick size becomes important almost every time you ask the kernel to do something related to pausing or delaying your process.

This includes calls to the following functions:

Normally, you use these functions assuming they'll do exactly what you say: Sleep for 8 seconds!, Sleep for 1 minute!, and so on. Unfortunately, you get into problems when you say Sleep for 1 millisecond, ten thousand times!

Delaying for a second: inaccurate code

Does this code work assuming a 1 ms tick?

void one_second_pause() {
  /* Wait 1000 milliseconds. */
  for ( unsigned i=0; i < 1000; i++ ) delay(1);
}

Unfortunately, no, this won't return after one second in QNX OS. It'll likely wait for about two seconds. In fact, when you call any function based on the nanosleep(), poll, or select() functions with an argument of n milliseconds, it actually takes anywhere from n to infinity milliseconds. But more than likely, this example will take about two seconds.

So why exactly does this function take two seconds?

Timer quantization error

What you're seeing is called timer quantization error. One aspect of this error is actually so well understood and accepted that it's even documented in a standard: the POSIX Realtime Extension (1003.1b-1993/1003.1i-1995). This document says that it's alright to delay too much, but it isn't alright to delay too little—the premature firing of a timer is undesirable.

The QNX OS aligns the expiry of timers to a system tick. In the example above, because the call to delay() occurs between two system tick times, the delay() function completes only after the second tick interval following its call. In this case, the program usually ends up calling delay() right after a system tick, and therefore waits almost 2 ms every time.

Most of the extra time for the outer function, one_second_pause(), comes from this 2 ms wait per delay() call. This extra time also depends on the thread being scheduled so it can make the call at each loop iteration; on a busier system, the scheduling delay could also increase the overall delay.

Page updated: