Timing jitter

Updated: April 19, 2023

There's one more thing you have to worry about. Let's say the timing resolution is 10 ms and you want a 20 ms timeout.

Are you always going to get exactly 20 milliseconds worth of delay from the time that you issue the delay() call to the time that the function call returns?

Absolutely not.

There are two good reasons why. The first is fairly simple: when you block, you're taken off the running queue. This means that another thread at your priority may now be using the CPU. When your 20 milliseconds have expired, you'll be placed at the end of the READY queue for that priority so you'll be at the mercy of whatever thread happens to be running. This also applies to interrupt handlers running or higher-priority threads running—just because you are READY doesn't mean that you're consuming the CPU.

The second reason is a bit more subtle. The following diagram will help explain why:

Figure 1. Clock jitter.

The problem is that your request is asynchronous to the clock source. You have no way to synchronize the hardware clock with your request. Therefore, you'll get from just over 20 milliseconds to just under 30 milliseconds worth of delay, depending on where in the hardware's clock period you started your request.

Note: This is a key point. Clock jitter is a sad fact of life. The way to get around it is to increase the system's timing resolution so your timing is within tolerance. (We'll see how to do this in the “Getting and setting the realtime clock” section, below.) Keep in mind that jitter takes place only on the first tick—a 100-second delay with a 10-millisecond clock will delay for greater than 100 seconds and less than 100.01 seconds.