diff options
author | Sergey Vojtovich <svoj@mariadb.org> | 2018-01-24 20:09:14 +0400 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2018-01-26 10:25:33 +0400 |
commit | ce0479006523bc72ed6abb703bd1f87ff256fd8a (patch) | |
tree | b79a3003e545eec2edc6efcdf43820fc6ad120b5 | |
parent | 92d233a5129c027a57ed301c81bd5161c1674dd6 (diff) | |
download | mariadb-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.result | 16 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/r/sysvars_innodb.result | 6 | ||||
-rw-r--r-- | storage/innobase/dict/dict0stats.cc | 7 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 11 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 4 | ||||
-rw-r--r-- | storage/innobase/include/ib0mutex.h | 6 | ||||
-rw-r--r-- | storage/innobase/include/ut0rnd.h | 10 | ||||
-rw-r--r-- | storage/innobase/include/ut0rnd.ic | 24 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 2 | ||||
-rw-r--r-- | storage/innobase/sync/sync0rw.cc | 23 |
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++; } |