]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: time: avoid overwriting the same values of global_now
authorWilly Tarreau <w@1wt.eu>
Fri, 23 Apr 2021 13:36:47 +0000 (15:36 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 23 Apr 2021 16:03:06 +0000 (18:03 +0200)
In tv_update_date(), we calculate the new global date based on the local
one. It's very likely that other threads will end up with the exact same
now_ms date (at 1 million wakeups/s it happens 99.9% of the time), and
even the microsecond was measured to remain unchanged ~70% of the time
with 16 threads, simply because sometimes another thread already updated
a more recent version of it.

In such cases, performing a CAS to the global variable requires a cache
line flush which brings nothing. By checking if they're changed before
writing, we can divide by about 6 the number of writes to the global
variables, hence the overall contention.

In addition, it's worth noting that all threads will want to update at
the same time, so let's place a cpu relax call before trying again, this
will spread attempts apart.

src/time.c

index 9b13ad90d166b98660561eaa6084aa80d9c0872e..cb106ca3f91fc009981722c006e7e76329ccce05 100644 (file)
@@ -252,8 +252,9 @@ void tv_update_date(int max_wait, int interrupted)
                /* let's try to update the global <now> (both in timeval
                 * and ms forms) or loop again.
                 */
-       } while (!_HA_ATOMIC_CAS(&global_now, &old_now, new_now) ||
-                !_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, now_ms));
+       } while (((new_now != old_now    && !_HA_ATOMIC_CAS(&global_now, &old_now, new_now)) ||
+                 (now_ms  != old_now_ms && !_HA_ATOMIC_CAS(&global_now_ms, &old_now_ms, now_ms))) &&
+                __ha_cpu_relax());
 
        /* <now> and <now_ms> are now updated to the last value of global_now
         * and global_now_ms, which were also monotonically updated. We can