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()
/* First, try busy spinning for a while. */
for (auto spin= srv_n_spin_wait_rounds; spin--; )
{
ut_delay(srv_spin_wait_delay);
LF_BACKOFF();
if (read_trylock())
return;
}
......@@ -301,7 +301,7 @@ void page_hash_latch::write_lock_wait()
{
if (write_lock_poll())
return;
ut_delay(srv_spin_wait_delay);
LF_BACKOFF();
}
/* Fall back to yielding to other threads. */
......
......@@ -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;
}
......
......@@ -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,
so that there will be no race condition in lock_release(). */
while (UNIV_UNLIKELY(is_referenced()))
ut_delay(srv_spin_wait_delay);
LF_BACKOFF();
}
else
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