Commit 0f0b7e47 authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent a73eedbf
...@@ -282,7 +282,7 @@ void page_hash_latch::read_lock_wait() ...@@ -282,7 +282,7 @@ void page_hash_latch::read_lock_wait()
/* First, try busy spinning for a while. */ /* First, try busy spinning for a while. */
for (auto spin= srv_n_spin_wait_rounds; spin--; ) for (auto spin= srv_n_spin_wait_rounds; spin--; )
{ {
ut_delay(srv_spin_wait_delay); LF_BACKOFF();
if (read_trylock()) if (read_trylock())
return; return;
} }
...@@ -301,7 +301,7 @@ void page_hash_latch::write_lock_wait() ...@@ -301,7 +301,7 @@ void page_hash_latch::write_lock_wait()
{ {
if (write_lock_poll()) if (write_lock_poll())
return; return;
ut_delay(srv_spin_wait_delay); LF_BACKOFF();
} }
/* Fall back to yielding to other threads. */ /* Fall back to yielding to other threads. */
......
...@@ -20,6 +20,21 @@ this program; if not, write to the Free Software Foundation, Inc., ...@@ -20,6 +20,21 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "srv0srv.h" #include "srv0srv.h"
#include "my_cpu.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 #ifdef SUX_LOCK_GENERIC
void ssux_lock_low::init() void ssux_lock_low::init()
{ {
...@@ -90,10 +105,12 @@ void ssux_lock_low::read_lock(uint32_t l) ...@@ -90,10 +105,12 @@ void ssux_lock_low::read_lock(uint32_t l)
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
continue; continue;
} }
else
const unsigned delay= srw_pause_delay();
for (auto spin= srv_n_spin_wait_rounds; spin; spin--) for (auto spin= srv_n_spin_wait_rounds; spin; spin--)
{ {
ut_delay(srv_spin_wait_delay); srw_pause(delay);
if (read_trylock<true>(l)) if (read_trylock<true>(l))
return; return;
else if (l == WRITER_WAITING) else if (l == WRITER_WAITING)
...@@ -128,14 +145,18 @@ void ssux_lock_low::update_lock(uint32_t l) ...@@ -128,14 +145,18 @@ void ssux_lock_low::update_lock(uint32_t l)
continue; continue;
} }
else else
{
const unsigned delay= srw_pause_delay();
for (auto spin= srv_n_spin_wait_rounds; spin; spin--) for (auto spin= srv_n_spin_wait_rounds; spin; spin--)
{ {
ut_delay(srv_spin_wait_delay); srw_pause(delay);
if (update_trylock(l)) if (update_trylock(l))
return; return;
else if ((l | UPDATER) == (UPDATER | WRITER_WAITING)) else if ((l | UPDATER) == (UPDATER | WRITER_WAITING))
goto wake_writer; goto wake_writer;
} }
}
readers_wait(l); readers_wait(l);
} }
...@@ -146,6 +167,8 @@ void ssux_lock_low::update_lock(uint32_t l) ...@@ -146,6 +167,8 @@ void ssux_lock_low::update_lock(uint32_t l)
@param holding_u whether we already hold u_lock() */ @param holding_u whether we already hold u_lock() */
void ssux_lock_low::write_lock(bool holding_u) void ssux_lock_low::write_lock(bool holding_u)
{ {
const unsigned delay= srw_pause_delay();
for (;;) for (;;)
{ {
uint32_t l= write_lock_wait_start(); uint32_t l= write_lock_wait_start();
...@@ -157,7 +180,7 @@ void ssux_lock_low::write_lock(bool holding_u) ...@@ -157,7 +180,7 @@ void ssux_lock_low::write_lock(bool holding_u)
return; return;
if (!(l & WRITER_WAITING)) if (!(l & WRITER_WAITING))
l= write_lock_wait_start(); 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; 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); } ...@@ -233,6 +256,9 @@ void ssux_lock_low::wake() { SRW_FUTEX(&readers, WAKE, 1); }
void srw_mutex::wait_and_lock() void srw_mutex::wait_and_lock()
{ {
uint32_t lk= 1 + lock.fetch_add(1, std::memory_order_relaxed); 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;;) for (auto spin= srv_n_spin_wait_rounds;;)
{ {
DBUG_ASSERT(~HOLDER & lk); DBUG_ASSERT(~HOLDER & lk);
...@@ -244,7 +270,7 @@ void srw_mutex::wait_and_lock() ...@@ -244,7 +270,7 @@ void srw_mutex::wait_and_lock()
if (!(lk & HOLDER)) if (!(lk & HOLDER))
goto acquired; goto acquired;
} }
ut_delay(srv_spin_wait_delay); srw_pause(delay);
if (!--spin) if (!--spin)
break; break;
} }
......
...@@ -1275,7 +1275,7 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1275,7 +1275,7 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr)
/* Wait for any implicit-to-explicit lock conversions to cease, /* Wait for any implicit-to-explicit lock conversions to cease,
so that there will be no race condition in lock_release(). */ so that there will be no race condition in lock_release(). */
while (UNIV_UNLIKELY(is_referenced())) while (UNIV_UNLIKELY(is_referenced()))
ut_delay(srv_spin_wait_delay); LF_BACKOFF();
} }
else else
ut_ad(read_only || !rsegs.m_redo.rseg); ut_ad(read_only || !rsegs.m_redo.rseg);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment