summaryrefslogtreecommitdiff
path: root/storage/innobase/sync
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-09-06 12:22:33 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-09-06 12:22:33 +0300
commit0f0b7e47bc794d0af0b7f758a6fe1518b8388e3a (patch)
treec9c56320d543c2801468ac189e545742e9c47cf2 /storage/innobase/sync
parenta73eedbf3fabd19ca7183b738056c30e3f7bbe35 (diff)
downloadmariadb-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.cc50
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;
}