diff options
Diffstat (limited to 'libnetdata/clocks')
-rw-r--r-- | libnetdata/clocks/clocks.c | 67 | ||||
-rw-r--r-- | libnetdata/clocks/clocks.h | 1 |
2 files changed, 47 insertions, 21 deletions
diff --git a/libnetdata/clocks/clocks.c b/libnetdata/clocks/clocks.c index 489e96855..adbad045f 100644 --- a/libnetdata/clocks/clocks.c +++ b/libnetdata/clocks/clocks.c @@ -7,8 +7,14 @@ static clockid_t clock_boottime_to_use = CLOCK_MONOTONIC; static clockid_t clock_monotonic_to_use = CLOCK_MONOTONIC; -usec_t clock_monotonic_resolution = 1000; -usec_t clock_realtime_resolution = 1000; +// the default clock resolution is 1ms +#define DEFAULT_CLOCK_RESOLUTION_UT ((usec_t)0 * USEC_PER_SEC + (usec_t)1 * USEC_PER_MS) + +// the max clock resolution is 10ms +#define MAX_CLOCK_RESOLUTION_UT ((usec_t)0 * USEC_PER_SEC + (usec_t)10 * USEC_PER_MS) + +usec_t clock_monotonic_resolution = DEFAULT_CLOCK_RESOLUTION_UT; +usec_t clock_realtime_resolution = DEFAULT_CLOCK_RESOLUTION_UT; #ifndef HAVE_CLOCK_GETTIME inline int clock_gettime(clockid_t clk_id __maybe_unused, struct timespec *ts) { @@ -50,9 +56,24 @@ static void test_clock_boottime(void) { } static usec_t get_clock_resolution(clockid_t clock) { - struct timespec ts; - clock_getres(clock, &ts); - return ts.tv_sec * USEC_PER_SEC + ts.tv_nsec * NSEC_PER_USEC; + struct timespec ts = { 0 }; + + if(clock_getres(clock, &ts) == 0) { + usec_t ret = (usec_t)ts.tv_sec * USEC_PER_SEC + (usec_t)ts.tv_nsec / NSEC_PER_USEC; + if(!ret && ts.tv_nsec > 0 && ts.tv_nsec < NSEC_PER_USEC) + return (usec_t)1; + + else if(ret > MAX_CLOCK_RESOLUTION_UT) { + nd_log(NDLS_DAEMON, NDLP_ERR, "clock_getres(%d) returned %"PRIu64" usec is out of range, using defaults for clock resolution.", (int)clock, ret); + return DEFAULT_CLOCK_RESOLUTION_UT; + } + + return ret; + } + else { + nd_log(NDLS_DAEMON, NDLP_ERR, "clock_getres(%d) failed, using defaults for clock resolution.", (int)clock); + return DEFAULT_CLOCK_RESOLUTION_UT; + } } // perform any initializations required for clocks @@ -66,14 +87,6 @@ void clocks_init(void) { clock_monotonic_resolution = get_clock_resolution(clock_monotonic_to_use); clock_realtime_resolution = get_clock_resolution(CLOCK_REALTIME); - - // if for any reason these are zero, netdata will crash - // since we use them as modulo to calculations - if(!clock_realtime_resolution) - clock_realtime_resolution = 1000; - - if(!clock_monotonic_resolution) - clock_monotonic_resolution = 1000; } inline time_t now_sec(clockid_t clk_id) { @@ -91,7 +104,7 @@ inline usec_t now_usec(clockid_t clk_id) { netdata_log_error("clock_gettime(%d, ×pec) failed.", clk_id); return 0; } - return (usec_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC; + return (usec_t)ts.tv_sec * USEC_PER_SEC + (usec_t)(ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC; } inline int now_timeval(clockid_t clk_id, struct timeval *tv) { @@ -113,6 +126,10 @@ inline time_t now_realtime_sec(void) { return now_sec(CLOCK_REALTIME); } +inline msec_t now_realtime_msec(void) { + return now_usec(CLOCK_REALTIME) / USEC_PER_MS; +} + inline usec_t now_realtime_usec(void) { return now_usec(CLOCK_REALTIME); } @@ -275,7 +292,7 @@ void heartbeat_statistics(usec_t *min_ptr, usec_t *max_ptr, usec_t *average_ptr, inline void heartbeat_init(heartbeat_t *hb) { hb->realtime = 0ULL; - hb->randomness = 250 * USEC_PER_MS + ((now_realtime_usec() * clock_realtime_resolution) % (250 * USEC_PER_MS)); + hb->randomness = (usec_t)250 * USEC_PER_MS + ((usec_t)(now_realtime_usec() * clock_realtime_resolution) % (250 * USEC_PER_MS)); hb->randomness -= (hb->randomness % clock_realtime_resolution); netdata_mutex_lock(&heartbeat_alignment_mutex); @@ -298,8 +315,10 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) { // TODO: The heartbeat tick should be specified at the heartbeat_init() function usec_t tmp = (now_realtime_usec() * clock_realtime_resolution) % (tick / 2); - error_limit_static_global_var(erl, 10, 0); - error_limit(&erl, "heartbeat randomness of %"PRIu64" is too big for a tick of %"PRIu64" - setting it to %"PRIu64"", hb->randomness, tick, tmp); + nd_log_limit_static_global_var(erl, 10, 0); + nd_log_limit(&erl, NDLS_DAEMON, NDLP_NOTICE, + "heartbeat randomness of %"PRIu64" is too big for a tick of %"PRIu64" - setting it to %"PRIu64"", + hb->randomness, tick, tmp); hb->randomness = tmp; } @@ -325,13 +344,19 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) { if(unlikely(now < next)) { errno = 0; - error_limit_static_global_var(erl, 10, 0); - error_limit(&erl, "heartbeat clock: woke up %"PRIu64" microseconds earlier than expected (can be due to the CLOCK_REALTIME set to the past).", next - now); + nd_log_limit_static_global_var(erl, 10, 0); + nd_log_limit(&erl, NDLS_DAEMON, NDLP_NOTICE, + "heartbeat clock: woke up %"PRIu64" microseconds earlier than expected " + "(can be due to the CLOCK_REALTIME set to the past).", + next - now); } else if(unlikely(now - next > tick / 2)) { errno = 0; - error_limit_static_global_var(erl, 10, 0); - error_limit(&erl, "heartbeat clock: woke up %"PRIu64" microseconds later than expected (can be due to system load or the CLOCK_REALTIME set to the future).", now - next); + nd_log_limit_static_global_var(erl, 10, 0); + nd_log_limit(&erl, NDLS_DAEMON, NDLP_NOTICE, + "heartbeat clock: woke up %"PRIu64" microseconds later than expected " + "(can be due to system load or the CLOCK_REALTIME set to the future).", + now - next); } if(unlikely(!hb->realtime)) { diff --git a/libnetdata/clocks/clocks.h b/libnetdata/clocks/clocks.h index 5b88a4579..2beb14ed9 100644 --- a/libnetdata/clocks/clocks.h +++ b/libnetdata/clocks/clocks.h @@ -117,6 +117,7 @@ usec_t now_realtime_usec(void); int now_monotonic_timeval(struct timeval *tv); time_t now_monotonic_sec(void); +msec_t now_realtime_msec(void); usec_t now_monotonic_usec(void); int now_monotonic_high_precision_timeval(struct timeval *tv); time_t now_monotonic_high_precision_sec(void); |