summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/clocks/clocks.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:33:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:34:10 +0000
commit83ba6762cc43d9db581b979bb5e3445669e46cc2 (patch)
tree2e69833b43f791ed253a7a20318b767ebe56cdb8 /src/libnetdata/clocks/clocks.c
parentReleasing debian version 1.47.5-1. (diff)
downloadnetdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.tar.xz
netdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.zip
Merging upstream version 2.0.3+dfsg (Closes: #923993, #1042533, #1045145).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libnetdata/clocks/clocks.c')
-rw-r--r--src/libnetdata/clocks/clocks.c123
1 files changed, 83 insertions, 40 deletions
diff --git a/src/libnetdata/clocks/clocks.c b/src/libnetdata/clocks/clocks.c
index 5da450a2d..c65886198 100644
--- a/src/libnetdata/clocks/clocks.c
+++ b/src/libnetdata/clocks/clocks.c
@@ -78,7 +78,9 @@ static usec_t get_clock_resolution(clockid_t clock) {
// perform any initializations required for clocks
-void clocks_init(void) {
+static __attribute__((constructor)) void clocks_init(void) {
+ os_get_system_HZ();
+
// monotonic raw has to be tested before boottime
test_clock_monotonic_raw();
@@ -87,6 +89,18 @@ void clocks_init(void) {
clock_monotonic_resolution = get_clock_resolution(clock_monotonic_to_use);
clock_realtime_resolution = get_clock_resolution(CLOCK_REALTIME);
+
+#if defined(OS_WINDOWS)
+ timeBeginPeriod(1);
+ clock_monotonic_resolution = 1 * USEC_PER_MS;
+ clock_realtime_resolution = 1 * USEC_PER_MS;
+#endif
+}
+
+static __attribute__((destructor)) void clocks_fin(void) {
+#if defined(OS_WINDOWS)
+ timeEndPeriod(1);
+#endif
}
inline time_t now_sec(clockid_t clk_id) {
@@ -246,13 +260,18 @@ void sleep_to_absolute_time(usec_t usec) {
}
#endif
-#define HEARTBEAT_ALIGNMENT_STATISTICS_SIZE 10
-netdata_mutex_t heartbeat_alignment_mutex = NETDATA_MUTEX_INITIALIZER;
+#define HEARTBEAT_MIN_OFFSET_UT (150 * USEC_PER_MS)
+#define HEARTBEAT_RANDOM_OFFSET_UT (350 * USEC_PER_MS)
+
+#define HEARTBEAT_ALIGNMENT_STATISTICS_SIZE 20
+static SPINLOCK heartbeat_alignment_spinlock = NETDATA_SPINLOCK_INITIALIZER;
static size_t heartbeat_alignment_id = 0;
struct heartbeat_thread_statistics {
+ pid_t tid;
size_t sequence;
usec_t dt;
+ usec_t randomness;
};
static struct heartbeat_thread_statistics heartbeat_alignment_values[HEARTBEAT_ALIGNMENT_STATISTICS_SIZE] = { 0 };
@@ -290,19 +309,58 @@ void heartbeat_statistics(usec_t *min_ptr, usec_t *max_ptr, usec_t *average_ptr,
memcpy(old, current, sizeof(struct heartbeat_thread_statistics) * HEARTBEAT_ALIGNMENT_STATISTICS_SIZE);
}
-inline void heartbeat_init(heartbeat_t *hb) {
- hb->realtime = 0ULL;
- 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);
+static XXH64_hash_t heartbeat_hash(usec_t step, size_t statistics_id) {
+ struct {
+ usec_t step;
+ pid_t pid;
+ pid_t tid;
+ usec_t now_ut;
+ size_t statistics_id;
+ char tag[ND_THREAD_TAG_MAX + 1];
+ } key = {
+ .step = step,
+ .pid = getpid(),
+ .tid = os_gettid(),
+ .now_ut = now_realtime_usec(),
+ .statistics_id = statistics_id,
+ };
+ strncpyz(key.tag, nd_thread_tag(), sizeof(key.tag) - 1);
+ return XXH3_64bits(&key, sizeof(key));
+}
+
+static usec_t heartbeat_randomness(XXH64_hash_t hash) {
+ usec_t offset_ut = HEARTBEAT_MIN_OFFSET_UT + (hash % HEARTBEAT_RANDOM_OFFSET_UT);
+
+ // Calculate the scheduler tick interval in microseconds
+ usec_t scheduler_step_ut = USEC_PER_SEC / (usec_t)system_hz;
+ if(scheduler_step_ut > 10 * USEC_PER_MS)
+ scheduler_step_ut = 10 * USEC_PER_MS;
+
+ // if the offset is close to the scheduler tick, move it away from it
+ if(offset_ut % scheduler_step_ut < scheduler_step_ut / 4)
+ offset_ut += scheduler_step_ut / 4;
+
+ return offset_ut;
+}
- netdata_mutex_lock(&heartbeat_alignment_mutex);
+inline void heartbeat_init(heartbeat_t *hb, usec_t step) {
+ if(!step) step = USEC_PER_SEC;
+
+ spinlock_lock(&heartbeat_alignment_spinlock);
hb->statistics_id = heartbeat_alignment_id;
heartbeat_alignment_id++;
- netdata_mutex_unlock(&heartbeat_alignment_mutex);
+ spinlock_unlock(&heartbeat_alignment_spinlock);
+
+ hb->step = step;
+ hb->realtime = 0ULL;
+ hb->hash = heartbeat_hash(hb->step, hb->statistics_id);
+ hb->randomness = heartbeat_randomness(hb->hash);
if(hb->statistics_id < HEARTBEAT_ALIGNMENT_STATISTICS_SIZE) {
heartbeat_alignment_values[hb->statistics_id].dt = 0;
heartbeat_alignment_values[hb->statistics_id].sequence = 0;
+ heartbeat_alignment_values[hb->statistics_id].randomness = hb->randomness;
+ heartbeat_alignment_values[hb->statistics_id].tid = os_gettid();
}
}
@@ -310,17 +368,8 @@ inline void heartbeat_init(heartbeat_t *hb) {
// it waits using the monotonic clock
// it returns the dt using the realtime clock
-usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) {
- if(unlikely(hb->randomness > tick / 2)) {
- // TODO: The heartbeat tick should be specified at the heartbeat_init() function
- usec_t tmp = (now_realtime_usec() * clock_realtime_resolution) % (tick / 2);
-
- 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;
- }
+usec_t heartbeat_next(heartbeat_t *hb) {
+ usec_t tick = hb->step;
usec_t dt;
usec_t now = now_realtime_usec();
@@ -331,10 +380,13 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) {
next = next - (next % clock_realtime_resolution) + clock_realtime_resolution;
// sleep_usec() has a loop to guarantee we will sleep for at least the requested time.
- // According the specs, when we sleep for a relative time, clock adjustments should not affect the duration
- // we sleep.
+ // According to the specs, when we sleep for a relative time, clock adjustments should
+ // not affect the duration we sleep.
sleep_usec_with_now(next - now, now);
+ spinlock_lock(&heartbeat_alignment_spinlock);
now = now_realtime_usec();
+ spinlock_unlock(&heartbeat_alignment_spinlock);
+
dt = now - hb->realtime;
if(hb->statistics_id < HEARTBEAT_ALIGNMENT_STATISTICS_SIZE) {
@@ -368,22 +420,15 @@ usec_t heartbeat_next(heartbeat_t *hb, usec_t tick) {
return dt;
}
-#ifdef OS_WINDOWS
-
-#include "windows.h"
-
-void sleep_usec_with_now(usec_t usec, usec_t started_ut)
-{
+#if defined(OS_WINDOWS)
+void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
if (!started_ut)
started_ut = now_realtime_usec();
usec_t end_ut = started_ut + usec;
usec_t remaining_ut = usec;
- timeBeginPeriod(1);
-
- while (remaining_ut >= 1000)
- {
+ while (remaining_ut >= clock_realtime_resolution) {
DWORD sleep_ms = (DWORD) (remaining_ut / USEC_PER_MS);
Sleep(sleep_ms);
@@ -393,8 +438,6 @@ void sleep_usec_with_now(usec_t usec, usec_t started_ut)
remaining_ut = end_ut - now_ut;
}
-
- timeEndPeriod(1);
}
#else
void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
@@ -406,7 +449,7 @@ void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
};
// make sure errno is not EINTR
- errno = 0;
+ errno_clear();
if(!started_ut)
started_ut = now_realtime_usec();
@@ -419,7 +462,7 @@ void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
rem = (struct timespec){ 0, 0 };
// break an infinite loop
- errno = 0;
+ errno_clear();
usec_t now_ut = now_realtime_usec();
if(now_ut >= end_ut)
@@ -429,8 +472,8 @@ void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
usec_t check_ut = now_ut - started_ut;
if(remaining_ut > check_ut) {
req = (struct timespec){
- .tv_sec = (time_t) ( check_ut / USEC_PER_SEC),
- .tv_nsec = (suseconds_t) ((check_ut % USEC_PER_SEC) * NSEC_PER_USEC)
+ .tv_sec = (time_t) ( check_ut / USEC_PER_SEC),
+ .tv_nsec = (suseconds_t) ((check_ut % USEC_PER_SEC) * NSEC_PER_USEC)
};
}
}
@@ -452,7 +495,7 @@ static inline collected_number uptime_from_boottime(void) {
}
static procfile *read_proc_uptime_ff = NULL;
-static inline collected_number read_proc_uptime(char *filename) {
+static inline collected_number read_proc_uptime(const char *filename) {
if(unlikely(!read_proc_uptime_ff)) {
read_proc_uptime_ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
if(unlikely(!read_proc_uptime_ff)) return 0;
@@ -473,7 +516,7 @@ static inline collected_number read_proc_uptime(char *filename) {
return (collected_number)(strtondd(procfile_lineword(read_proc_uptime_ff, 0, 0), NULL) * 1000.0);
}
-inline collected_number uptime_msec(char *filename){
+inline collected_number uptime_msec(const char *filename){
static int use_boottime = -1;
if(unlikely(use_boottime == -1)) {