Browse Source
WL#2595 kernel-independent atomic operations
WL#2595 kernel-independent atomic operations
Backport from 6.0.14 to 5.6.0 Original code from Sergei Golubchikpull/374/head
14 changed files with 675 additions and 282 deletions
-
90configure.in
-
6include/Makefile.am
-
5include/atomic/gcc_builtins.h
-
116include/atomic/generic-msvc.h
-
49include/atomic/nolock.h
-
70include/atomic/rwlock.h
-
8include/atomic/solaris.h
-
28include/atomic/x86-gcc.h
-
269include/my_atomic.h
-
33mysys/my_atomic.c
-
34mysys/my_getncpus.c
-
2unittest/mysys/Makefile.am
-
155unittest/mysys/my_atomic-t.c
-
92unittest/mysys/thr_template.c
@ -0,0 +1,116 @@ |
|||
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#ifndef _atomic_h_cleanup_ |
|||
#define _atomic_h_cleanup_ "atomic/generic-msvc.h" |
|||
|
|||
/* |
|||
We don't implement anything specific for MY_ATOMIC_MODE_DUMMY, always use |
|||
intrinsics. |
|||
8 and 16-bit atomics are not implemented, but it can be done if necessary. |
|||
*/ |
|||
#undef MY_ATOMIC_HAS_8_16 |
|||
|
|||
/* |
|||
x86 compilers (both VS2003 or VS2005) never use instrinsics, but generate |
|||
function calls to kernel32 instead, even in the optimized build. |
|||
We force intrinsics as described in MSDN documentation for |
|||
_InterlockedCompareExchange. |
|||
*/ |
|||
#ifdef _M_IX86 |
|||
|
|||
#if (_MSC_VER >= 1500) |
|||
#include <intrin.h> |
|||
#else |
|||
C_MODE_START |
|||
/*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/ |
|||
LONG _InterlockedExchange (LONG volatile *Target,LONG Value); |
|||
LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp); |
|||
LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value); |
|||
C_MODE_END |
|||
|
|||
#pragma intrinsic(_InterlockedExchangeAdd) |
|||
#pragma intrinsic(_InterlockedCompareExchange) |
|||
#pragma intrinsic(_InterlockedExchange) |
|||
#endif |
|||
|
|||
#define InterlockedExchange _InterlockedExchange |
|||
#define InterlockedExchangeAdd _InterlockedExchangeAdd |
|||
#define InterlockedCompareExchange _InterlockedCompareExchange |
|||
/* |
|||
No need to do something special for InterlockedCompareExchangePointer |
|||
as it is a #define to InterlockedCompareExchange. The same applies to |
|||
InterlockedExchangePointer. |
|||
*/ |
|||
#endif /*_M_IX86*/ |
|||
|
|||
#define MY_ATOMIC_MODE "msvc-intrinsics" |
|||
#define IL_EXCHG_ADD32(X,Y) InterlockedExchangeAdd((volatile LONG *)(X),(Y)) |
|||
#define IL_COMP_EXCHG32(X,Y,Z) InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z)) |
|||
#define IL_COMP_EXCHGptr InterlockedCompareExchangePointer |
|||
#define IL_EXCHG32(X,Y) InterlockedExchange((volatile LONG *)(X),(Y)) |
|||
#define IL_EXCHGptr InterlockedExchangePointer |
|||
#define make_atomic_add_body(S) \ |
|||
v= IL_EXCHG_ADD ## S (a, v) |
|||
#define make_atomic_cas_body(S) \ |
|||
int ## S initial_cmp= *cmp; \ |
|||
int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \ |
|||
if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a; |
|||
#define make_atomic_swap_body(S) \ |
|||
v= IL_EXCHG ## S (a, v) |
|||
#define make_atomic_load_body(S) \ |
|||
ret= 0; /* avoid compiler warning */ \ |
|||
ret= IL_COMP_EXCHG ## S (a, ret, ret); |
|||
|
|||
/* |
|||
my_yield_processor (equivalent of x86 PAUSE instruction) should be used |
|||
to improve performance on hyperthreaded CPUs. Intel recommends to use it in |
|||
spin loops also on non-HT machines to reduce power consumption (see e.g |
|||
http://softwarecommunity.intel.com/articles/eng/2004.htm) |
|||
|
|||
Running benchmarks for spinlocks implemented with InterlockedCompareExchange |
|||
and YieldProcessor shows that much better performance is achieved by calling |
|||
YieldProcessor in a loop - that is, yielding longer. On Intel boxes setting |
|||
loop count in the range 200-300 brought best results. |
|||
*/ |
|||
#ifndef YIELD_LOOPS |
|||
#define YIELD_LOOPS 200 |
|||
#endif |
|||
|
|||
static __inline int my_yield_processor() |
|||
{ |
|||
int i; |
|||
for(i=0; i<YIELD_LOOPS; i++) |
|||
{ |
|||
#if (_MSC_VER <= 1310) |
|||
/* On older compilers YieldProcessor is not available, use inline assembly*/ |
|||
__asm { rep nop } |
|||
#else |
|||
YieldProcessor(); |
|||
#endif |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
#define LF_BACKOFF my_yield_processor() |
|||
#else /* cleanup */ |
|||
|
|||
#undef IL_EXCHG_ADD32 |
|||
#undef IL_COMP_EXCHG32 |
|||
#undef IL_COMP_EXCHGptr |
|||
#undef IL_EXCHG32 |
|||
#undef IL_EXCHGptr |
|||
|
|||
#endif |
@ -0,0 +1,92 @@ |
|||
/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|||
|
|||
#include <my_global.h> |
|||
#include <my_sys.h> |
|||
#include <my_atomic.h> |
|||
#include <tap.h> |
|||
|
|||
volatile uint32 bad; |
|||
pthread_attr_t thr_attr; |
|||
pthread_mutex_t mutex; |
|||
pthread_cond_t cond; |
|||
uint running_threads; |
|||
|
|||
void do_tests(); |
|||
|
|||
void test_concurrently(const char *test, pthread_handler handler, int n, int m) |
|||
{ |
|||
pthread_t t; |
|||
ulonglong now= my_getsystime(); |
|||
|
|||
bad= 0; |
|||
|
|||
diag("Testing %s with %d threads, %d iterations... ", test, n, m); |
|||
for (running_threads= n ; n ; n--) |
|||
{ |
|||
if (pthread_create(&t, &thr_attr, handler, &m) != 0) |
|||
{ |
|||
diag("Could not create thread"); |
|||
abort(); |
|||
} |
|||
} |
|||
pthread_mutex_lock(&mutex); |
|||
while (running_threads) |
|||
pthread_cond_wait(&cond, &mutex); |
|||
pthread_mutex_unlock(&mutex); |
|||
|
|||
now= my_getsystime()-now; |
|||
ok(!bad, "tested %s in %g secs (%d)", test, ((double)now)/1e7, bad); |
|||
} |
|||
|
|||
int main(int argc __attribute__((unused)), char **argv) |
|||
{ |
|||
MY_INIT("thd_template"); |
|||
|
|||
if (argv[1] && *argv[1]) |
|||
DBUG_SET_INITIAL(argv[1]); |
|||
|
|||
pthread_mutex_init(&mutex, 0); |
|||
pthread_cond_init(&cond, 0); |
|||
pthread_attr_init(&thr_attr); |
|||
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); |
|||
|
|||
#ifdef MY_ATOMIC_MODE_RWLOCKS |
|||
#if defined(HPUX11) || defined(__POWERPC__) /* showed to be very slow (scheduler-related) */ |
|||
#define CYCLES 300 |
|||
#else |
|||
#define CYCLES 3000 |
|||
#endif |
|||
#else |
|||
#define CYCLES 3000 |
|||
#endif |
|||
#define THREADS 30 |
|||
|
|||
diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE); |
|||
|
|||
do_tests(); |
|||
|
|||
/* |
|||
workaround until we know why it crashes randomly on some machine |
|||
(BUG#22320). |
|||
*/ |
|||
sleep(2); |
|||
pthread_mutex_destroy(&mutex); |
|||
pthread_cond_destroy(&cond); |
|||
pthread_attr_destroy(&thr_attr); |
|||
my_end(0); |
|||
return exit_status(); |
|||
} |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue