summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Vojtovich <svoj@mariadb.org>2018-01-24 20:09:14 +0400
committerSergey Vojtovich <svoj@mariadb.org>2018-01-26 10:25:33 +0400
commitce0479006523bc72ed6abb703bd1f87ff256fd8a (patch)
treeb79a3003e545eec2edc6efcdf43820fc6ad120b5
parent92d233a5129c027a57ed301c81bd5161c1674dd6 (diff)
downloadmariadb-git-ce0479006523bc72ed6abb703bd1f87ff256fd8a.tar.gz
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).
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_spin_wait_delay_basic.result16
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_innodb.result6
-rw-r--r--storage/innobase/dict/dict0stats.cc7
-rw-r--r--storage/innobase/fil/fil0fil.cc11
-rw-r--r--storage/innobase/handler/ha_innodb.cc4
-rw-r--r--storage/innobase/include/ib0mutex.h6
-rw-r--r--storage/innobase/include/ut0rnd.h10
-rw-r--r--storage/innobase/include/ut0rnd.ic24
-rw-r--r--storage/innobase/lock/lock0lock.cc2
-rw-r--r--storage/innobase/sync/sync0rw.cc23
10 files changed, 23 insertions, 86 deletions
diff --git a/mysql-test/suite/sys_vars/r/innodb_spin_wait_delay_basic.result b/mysql-test/suite/sys_vars/r/innodb_spin_wait_delay_basic.result
index 88516a854fe..b76ba4933f2 100644
--- a/mysql-test/suite/sys_vars/r/innodb_spin_wait_delay_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_spin_wait_delay_basic.result
@@ -1,28 +1,28 @@
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
diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
index 720d6a1458a..ad972212d7b 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
@@ -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
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 82bdf1f92ce..a45c752ffc0 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -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));
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index fa65bda4490..b93489a10e6 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -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);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index b1f858a5927..41ce69d9ca6 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -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,
diff --git a/storage/innobase/include/ib0mutex.h b/storage/innobase/include/ib0mutex.h
index 76f02cc1521..20703a4a933 100644
--- a/storage/innobase/include/ib0mutex.h
+++ b/storage/innobase/include/ib0mutex.h
@@ -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);
}
}
diff --git a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h
index 49ae3c81356..5baf8684d23 100644
--- a/storage/innobase/include/ut0rnd.h
+++ b/storage/innobase/include/ut0rnd.h
@@ -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
diff --git a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic
index 16dccb545d8..1e4915dd0f9 100644
--- a/storage/innobase/include/ut0rnd.ic
+++ b/storage/innobase/include/ut0rnd.ic
@@ -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
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 8049e6d6d01..1440ad9eae8 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -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();
diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc
index 13c81d7333d..9996bd7262c 100644
--- a/storage/innobase/sync/sync0rw.cc
+++ b/storage/innobase/sync/sync0rw.cc
@@ -317,10 +317,7 @@ lock_loop:
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 @@ lock_loop:
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 @@ lock_loop:
/* 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++;
}