]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: clock: use the monotonic clock for idle time calculation
authorWilly Tarreau <w@1wt.eu>
Sun, 8 Sep 2024 18:54:36 +0000 (18:54 +0000)
committerWilly Tarreau <w@1wt.eu>
Tue, 17 Sep 2024 07:08:10 +0000 (09:08 +0200)
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.

src/clock.c

index 5528ec7def3f9bd7e5c24267c85de12bd5fbd9a7..ab266632d9bde248722c1e1e171317b392e2a1c5 100644 (file)
@@ -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;