From 4d01f3dcdc81465e4a3712642cb9ba4148030049 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 23 Apr 2021 15:36:47 +0200 Subject: [PATCH] MINOR: time: avoid overwriting the same values of global_now 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 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/time.c b/src/time.c index 9b13ad90d1..cb106ca3f9 100644 --- a/src/time.c +++ b/src/time.c @@ -252,8 +252,9 @@ void tv_update_date(int max_wait, int interrupted) /* let's try to update the global (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()); /* and are now updated to the last value of global_now * and global_now_ms, which were also monotonically updated. We can -- 2.39.5