Search code examples
clinuxsystem-clock

How does CLOCK_MONOTONIC handle NTP changes to the system clock?


Savvy engineers use clock_gettime( CLOCK_MONOTONIC, &my_timspec_struct ) to get a continuously increasing epoch-style clock that is "unaffected" by changes to the system clock. (Where the epoch-start is not defined).

However, CLOCK_MONOTONIC is effected by NTP daemon time-changes known as clock "slewing".

By the definition of CLOCK_MONOTONIC, we know that it will never jump backwards. But how does it it mitigate changes by NTP? If the system-clock is suddenly set 5 hours in the past by NTP, does the monotonic clock run a bit slower until it catches up? Maybe it just stops "ticking" until the difference evens-out?

What really does happen? If it's system dependent, what happens on Linux?

I have some timing related code that's failing where the hardware clocks are very flaky. They're being re-adjusted to a GPS source every few minutes. And while this reads like it shouldn't effect CLOCK_MONOTONIC, sometimes (1 in 20) timing related code is just not working. I can't just change everything to CLOCK_MONOTONIC_RAW, because libraries (e.g.: Qt) still use non-raw (Ref: Qt 5.15 source).


Solution

  • What really does happen? If it's system dependent, what happens on Linux?

    It is system-dependent whether there even is a CLOCK_MONOTONIC. The only clock that POSIX requires implementations to provide is CLOCK_REALTIME. So, what happens on Linux?

    The docs have this to say about CLOCK_MONOTONIC:

    Clock that cannot be set and represents monotonic time since some unspecified starting point. This clock is not affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.

    The docs for adjtime() add:

    If the adjustment in delta is positive, then the system clock is speeded up by some small percentage (i.e., by adding a small amount of time to the clock value in each second) until the adjustment has been completed. If the adjustment in delta is negative, then the clock is slowed down in a similar fashion.

    From that we can conclude that CLOCK_MONOTONIC moves at the same speed as the system clock, which is why it is affected when NTP slews the clock or adjtime() is used, but that it is not updated when the system clock is set. It just keeps counting up, monotonically.