]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: clock: do not mix wall-clock and monotonic time in uptime calculation
authorWilly Tarreau <w@1wt.eu>
Tue, 7 Feb 2023 14:52:14 +0000 (15:52 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 8 Feb 2023 10:06:55 +0000 (11:06 +0100)
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
src/activity.c
src/clock.c
src/haproxy.c
src/stats.c

index 22bb2c9471710a77b7224dfb56cf00176c583faa..a6f7cd2dbf9158cbf4f879ece6a0322144cbd43b 100644 (file)
@@ -26,6 +26,7 @@
 #include <haproxy/api.h>
 
 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 */
index 5ee5fbb10e640041597034d0ee652aa340fdcec5..010fd313ad6bb4a4198457a771cee2fd5c81e859 100644 (file)
@@ -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);
index 3d96c31d092b07c2debf4f05037372f90e2a1a29..75d2293ac95b38b3087f77d194b3dc67433a5fd5 100644 (file)
@@ -27,6 +27,7 @@
 #include <haproxy/tools.h>
 
 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) */
 
index e03b2388e9ff24ed3bef51217470e5d017590eef..f7e0b34ac1d80a217eb1dde008948642c7dc6d08 100644 (file)
@@ -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.
index 960fcbf5f6cc294929801d0487d3bd2ef58ff528..9866a54747d64168a46bc6abb78884bb61732e36 100644 (file)
@@ -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));