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.
This commit is contained in:
Willy Tarreau 2021-04-23 15:36:47 +02:00
parent 481795de13
commit 4d01f3dcdc
1 changed files with 3 additions and 2 deletions

View 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