WL#4975: Improvement of InnoDB spinloop
Affects: Server-5.4
—
Status: Complete
Improvement of InnoDB spinloop and modified default values of spin values. In MySQL 5.4.0
Add a PAUSE instruction to the SPIN loop to decrease the amount of resources used by the CPU-thread that is spinning, to make it possible for the CPU-threads that do valuable work to progress with greater speed. This will be implemented on x86 by using the PAUSE instruction, on SPARC the Compare and Swap instruction will be used instead in light of a research paper on this topic on CMT boxes. For further details, see: http://mikaelronstrom.blogspot.com/2009/04/mysql-54-patches-improvements-to-spin.html
Added a PAUSE instruction to the SPIN loop according to recommendation from Intel. Minor modifications to spin values which showed to be slightly better. Fix of ifdef error Yet another idef error Fix compiler error Fixed bug Use AC_TRY_RUN instead of AC_TRY_LINK when checking for x86 PAUSE instruction support, due to http://bugs.opensolaris.org/bugdatabase/printableBug.do?bug_id=6478684 . Added support for rep; nop replacing PAUSE due to Solaris bug Replaced abs_top_srcdir with top_srcdir, not sure it's an improvement but at least it's known that abs_top_srcdir in cases have a problem and this is a more common variable to use for the same purpose. These patches implement the InnoDB spinloop improvements. === modified file 'configure.in' --- configure.in 2008-12-05 18:43:45 +0000 +++ configure.in 2008-12-10 13:02:52 +0000 @@ -2342,6 +2342,17 @@ fi fi #---END: +#Check for x86 PAUSE instruction +AC_MSG_CHECKING("for x86 PAUSE instruction") +AC_TRY_COMPILE( +[], +[{__asm__ __volatile__ ("pause");}], +x86_pause_exists=yes, x86_pause_exists=no) +if test "$x86_pause_exists" = "yes" +then + AC_DEFINE([HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) +fi + # Check if pthread_attr_setscope() exists AC_CACHE_CHECK("for pthread_attr_setscope", mysql_cv_pthread_attr_setscope, AC_TRY_LINK( === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-10-16 18:45:12 +0000 +++ storage/innobase/include/ut0ut.h 2008-12-10 13:02:52 +0000 @@ -17,6 +17,19 @@ Created 1/20/1994 Heikki Tuuri typedef time_t ib_time_t; +#ifdef HAVE_PAUSE_INSTRUCTION +#define PAUSE_INSTRUCTION(volatile_var) {__asm__ __volatile__ ("pause");} +#elif +#ifdef UNIV_SYNC_ATOMIC +#define PAUSE_INSTRUCTION(volatile_var) \ + { \ + os_compare_and_swap(volatile_var, 0, 1); \ + } +#elif +#define PAUSE_INSTRUCTION(volatile_var) +#endif +#endif + /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, but since there seem to be compiler bugs in both gcc and Visual C++, === modified file 'storage/innobase/ut/ut0ut.c' --- storage/innobase/ut/ut0ut.c 2008-10-16 18:45:12 +0000 +++ storage/innobase/ut/ut0ut.c 2008-12-10 13:02:52 +0000 @@ -336,11 +336,13 @@ ut_delay( ulint delay) /* in: delay in microseconds on 100 MHz Pentium */ { ulint i, j; + volatile lint volatile_var; j = 0; for (i = 0; i < delay * 50; i++) { j += i; + PAUSE_INSTRUCTION(&volatile_var); } if (ut_always_false) { === modified file 'storage/innobase/srv/srv0srv.c' --- storage/innobase/srv/srv0srv.c 2008-12-05 13:08:28 +0000 +++ storage/innobase/srv/srv0srv.c 2008-12-10 17:54:23 +0000 @@ -352,10 +352,10 @@ ibool srv_use_awe = FALSE; ibool srv_use_adaptive_hash_indexes = TRUE; /*-------------------------------------------*/ -ulong srv_n_spin_wait_rounds = 20; +ulong srv_n_spin_wait_rounds = 30; ulong srv_n_free_tickets_to_enter = 500; ulong srv_thread_sleep_delay = 10000; -ulint srv_spin_wait_delay = 5; +ulint srv_spin_wait_delay = 6; ibool srv_priority_boost = TRUE; ibool srv_print_thread_releases = FALSE; === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-12-10 13:02:52 +0000 +++ storage/innobase/include/ut0ut.h 2008-12-12 21:39:12 +0000 @@ -25,7 +25,7 @@ typedef time_t ib_time_t; { \ os_compare_and_swap(volatile_var, 0, 1); \ } -#elif +#else #define PAUSE_INSTRUCTION(volatile_var) #endif #endif === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-12-12 21:39:12 +0000 +++ storage/innobase/include/ut0ut.h 2008-12-12 22:44:39 +0000 @@ -19,7 +19,7 @@ typedef time_t ib_time_t; #ifdef HAVE_PAUSE_INSTRUCTION #define PAUSE_INSTRUCTION(volatile_var) {__asm__ __volatile__ ("pause");} -#elif +#else #ifdef UNIV_SYNC_ATOMIC #define PAUSE_INSTRUCTION(volatile_var) \ { \ === modified file 'configure.in' --- configure.in 2008-12-20 15:15:46 +0000 +++ configure.in 2009-02-01 01:34:39 +0000 @@ -2357,10 +2357,20 @@ fi #Check for x86 PAUSE instruction AC_MSG_CHECKING("for x86 PAUSE instruction") -AC_TRY_COMPILE( -[], -[{__asm__ __volatile__ ("pause");}], -x86_pause_exists=yes, x86_pause_exists=no) +# We have to actually try running the test program, because of a bug +# in Solaris on x86_64, where it wrongly reports that PAUSE is not +# supported when trying to run an application. See +# http://bugs.opensolaris.org/bugdatabase/printableBug.do?bug_id=6478684 +AC_TRY_RUN([ + int main() { + __asm__ __volatile__ ("pause"); + return 0; + } + ], + [x86_pause_exists=yes], + [x86_pause_exists=no], + [x86_pause_exists=no] # Cross-compile, assume no PAUSE instruction +) if test "$x86_pause_exists" = "yes" then AC_DEFINE([HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) === modified file 'configure.in' --- configure.in 2009-02-01 01:34:39 +0000 +++ configure.in 2009-02-03 11:46:52 +0000 @@ -2371,9 +2371,24 @@ AC_TRY_RUN([ [x86_pause_exists=no], [x86_pause_exists=no] # Cross-compile, assume no PAUSE instruction ) +AC_TRY_RUN([ + int main() { + __asm__ __volatile__ ("rep; nop"); + return 0; + } + ], + [x86_fake_pause_exists=yes], + [x86_fake_pause_exists=no], + [x86_fake_pause_exists=no] # Cross-compile, assume no x86 NOP instruction +) if test "$x86_pause_exists" = "yes" then AC_DEFINE([HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) +else + if test "$x86_fake_pause_exists" = "yes" + then + AC_DEFINE([HAVE_FAKE_PAUSE_INSTRUCTION], [1], [Does x86 NOP instruction exist]) + fi fi # Check if pthread_attr_setscope() exists === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-12-15 10:19:47 +0000 +++ storage/innobase/include/ut0ut.h 2009-02-03 11:46:52 +0000 @@ -20,6 +20,9 @@ typedef time_t ib_time_t; #ifdef HAVE_PAUSE_INSTRUCTION #define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("pause");} #else +#ifdef HAVE_FAKE_PAUSE_INSTRUCTION +#define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("rep; nop");} +#else #ifdef UNIV_SYNC_ATOMIC #define PAUSE_INSTRUCTION() \ { \ @@ -30,6 +33,7 @@ typedef time_t ib_time_t; #define PAUSE_INSTRUCTION() #endif #endif +#endif /************************************************************ Gets the high 32 bits in a ulint. That is makes a shift >> 32, === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-12-15 08:44:00 +0000 +++ storage/innobase/include/ut0ut.h 2008-12-15 09:05:35 +0000 @@ -23,7 +23,7 @@ typedef time_t ib_time_t; #ifdef UNIV_SYNC_ATOMIC #define PAUSE_INSTRUCTION() \ { \ - volatile lint volatile_var; + volatile lint volatile_var; \ os_compare_and_swap(volatile_var, 0, 1); \ } #else === modified file 'storage/innobase/include/ut0ut.h' --- storage/innobase/include/ut0ut.h 2008-12-15 09:05:35 +0000 +++ storage/innobase/include/ut0ut.h 2008-12-15 10:19:47 +0000 @@ -24,7 +24,7 @@ typedef time_t ib_time_t; #define PAUSE_INSTRUCTION() \ { \ volatile lint volatile_var; \ - os_compare_and_swap(volatile_var, 0, 1); \ + os_compare_and_swap(&volatile_var, 0, 1); \ } #else #define PAUSE_INSTRUCTION()
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.