From a3d894000b7243e4bfd54f99de3bee8154827897 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Mon, 5 Sep 2016 22:02:40 +0200 Subject: Use a monotonic clock instead of a realtime clock Using a realtime clock is a bad idea: it is affected by any kind of time change, which can happen when the administrator modifies the system time, or more simply when a laptop suspends to RAM and then wakes up from sleep. With the current approach of using a realtime clock: - if the system time jumps forward (e.g. when resuming after a suspend-to-RAM), bmon would take 100% CPU and display random graph data extremely fast, until it "catches up" with the new time. - if the system time jumps backwards, bmon would freeze until *time* "catches up" to the point it was before. bmon then (incorrectly) displays a spike in the graph, because lots of packets have been sent/received since the last update. Instead of using gettimeofday(), switch to clock_gettime() with CLOCK_MONOTONIC on systems that support it. OS X does not provide clock_gettime(), so this commit also adds a Mach-specific implementation. This change has been tested on Linux 4.1 with glibc and musl, and on FreeBSD 10.0-RELEASE-p12. --- configure.ac | 5 ++++- include/bmon/defs.h.in | 9 ++++++--- src/utils.c | 22 ++++++++++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 70adab3..f1439e1 100644 --- a/configure.ac +++ b/configure.ac @@ -58,7 +58,7 @@ AC_CHECK_HEADERS(sys/param.h sys/socket.h) AC_CHECK_TYPES(suseconds_t) -AC_CHECK_FUNCS(atexit gettimeofday memset pow socket strcasecmp) +AC_CHECK_FUNCS(atexit clock_gettime memset pow socket strcasecmp) AC_CHECK_FUNCS(strchr strdup strerror strncasecmp strstr strtol) AC_CHECK_FUNCS(uname getdate) @@ -86,6 +86,9 @@ esac AC_CHECK_LIB(m, pow, [], AC_MSG_ERROR([requires libm])) +# Don't fail if not found (for instance, OS X does not have clock_gettime) +AC_CHECK_LIB(rt, clock_gettime, [], []) + BMON_LIB="" ##################################################################### diff --git a/include/bmon/defs.h.in b/include/bmon/defs.h.in index d176c30..92b72eb 100644 --- a/include/bmon/defs.h.in +++ b/include/bmon/defs.h.in @@ -9,6 +9,9 @@ /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* have curses */ #undef HAVE_CURSES @@ -39,15 +42,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `m' library (-lm). */ #undef HAVE_LIBM +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/src/utils.c b/src/utils.c index 248d829..7db96e7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -27,6 +27,11 @@ #include #include +#ifdef __MACH__ +#include +#include +#endif + void *xcalloc(size_t n, size_t s) { void *d = calloc(n, s); @@ -112,12 +117,21 @@ int timestamp_is_negative(timestamp_t *ts) void update_timestamp(timestamp_t *dst) { - struct timeval tv; +#ifdef __MACH__ + clock_serv_t cclock; + mach_timespec_t tp; - gettimeofday(&tv, NULL); + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &tp); + mach_port_deallocate(mach_task_self(), cclock); +#else + struct timespec tp; + + clock_gettime(CLOCK_MONOTONIC, &tp); +#endif - dst->tv_sec = tv.tv_sec; - dst->tv_usec = tv.tv_usec; + dst->tv_sec = tp.tv_sec; + dst->tv_usec = tp.tv_nsec / 1000; } void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2) -- cgit v1.2.3