From: Willy Tarreau Date: Sun, 8 Sep 2024 18:54:36 +0000 (+0000) Subject: MEDIUM: clock: use the monotonic clock for idle time calculation X-Git-Tag: v3.1-dev8~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=24496803d16e0397893602b8df8d2c57b3c72087;p=thirdparty%2Fhaproxy.git MEDIUM: clock: use the monotonic clock for idle time calculation By just keeping a copy of the last known value before entering polling, we can apply the same algorithm as we're currently using, except that it's now applied to the monotonic clock instead of the wall clock, when it's detected that it's ticking. This improves idle time calculation accuracy by making it independent on the wall clock. --- diff --git a/src/clock.c b/src/clock.c index 5528ec7def..ab266632d9 100644 --- a/src/clock.c +++ b/src/clock.c @@ -39,6 +39,7 @@ THREAD_LOCAL ullong now_ns; /* internal monotonic date der THREAD_LOCAL uint now_ms; /* internal monotonic date in milliseconds (may wrap) */ THREAD_LOCAL struct timeval date; /* the real current date (wall-clock time) */ +static THREAD_LOCAL ullong before_poll_mono_ns; /* system wide monotonic time when entering poll last */ static THREAD_LOCAL struct timeval before_poll; /* system date before calling poll() */ static THREAD_LOCAL struct timeval after_poll; /* system date after leaving poll() */ static THREAD_LOCAL unsigned int samp_time; /* total elapsed time over current sample */ @@ -310,7 +311,8 @@ void clock_update_global_date() void clock_init_process_date(void) { now_offset = 0; - th_ctx->prev_mono_time = th_ctx->curr_mono_time = now_mono_time(); // 0 if not supported + before_poll_mono_ns = now_mono_time(); // 0 if not supported + th_ctx->prev_mono_time = th_ctx->curr_mono_time = before_poll_mono_ns; gettimeofday(&date, NULL); after_poll = before_poll = date; global_now_ns = th_ctx->curr_mono_time; @@ -356,6 +358,7 @@ void clock_init_thread_date(void) th_ctx->prev_cpu_time = now_cpu_time(); th_ctx->prev_mono_time = now_mono_time(); th_ctx->curr_mono_time = th_ctx->prev_mono_time; + before_poll_mono_ns = th_ctx->curr_mono_time; clock_update_date(0, 1); } @@ -390,15 +393,23 @@ static inline void clock_measure_idle(void) */ int delta; - if ((delta = date.tv_sec - before_poll.tv_sec)) - delta *= 1000000; - idle_time += delta + (date.tv_usec - before_poll.tv_usec); + if (before_poll_mono_ns) { + /* CLOCK_MONOTONIC in use, use it and convert it to microseconds */ - if ((delta = date.tv_sec - after_poll.tv_sec)) - delta *= 1000000; - samp_time += delta + (date.tv_usec - after_poll.tv_usec); + idle_time += (th_ctx->curr_mono_time - before_poll_mono_ns) / 1000ull; + samp_time += (th_ctx->curr_mono_time - th_ctx->prev_mono_time) / 1000ull; + } else { + /* CLOCK_MONOTONIC not used */ + if ((delta = date.tv_sec - before_poll.tv_sec)) + delta *= 1000000; + idle_time += delta + (date.tv_usec - before_poll.tv_usec); + + if ((delta = date.tv_sec - after_poll.tv_sec)) + delta *= 1000000; + samp_time += delta + (date.tv_usec - after_poll.tv_usec); - after_poll.tv_sec = date.tv_sec; after_poll.tv_usec = date.tv_usec; + after_poll.tv_sec = date.tv_sec; after_poll.tv_usec = date.tv_usec; + } if (samp_time < 500000) return; @@ -433,6 +444,12 @@ void clock_entering_poll(void) gettimeofday(&before_poll, NULL); + new_cpu_time = now_cpu_time(); + new_mono_time = now_mono_time(); + + /* the the time when we entere poll */ + before_poll_mono_ns = new_mono_time; + /* The time might have jumped either backwards or forwards during tasks * processing. It's easy to detect a backwards jump, but a forward jump * needs a marging. Here the upper limit of 2 seconds corresponds to a @@ -449,10 +466,10 @@ void clock_entering_poll(void) else if (unlikely(__tv_ms_elapsed(&after_poll, &before_poll) >= 2000)) tv_ms_add(&before_poll, &after_poll, 2000); - run_time = (before_poll.tv_sec - after_poll.tv_sec) * 1000000U + (before_poll.tv_usec - after_poll.tv_usec); - - new_cpu_time = now_cpu_time(); - new_mono_time = now_mono_time(); + if (before_poll_mono_ns) + run_time = (before_poll_mono_ns - th_ctx->curr_mono_time) / 1000ull; + else + run_time = (before_poll.tv_sec - after_poll.tv_sec) * 1000000U + (before_poll.tv_usec - after_poll.tv_usec); if (th_ctx->prev_cpu_time && th_ctx->prev_mono_time) { new_cpu_time -= th_ctx->prev_cpu_time;