summaryrefslogtreecommitdiffstats
path: root/libnetdata/clocks
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/clocks')
-rw-r--r--libnetdata/clocks/clocks.c67
-rw-r--r--libnetdata/clocks/clocks.h1
2 files changed, 47 insertions, 21 deletions
diff --git a/libnetdata/clocks/clocks.c b/libnetdata/clocks/clocks.c
index 489e9685..adbad045 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, &timespec) 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 5b88a457..2beb14ed 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);