diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-06 12:22:33 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-06 12:22:33 +0300 |
commit | 0f0b7e47bc794d0af0b7f758a6fe1518b8388e3a (patch) | |
tree | c9c56320d543c2801468ac189e545742e9c47cf2 /storage/innobase/sync | |
parent | a73eedbf3fabd19ca7183b738056c30e3f7bbe35 (diff) | |
download | mariadb-git-0f0b7e47bc794d0af0b7f758a6fe1518b8388e3a.tar.gz |
MDEV-26467: Avoid re-reading srv_spin_wait_delay inside a loop
Invoking ut_delay(srv_wpin_wait_delay) inside a spinloop would
cause a read of 2 global variables as well as multiplication.
Let us loop around MY_RELAX_CPU() using a precomputed loop count
to keep the loops simpler, to help them scale better.
We also tried precomputing the delay into a global variable,
but that appeared to result in slightly worse throughput.
Diffstat (limited to 'storage/innobase/sync')
-rw-r--r-- | storage/innobase/sync/srw_lock.cc | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc index 780add3f705..b267969c3df 100644 --- a/storage/innobase/sync/srw_lock.cc +++ b/storage/innobase/sync/srw_lock.cc @@ -20,6 +20,21 @@ this program; if not, write to the Free Software Foundation, Inc., #include "srv0srv.h" #include "my_cpu.h" +/** @return the parameter for srw_pause() */ +static inline unsigned srw_pause_delay() +{ + return my_cpu_relax_multiplier / 4 * srv_spin_wait_delay; +} + +/** Pause the CPU for some time, with no memory accesses. */ +static inline void srw_pause(unsigned delay) +{ + HMT_low(); + while (delay--) + MY_RELAX_CPU(); + HMT_medium(); +} + #ifdef SUX_LOCK_GENERIC void ssux_lock_low::init() { @@ -90,15 +105,17 @@ void ssux_lock_low::read_lock(uint32_t l) pthread_mutex_unlock(&mutex); continue; } - else - for (auto spin= srv_n_spin_wait_rounds; spin; spin--) - { - ut_delay(srv_spin_wait_delay); - if (read_trylock<true>(l)) - return; - else if (l == WRITER_WAITING) - goto wake_writer; - } + + const unsigned delay= srw_pause_delay(); + + for (auto spin= srv_n_spin_wait_rounds; spin; spin--) + { + srw_pause(delay); + if (read_trylock<true>(l)) + return; + else if (l == WRITER_WAITING) + goto wake_writer; + } readers_wait(l); } @@ -128,14 +145,18 @@ void ssux_lock_low::update_lock(uint32_t l) continue; } else + { + const unsigned delay= srw_pause_delay(); + for (auto spin= srv_n_spin_wait_rounds; spin; spin--) { - ut_delay(srv_spin_wait_delay); + srw_pause(delay); if (update_trylock(l)) return; else if ((l | UPDATER) == (UPDATER | WRITER_WAITING)) goto wake_writer; } + } readers_wait(l); } @@ -146,6 +167,8 @@ void ssux_lock_low::update_lock(uint32_t l) @param holding_u whether we already hold u_lock() */ void ssux_lock_low::write_lock(bool holding_u) { + const unsigned delay= srw_pause_delay(); + for (;;) { uint32_t l= write_lock_wait_start(); @@ -157,7 +180,7 @@ void ssux_lock_low::write_lock(bool holding_u) return; if (!(l & WRITER_WAITING)) l= write_lock_wait_start(); - ut_delay(srv_spin_wait_delay); + srw_pause(delay); } const uint32_t e= holding_u ? WRITER_WAITING | UPDATER : WRITER_WAITING; @@ -233,6 +256,9 @@ void ssux_lock_low::wake() { SRW_FUTEX(&readers, WAKE, 1); } void srw_mutex::wait_and_lock() { uint32_t lk= 1 + lock.fetch_add(1, std::memory_order_relaxed); + + const unsigned delay= srw_pause_delay(); + for (auto spin= srv_n_spin_wait_rounds;;) { DBUG_ASSERT(~HOLDER & lk); @@ -244,7 +270,7 @@ void srw_mutex::wait_and_lock() if (!(lk & HOLDER)) goto acquired; } - ut_delay(srv_spin_wait_delay); + srw_pause(delay); if (!--spin) break; } |