Commit ce047900 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-14482 - Cache line contention on ut_rnd_ulint_counter()

InnoDB RNG maintains global state, causing otherwise unnecessary bus
traffic. Even worse this is cross-mutex traffic. That is different
mutexes suffer from contention.

Fixed delay of 4 was verified to give best throughput by OLTP update
index and read-write benchmarks on Intel Broadwell (2/20/40) and
ARM (1/46/46).
parent 92d233a5
SET @start_global_value = @@global.innodb_spin_wait_delay;
SELECT @start_global_value;
@start_global_value
6
4
Valid values are zero or above
select @@global.innodb_spin_wait_delay >=0;
@@global.innodb_spin_wait_delay >=0
1
select @@global.innodb_spin_wait_delay;
@@global.innodb_spin_wait_delay
6
4
select @@session.innodb_spin_wait_delay;
ERROR HY000: Variable 'innodb_spin_wait_delay' is a GLOBAL variable
show global variables like 'innodb_spin_wait_delay';
Variable_name Value
innodb_spin_wait_delay 6
innodb_spin_wait_delay 4
show session variables like 'innodb_spin_wait_delay';
Variable_name Value
innodb_spin_wait_delay 6
innodb_spin_wait_delay 4
select * from information_schema.global_variables where variable_name='innodb_spin_wait_delay';
VARIABLE_NAME VARIABLE_VALUE
INNODB_SPIN_WAIT_DELAY 6
INNODB_SPIN_WAIT_DELAY 4
select * from information_schema.session_variables where variable_name='innodb_spin_wait_delay';
VARIABLE_NAME VARIABLE_VALUE
INNODB_SPIN_WAIT_DELAY 6
INNODB_SPIN_WAIT_DELAY 4
set global innodb_spin_wait_delay=10;
select @@global.innodb_spin_wait_delay;
@@global.innodb_spin_wait_delay
......@@ -38,7 +38,7 @@ ERROR HY000: Variable 'innodb_spin_wait_delay' is a GLOBAL variable and should b
set global innodb_spin_wait_delay=DEFAULT;
select @@global.innodb_spin_wait_delay;
@@global.innodb_spin_wait_delay
6
4
set global innodb_spin_wait_delay=0;
select @@global.innodb_spin_wait_delay;
@@global.innodb_spin_wait_delay
......@@ -111,4 +111,4 @@ INNODB_SPIN_WAIT_DELAY 0
SET @@global.innodb_spin_wait_delay = @start_global_value;
SELECT @@global.innodb_spin_wait_delay;
@@global.innodb_spin_wait_delay
6
4
......@@ -1996,12 +1996,12 @@ READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_SPIN_WAIT_DELAY
SESSION_VALUE NULL
GLOBAL_VALUE 6
GLOBAL_VALUE 4
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 6
DEFAULT_VALUE 4
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Maximum delay between polling for a spin lock (6 by default)
VARIABLE_COMMENT Maximum delay between polling for a spin lock (4 by default)
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 6000
NUMERIC_BLOCK_SIZE 0
......
......@@ -1758,11 +1758,8 @@ dict_stats_analyze_index_for_n_prefix(
ut_a(left <= right);
ut_a(right <= last_idx_on_level);
/* we do not pass (left, right) because we do not want to ask
ut_rnd_interval() to work with too big numbers since
ib_uint64_t could be bigger than ulint */
const ulint rnd = ut_rnd_interval(
0, static_cast<ulint>(right - left));
const ulint rnd = right == left ? 0 :
ut_rnd_gen_ulint() % (right - left);
const ib_uint64_t dive_below_idx
= boundaries->at(static_cast<unsigned>(left + rnd));
......
......@@ -5978,17 +5978,6 @@ fil_tablespace_iterate(
innodb_data_file_key, filepath,
OS_FILE_OPEN, OS_FILE_READ_WRITE, srv_read_only_mode, &success);
DBUG_EXECUTE_IF("fil_tablespace_iterate_failure",
{
static bool once;
if (!once || ut_rnd_interval(0, 10) == 5) {
once = true;
success = false;
os_file_close(file);
}
});
if (!success) {
/* The following call prints an error message */
os_file_get_last_error(true);
......
......@@ -20559,8 +20559,8 @@ static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
static MYSQL_SYSVAR_UINT(spin_wait_delay, srv_spin_wait_delay,
PLUGIN_VAR_OPCMDARG,
"Maximum delay between polling for a spin lock (6 by default)",
NULL, NULL, 6, 0, 6000, 0);
"Maximum delay between polling for a spin lock (4 by default)",
NULL, NULL, 4, 0, 6000, 0);
static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
PLUGIN_VAR_RQCMDARG,
......
......@@ -225,7 +225,7 @@ struct TTASFutexMutex {
return;
}
ut_delay(ut_rnd_interval(0, max_delay));
ut_delay(max_delay);
}
for (n_waits= 0;; n_waits++) {
......@@ -362,7 +362,7 @@ struct TTASMutex {
uint32_t n_spins = 0;
while (!try_lock()) {
ut_delay(ut_rnd_interval(0, max_delay));
ut_delay(max_delay);
if (++n_spins == max_spins) {
os_thread_yield();
max_spins+= step;
......@@ -516,7 +516,7 @@ struct TTASEventMutex {
sync_array_wait_event(sync_arr, cell);
}
} else {
ut_delay(ut_rnd_interval(0, max_delay));
ut_delay(max_delay);
}
}
......
......@@ -61,16 +61,6 @@ UNIV_INLINE
ulint
ut_rnd_gen_ulint(void);
/*==================*/
/********************************************************//**
Generates a random integer from a given interval.
@return the 'random' number */
UNIV_INLINE
ulint
ut_rnd_interval(
/*============*/
ulint low, /*!< in: low limit; can generate also this value */
ulint high); /*!< in: high limit; can generate also this value */
/*******************************************************//**
The following function generates a hash value for a ulint integer
to a hash table of size table_size, which should be a prime or some
......
......@@ -97,30 +97,6 @@ ut_rnd_gen_ulint(void)
return(rnd);
}
/********************************************************//**
Generates a random integer from a given interval.
@return the 'random' number */
UNIV_INLINE
ulint
ut_rnd_interval(
/*============*/
ulint low, /*!< in: low limit; can generate also this value */
ulint high) /*!< in: high limit; can generate also this value */
{
ulint rnd;
ut_ad(high >= low);
if (low == high) {
return(low);
}
rnd = ut_rnd_gen_ulint();
return(low + (rnd % (high - low)));
}
/*******************************************************//**
The following function generates a hash value for a ulint integer
to a hash table of size table_size, which should be a prime
......
......@@ -7285,7 +7285,7 @@ lock_trx_release_locks(
/** Doing an implicit to explicit conversion
should not be expensive. */
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
ut_delay(srv_spin_wait_delay);
}
lock_mutex_enter();
......
......@@ -317,10 +317,7 @@ rw_lock_s_lock_spin(
while (i < srv_n_spin_wait_rounds &&
my_atomic_load32_explicit(&lock->lock_word,
MY_MEMORY_ORDER_RELAXED) <= 0) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
}
ut_delay(srv_spin_wait_delay);
i++;
}
......@@ -441,9 +438,7 @@ rw_lock_x_lock_wait_func(
HMT_low();
while (my_atomic_load32_explicit(&lock->lock_word, MY_MEMORY_ORDER_RELAXED) < threshold) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
}
ut_delay(srv_spin_wait_delay);
if (i < srv_n_spin_wait_rounds) {
i++;
......@@ -714,12 +709,7 @@ rw_lock_x_lock_func(
HMT_low();
while (i < srv_n_spin_wait_rounds
&& my_atomic_load32_explicit(&lock->lock_word, MY_MEMORY_ORDER_RELAXED) <= X_LOCK_HALF_DECR) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(
0, srv_spin_wait_delay));
}
ut_delay(srv_spin_wait_delay);
i++;
}
......@@ -820,12 +810,7 @@ rw_lock_sx_lock_func(
/* Spin waiting for the lock_word to become free */
while (i < srv_n_spin_wait_rounds
&& my_atomic_load32_explicit(&lock->lock_word, MY_MEMORY_ORDER_RELAXED) <= X_LOCK_HALF_DECR) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(
0, srv_spin_wait_delay));
}
ut_delay(srv_spin_wait_delay);
i++;
}
......
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