Linux clock_gettime(CLOCK_MONOTONIC) strange non-monotonic behavior
man clock_gettime
says:
CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments.
Since CLOCK_MONOTONIC_RAW
is not subject of NTP adjustments, I guess CLOCK_MONOTONIC
could be.
We had similar problems with Redhat Enterprise 5.0 with 2.6.18 kernel and some specific Itanium processor. We couldn't reproduce it with other processor on the same OS. It was fixed in RHEL 5.3 with slightly newer kernel and some Redhat patches.
In what cases CLOCK_MONOTONIC might not be available
Is it reasonable to assume that CLOCK_MONOTONIC clock is available on all modern Linux servers?
Yes. It is reasonable to assume that.
From the wording of the gettime manual entry, we can infer that really old versions of glibc do not support CLOCK_MONOTONIC
. (I am still trying to figure out how old ... but probably when glibc claimed POSIX 1003.1 compliance.)
CLOCK_MONOTONIC
was specified (at least) in IEEE Std 1003.1, 2004 Edition, though it remains possible for a compliant libc implementation to not support CLOCK_MONOTONIC
.
The Linux kernel source code has had support for a CLOCK_MONOTONIC
clock at least since Linux 3.0 (2011).
From other sources, it also depends on how your system's glibc was built. (When built with "emulated timers", CLOCK_MONOTONIC
is not supported.)
Here are some cases where it is not supported:
There can be problems with some old CPU chips; e.g. https://bugzilla.redhat.com/show_bug.cgi?id=1499480
It is not supported for some (all?) versions of Cygwin.
It is not supported for some (all?) versions of uCLibc on ARM.
It is also possible for CLOCK_MONOTONIC
to be supported but buggy:
- Linux clock_gettime(CLOCK_MONOTONIC) strange non-monotonic behavior
clock_gettime() still not monotonic - alternatives?
This has nothing to do with the mythology of clock_gettime
's monotonic clock not actually being monotonic (which probably has a basis in reality, but which was never well documented and probably fixed a long time ago). It's just a bug in your program. tv_nsec
is the nanoseconds portion of a time value that's stored as two fields:
tv_sec
- whole secondstv_nsec
- nanoseconds in the range 0 to 999999999
Of course tv_nsec
is going to jump backwards from 999999999 to 0 when tv_sec
increments. To compute differences of timespec
structs, you need to take 1000000000 times the difference in seconds and add that to the difference in nanoseconds. Of course this could quickly overflow if you don't convert to a 64-bit type first.
What is the difference between CLOCK_MONOTONIC & CLOCK_MONOTONIC_RAW?
CLOCK_MONOTONIC
never experiences discontinuities due to NTP time adjustments, but it does change in frequency as NTP learns what error exists between the local oscillator and the upstream servers.
CLOCK_MONOTONIC_RAW
is simply the local oscillator, not disciplined by NTP. This could be very useful if you want to implement some other time synchronization algorithm against a clock which is not fighting you due to NTP. While ntpd (the reference implementation of NTP protocol and the most widespread NTP daemon) is reputed to be "gentle" with time adjustments, it's more accurate to say it's gentle with the absolute time. It's willing to slew the clock by 500ppm which is pretty dramatic if you're in a position to measure your clock frequency against some other standard.
The utility of CLOCK_MONOTONIC_RAW
is going to be limited until facilities like pthread_timedwait_monotonic
offer an option to use that timebase.
clock_gettime returns some extrange values
The fluctuation is caused by the OS scheduler. It pauses your process and gives a chance to an other process to run.
Can you report back results with CLOCK_PROCESS_CPUTIME_ID
?
Is CLOCK_MONOTONIC process (or thread) specific?
The answer Maxim and comments to that answered the second part of your question, I believe. To expand on the answer for the first part, POSIX 2008 states
If the Monotonic Clock option is supported, all implementations shall support a clock_id of CLOCK_MONOTONIC defined in <time.h>. This clock represents the monotonic clock for the system. For this clock, the value returned by clock_gettime() represents the amount of time (in seconds and nanoseconds) since an unspecified point in the past (for example, system start-up time, or the Epoch). This point does not change after system start-up time.
In particular, note "the monotonic clock for the system". That is, per-system and not per-process, it keeps ticking even though your process is not running. Also, "This point does not change after system start-up time.", which again implies that it keeps ticking regardless of whether a particular process is running or sleeping.
So, either you have found a bug in the Linux implementation, or more likely, in your test program.
Measuring Elapsed Time Using clock_gettime(CLOCK_MONOTONIC)
Write a helper function that calculates the difference between two timespecs:
int64_t difftimespec_ns(const struct timespec after, const struct timespec before)
{
return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000000
+ ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec);
}
If you want it in microseconds, just divide it by 1000, or use:
int64_t difftimespec_us(const struct timespec after, const struct timespec before)
{
return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000
+ ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec) / 1000;
}
Remember to include <inttypes.h>, so that you can use conversion "%" PRIi64
to print integers of int64_t
type:
printf("%09" PRIi64 " | 5\n", difftimespec_ns(after, before));
How do I get monotonic time durations in python?
That function is simple enough that you can use ctypes to access it:
#!/usr/bin/env python
__all__ = ["monotonic_time"]
import ctypes, os
CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>
class timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
def monotonic_time():
t = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_))
return t.tv_sec + t.tv_nsec * 1e-9
if __name__ == "__main__":
print monotonic_time()
Related Topics
How to Get Unique Values from an Array in Bash
Use of Floating Point in the Linux Kernel
How to View the List of Functions a Linux Shared Library Is Exporting
How to Setup Public-Key Authentication
Which Linux Ipc Technique to Use
What Are the Return Values of System Calls in Assembly
Return Value of Sed For No Match
Forward Host Port to Docker Container
How to Upgrade Glibc from Version 2.12 to 2.14 on Centos
Bluetooth Low Energy: Listening For Notifications/Indications in Linux
Why Data and Stack Segments Are Executable
How to Create Docker Overlay Network Between Multi Hosts
How to Set the Gopath Environment Variable on Ubuntu? What File Must I Edit
How to Replace a String in Multiple Files in Linux Command Line
Python Code to Check If Service Is Running or Not.
Mount Smb/Cifs Share Within a Docker Container
Glibc Scanf Segmentation Faults When Called from a Function That Doesn't Align Rsp