From 6093ba47c0b940df7ba60943dfb0ae88de47c323 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 7 Feb 2023 15:52:14 +0100 Subject: [PATCH] BUG/MINOR: clock: do not mix wall-clock and monotonic time in uptime calculation We've had a start date even before the internal monotonic clock existed, but once the monotonic clock was added, the start date was not updated to distinguish the wall clock time units and the internal monotonic time units. The distinction is important because both clocks do not necessarily progress at the same speed. The very rare occurrences of the wall-clock date are essentially for human consumption and communication with third parties (e.g. report the start date in "show info" for monitoring purposes). However currently this one is also used to measure the distance to "now" as being the process' uptime. This is actually not correct. It only works because for now the two dates are initialized at the exact same instant at boot but could still be wrong if the system's date shows a big jump backwards during startup for example. In addition the current situation prevents us from enforcing an abritrary offset at boot to reveal some heisenbugs. This patch adds a new "start_time" at boot that is set from "now" and is used in uptime calculations. "start_date" instead is now set from "date" and will always reflect the system date for human consumption (e.g. in "show info"). This way we're now sure that any drift of the internal clock relative to the system date will not impact the reported uptime. This could possibly be backported though it's unlikely that anyone has ever noticed the problem. --- include/haproxy/clock.h | 1 + src/activity.c | 2 +- src/clock.c | 1 + src/haproxy.c | 3 ++- src/stats.c | 4 ++-- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/haproxy/clock.h b/include/haproxy/clock.h index 22bb2c947..a6f7cd2db 100644 --- a/include/haproxy/clock.h +++ b/include/haproxy/clock.h @@ -26,6 +26,7 @@ #include extern struct timeval start_date; /* the process's start date in wall-clock time */ +extern struct timeval start_time; /* the process's start date in internal monotonic time */ extern volatile ullong global_now; /* common monotonic date between all threads (32:32) */ extern THREAD_LOCAL struct timeval now; /* internal monotonic date derived from real clock */ diff --git a/src/activity.c b/src/activity.c index 5ee5fbb10..010fd313a 100644 --- a/src/activity.c +++ b/src/activity.c @@ -1083,7 +1083,7 @@ static int cli_io_handler_show_activity(struct appctx *appctx) } while (0) /* retrieve uptime */ - tv_remain(&start_date, &now, &up); + tv_remain(&start_time, &now, &up); chunk_appendf(&trash, "thread_id: %u (%u..%u)\n", tid + 1, 1, global.nbthread); chunk_appendf(&trash, "date_now: %lu.%06lu\n", (ulong)now.tv_sec, (ulong)now.tv_usec); diff --git a/src/clock.c b/src/clock.c index 3d96c31d0..75d2293ac 100644 --- a/src/clock.c +++ b/src/clock.c @@ -27,6 +27,7 @@ #include struct timeval start_date; /* the process's start date in wall-clock time */ +struct timeval start_time; /* the process's start date in internal monotonic time */ volatile ullong global_now; /* common monotonic date between all threads (32:32) */ volatile uint global_now_ms; /* common monotonic date in milliseconds (may wrap) */ diff --git a/src/haproxy.c b/src/haproxy.c index e03b2388e..f7e0b34ac 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1504,7 +1504,8 @@ static void init_early(int argc, char **argv) /* initialize date, time, and pid */ tzset(); clock_init_process_date(); - start_date = now; + start_date = date; + start_time = now; pid = getpid(); /* Set local host name and adjust some environment variables. diff --git a/src/stats.c b/src/stats.c index 960fcbf5f..9866a5474 100644 --- a/src/stats.c +++ b/src/stats.c @@ -4613,7 +4613,7 @@ int stats_fill_info(struct field *info, int len, uint flags) } glob_out_b32 *= 32; // values are 32-byte units - tv_remain(&start_date, &now, &up); + tv_remain(&start_time, &now, &up); if (len < INF_TOTAL_FIELDS) return 0; @@ -4635,7 +4635,7 @@ int stats_fill_info(struct field *info, int len, uint flags) chunk_appendf(out, "%ud %uh%02um%02us", (uint)up.tv_sec / 86400, ((uint)up.tv_sec % 86400) / 3600, ((uint)up.tv_sec % 3600) / 60, ((uint)up.tv_sec % 60)); info[INF_UPTIME_SEC] = (flags & STAT_USE_FLOAT) ? mkf_flt(FN_DURATION, up.tv_sec + up.tv_usec / 1000000.0) : mkf_u32(FN_DURATION, up.tv_sec); - info[INF_START_TIME_SEC] = (flags & STAT_USE_FLOAT) ? mkf_flt(FN_DURATION, start_date.tv_sec + start_date.tv_usec / 1000000.0) : mkf_u32(FN_DURATION, start_date.tv_sec); + info[INF_START_TIME_SEC] = (flags & STAT_USE_FLOAT) ? mkf_flt(FN_DURATION, start_time.tv_sec + start_time.tv_usec / 1000000.0) : mkf_u32(FN_DURATION, start_time.tv_sec); info[INF_MEMMAX_MB] = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_memmax); info[INF_MEMMAX_BYTES] = mkf_u32(FO_CONFIG|FN_LIMIT, global.rlimit_memmax * 1048576L); info[INF_POOL_ALLOC_MB] = mkf_u32(0, (unsigned)(pool_total_allocated() / 1048576L));