From 9f61d1d8a3fa1e83b5067001dd26f306884c1e92 Mon Sep 17 00:00:00 2001 From: Brian Barrett Date: Thu, 27 Jan 2005 21:08:35 +0000 Subject: [PATCH] * Clean up some problems with the atomic operation interface discovered during testing. In particular, we can't have a cmpset macro that can deal with pointers without some really evil voodoo. So have a different macro for pointers * Add more detailed testing of the atomics using AM's test framework. More to come... This commit was SVN r4191. --- configure.ac | 2 + src/asm/Makefile.am | 9 +- src/asm/test/Makefile.am | 79 ++++++++ src/asm/{ => test}/atomic-test.c | 251 +++++++++---------------- src/asm/test/atomic_barrier.c | 36 ++++ src/asm/test/atomic_cmpset_32_serial.c | 56 ++++++ src/asm/test/atomic_cmpset_64_serial.c | 61 ++++++ src/asm/test/atomic_spinlock.c | 106 +++++++++++ src/asm/test/atomic_spinlock_2.c | 33 ++++ src/asm/test/atomic_spinlock_5.c | 33 ++++ src/asm/test/atomic_spinlock_8.c | 33 ++++ src/asm/test/atomic_spinlock_serial.c | 33 ++++ src/include/sys/atomic.h | 74 ++++++-- src/include/sys/atomic_impl.h | 81 ++++++++ 14 files changed, 700 insertions(+), 187 deletions(-) create mode 100644 src/asm/test/Makefile.am rename src/asm/{ => test}/atomic-test.c (52%) create mode 100644 src/asm/test/atomic_barrier.c create mode 100644 src/asm/test/atomic_cmpset_32_serial.c create mode 100644 src/asm/test/atomic_cmpset_64_serial.c create mode 100644 src/asm/test/atomic_spinlock.c create mode 100644 src/asm/test/atomic_spinlock_2.c create mode 100644 src/asm/test/atomic_spinlock_5.c create mode 100644 src/asm/test/atomic_spinlock_8.c create mode 100644 src/asm/test/atomic_spinlock_serial.c diff --git a/configure.ac b/configure.ac index b5b4022f98..83f200fb3e 100644 --- a/configure.ac +++ b/configure.ac @@ -1489,5 +1489,7 @@ AC_CONFIG_FILES([ src/tools/ompid/Makefile src/tools/openmpi/Makefile src/tools/wrappers/Makefile + + src/asm/test/Makefile ]) AC_OUTPUT diff --git a/src/asm/Makefile.am b/src/asm/Makefile.am index df7d07cbf0..be21f0cff5 100644 --- a/src/asm/Makefile.am +++ b/src/asm/Makefile.am @@ -14,6 +14,8 @@ include $(top_srcdir)/config/Makefile.options +SUBDIRS = . test + ###################################################################### # # This is a bit complicated. If there is anything in the library, @@ -57,13 +59,6 @@ EXTRA_DIST = \ ###################################################################### -TESTS = atomic-test -check_PROGRAMS = atomic-test -atomic_test_SOURCES = atomic-test.c -atomic_test_LDADD = libasm.la - -###################################################################### - clean-local: rm -f atomic-asm.s diff --git a/src/asm/test/Makefile.am b/src/asm/test/Makefile.am new file mode 100644 index 0000000000..8998be1fd7 --- /dev/null +++ b/src/asm/test/Makefile.am @@ -0,0 +1,79 @@ +# +# Copyright (c) 2004-2005 The Trustees of Indiana University. +# All rights reserved. +# Copyright (c) 2004-2005 The Trustees of the University of Tennessee. +# All rights reserved. +# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, +# University of Stuttgart. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +include $(top_srcdir)/config/Makefile.options + +noinst_HEADERS = atomic_test.h + +TESTS = \ + atomic_barrier \ + atomic_spinlock_serial \ + atomic_spinlock_2 \ + atomic_spinlock_5 \ + atomic_spinlock_8 \ + atomic_cmpset_32_serial \ + atomic_cmpset_64_serial \ + atomic-test + +check_PROGRAMS = \ + atomic_barrier \ + atomic_spinlock_serial \ + atomic_spinlock_2 \ + atomic_spinlock_5 \ + atomic_spinlock_8 \ + atomic_cmpset_32_serial \ + atomic_cmpset_64_serial \ + atomic-test + +###################################################################### + +atomic_barrier_SOURCES = atomic_barrier.c +atomic_barrier_LDADD = ../libasm.la + +###################################################################### + +atomic_spinlock_serial_SOURCES = \ + atomic_spinlock_serial.c \ + atomic_spinlock.c +atomic_spinlock_serial_LDADD = ../libasm.la + +atomic_spinlock_2_SOURCES = \ + atomic_spinlock_2.c \ + atomic_spinlock.c +atomic_spinlock_2_LDADD = ../libasm.la + +atomic_spinlock_5_SOURCES = \ + atomic_spinlock_5.c \ + atomic_spinlock.c +atomic_spinlock_5_LDADD = ../libasm.la + +atomic_spinlock_8_SOURCES = \ + atomic_spinlock_8.c \ + atomic_spinlock.c +atomic_spinlock_8_LDADD = ../libasm.la + +###################################################################### + +atomic_cmpset_32_serial_SOURCES = atomic_cmpset_32_serial.c +atomic_cmpset_32_serial_LDADD = ../libasm.la + +###################################################################### + +atomic_cmpset_64_serial_SOURCES = atomic_cmpset_64_serial.c +atomic_cmpset_64_serial_LDADD = ../libasm.la + +###################################################################### + +atomic_test_SOURCES = atomic-test.c +atomic_test_LDADD = ../libasm.la diff --git a/src/asm/atomic-test.c b/src/asm/test/atomic-test.c similarity index 52% rename from src/asm/atomic-test.c rename to src/asm/test/atomic-test.c index 3824409cd8..883f09b621 100644 --- a/src/asm/atomic-test.c +++ b/src/asm/test/atomic-test.c @@ -1,6 +1,20 @@ -#undef OMPI_BUILDING +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +#undef OMPI_BUILDING #include "ompi_config.h" + #include #include #ifdef HAVE_PTHREAD_H @@ -13,102 +27,6 @@ #include "include/sys/atomic.h" -/** - * A testing support library to provide uniform reporting output - */ - -static int ompi_n_tests; -static int ompi_n_success; -static int ompi_n_failures; -static char *ompi_description; - -static void test_init(char *a) -{ - /* local variables */ - size_t len; - - /* save the descriptive string */ - len = strlen(a); - ompi_description = (char *) malloc(len + 1); - assert(ompi_description); - - strcpy(ompi_description, a); - - /* initialize counters */ - ompi_n_tests = 0; - ompi_n_success = 0; - ompi_n_failures = 0; - - return; - -} - - -static void test_success(void) -{ - ompi_n_tests++; - ompi_n_success++; -} - - -static void test_failure(char *a) -{ - ompi_n_tests++; - ompi_n_failures++; - - fprintf(stderr, " Failure : "); - fprintf(stderr, a); - fprintf(stderr, "\n"); - fflush(stderr); -} - - -static int test_verify_int(int expected_result, int test_result) -{ - int return_value; - - return_value = 1; - if (expected_result != test_result) { - test_failure("Comparison failure"); - fprintf(stderr, " Expected result: %d\n", expected_result); - fprintf(stderr, " Test result: %d\n", test_result); - fflush(stderr); - return_value = 0; - } else { - test_success(); - } - - return return_value; -} - - -static int test_finalize(void) -{ - int return_value; - - return_value = 1; - - if (ompi_n_tests == ompi_n_success) { - fprintf(stderr, "SUPPORT: OMPI Test Passed: %s: (%d tests)\n", - ompi_description, ompi_n_tests); - fflush(stderr); - } else { - fprintf(stderr, - "SUPPORT: OMPI Test failed: %s (%d of %d failed)\n", - ompi_description, ompi_n_failures, ompi_n_tests); - fflush(stderr); - return_value = 0; - } - - return return_value; -} - - -/* note this is for additional output that does NOT go to STDERR but STDOUT */ -static void test_comment (char* userstr) -{ - fprintf(stdout, "%s:%s\n", ompi_description, userstr); -} /* default options */ @@ -122,7 +40,7 @@ int32_t val32; int32_t old32; int32_t new32; -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 volatile int64_t vol64; int64_t val64; int64_t old64; @@ -144,7 +62,7 @@ static void help(void) printf("Usage: threadtest [flags]\n" "\n" " Flags may be any of\n" -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 " -l do 64-bit tests\n" #endif " -r NREPS number of repetitions\n" @@ -153,7 +71,7 @@ static void help(void) " -h print this info\n" "\n" " Numbers may be postfixed with 'k' or 'm'\n\n"); -#ifndef ENABLE_64_BIT +#ifndef OMPI_HAVE_ATOMIC_MATH_64 printf(" 64-bit tests are not enabled in this build of the tests\n\n"); #endif @@ -216,7 +134,7 @@ static void *thread_main(void *arg) for (i = 0; i < nreps; i++) { ompi_atomic_add_32(&val32, 5); -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 if (enable_64_bit_tests) { ompi_atomic_add_64(&val64, 5); } @@ -231,20 +149,20 @@ static void *thread_main(void *arg) int main(int argc, char *argv[]) { int c; +#if HAVE_PTHREAD_H int tid; pthread_t *th; +#endif /* option processing */ - test_init("atomic operations"); - while ((c = getopt(argc, argv, "hlr:t:v")) != -1) { switch (c) { case 'h': help(); break; case 'l': -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 enable_64_bit_tests = 1; #else usage(); @@ -280,144 +198,144 @@ int main(int argc, char *argv[]) /* -- cmpset 32-bit tests -- */ vol32 = 42, old32 = 42, new32 = 50; - test_verify_int(ompi_atomic_cmpset_32(&vol32, old32, new32), 1); - test_verify_int(vol32, new32); + assert(ompi_atomic_cmpset_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); vol32 = 42, old32 = 420, new32 = 50; - test_verify_int(ompi_atomic_cmpset_32(&vol32, old32, new32), 0); - test_verify_int(vol32, 42); + assert(ompi_atomic_cmpset_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); vol32 = 42, old32 = 42, new32 = 50; - test_verify_int(ompi_atomic_cmpset_acq_32(&vol32, old32, new32), 1); - test_verify_int(vol32, new32); + assert(ompi_atomic_cmpset_acq_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); vol32 = 42, old32 = 420, new32 = 50; - test_verify_int(ompi_atomic_cmpset_acq_32(&vol32, old32, new32), 0); - test_verify_int(vol32, 42); + assert(ompi_atomic_cmpset_acq_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); vol32 = 42, old32 = 42, new32 = 50; - test_verify_int(ompi_atomic_cmpset_rel_32(&vol32, old32, new32), 1); - test_verify_int(vol32, new32); + assert(ompi_atomic_cmpset_rel_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); vol32 = 42, old32 = 420, new32 = 50; - test_verify_int(ompi_atomic_cmpset_rel_32(&vol32, old32, new32), 0); - test_verify_int(vol32, 42); + assert(ompi_atomic_cmpset_rel_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); /* -- cmpset 64-bit tests -- */ -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 if (enable_64_bit_tests) { verbose("64 bit serial tests\n"); vol64 = 42, old64 = 42, new64 = 50; - test_verify_int(1, ompi_atomic_cmpset_64(&vol64, old64, new64)); - test_verify_int(new64, vol64); + assert(1 == ompi_atomic_cmpset_64(&vol64, old64, new64)); + assert(new64 == vol64); verbose("64 bit serial test 2\n"); vol64 = 42, old64 = 420, new64 = 50; - test_verify_int(ompi_atomic_cmpset_64(&vol64, old64, new64), 0); - test_verify_int(vol64, 42); + assert(ompi_atomic_cmpset_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); vol64 = 42, old64 = 42, new64 = 50; - test_verify_int(ompi_atomic_cmpset_acq_64(&vol64, old64, new64), 1); - test_verify_int(vol64, new64); + assert(ompi_atomic_cmpset_acq_64(&vol64, old64, new64) == 1); + assert(vol64 == new64); vol64 = 42, old64 = 420, new64 = 50; - test_verify_int(ompi_atomic_cmpset_acq_64(&vol64, old64, new64), 0); - test_verify_int(vol64, 42); + assert(ompi_atomic_cmpset_acq_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); vol64 = 42, old64 = 42, new64 = 50; - test_verify_int(ompi_atomic_cmpset_rel_64(&vol64, old64, new64), 1); - test_verify_int(vol64, new64); + assert(ompi_atomic_cmpset_rel_64(&vol64, old64, new64) == 1); + assert(vol64 == new64); vol64 = 42, old64 = 420, new64 = 50; - test_verify_int(ompi_atomic_cmpset_rel_64(&vol64, old64, new64), 0); - test_verify_int(vol64, 42); + assert(ompi_atomic_cmpset_rel_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); } #endif /* -- cmpset int tests -- */ volint = 42, oldint = 42, newint = 50; - test_verify_int(ompi_atomic_cmpset(&volint, oldint, newint), 1); - test_verify_int(volint, newint); + assert(ompi_atomic_cmpset(&volint, oldint, newint) == 1); + assert(volint ==newint); volint = 42, oldint = 420, newint = 50; - test_verify_int(ompi_atomic_cmpset(&volint, oldint, newint), 0); - test_verify_int(volint, 42); + assert(ompi_atomic_cmpset(&volint, oldint, newint) == 0); + assert(volint == 42); volint = 42, oldint = 42, newint = 50; - test_verify_int(ompi_atomic_cmpset_acq(&volint, oldint, newint), 1); - test_verify_int(volint, newint); + assert(ompi_atomic_cmpset_acq(&volint, oldint, newint) == 1); + assert(volint == newint); volint = 42, oldint = 420, newint = 50; - test_verify_int(ompi_atomic_cmpset_acq(&volint, oldint, newint), 0); - test_verify_int(volint, 42); + assert(ompi_atomic_cmpset_acq(&volint, oldint, newint) == 0); + assert(volint == 42); volint = 42, oldint = 42, newint = 50; - test_verify_int(ompi_atomic_cmpset_rel(&volint, oldint, newint), 1); - test_verify_int(volint, newint); + assert(ompi_atomic_cmpset_rel(&volint, oldint, newint) == 1); + assert(volint == newint); volint = 42, oldint = 420, newint = 50; - test_verify_int(ompi_atomic_cmpset_rel(&volint, oldint, newint), 0); - test_verify_int(volint, 42); + assert(ompi_atomic_cmpset_rel(&volint, oldint, newint) == 0); + assert(volint == 42); /* -- cmpset ptr tests -- */ volptr = (void *) 42, oldptr = (void *) 42, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset(&volptr, oldptr, newptr), 1); - test_verify_int(volptr, newptr); + assert(ompi_atomic_cmpset_ptr(&volptr, oldptr, newptr) == 1); + assert(volptr == newptr); volptr = (void *) 42, oldptr = (void *) 420, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset(&volptr, oldptr, newptr), 0); - test_verify_int(volptr, (void *) 42); + assert(ompi_atomic_cmpset_ptr(&volptr, oldptr, newptr) == 0); + assert(volptr == (void *) 42); volptr = (void *) 42, oldptr = (void *) 42, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset_acq(&volptr, oldptr, newptr), 1); - test_verify_int(volptr, newptr); + assert(ompi_atomic_cmpset_acq_ptr(&volptr, oldptr, newptr) == 1); + assert(volptr == newptr); volptr = (void *) 42, oldptr = (void *) 420, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset_acq(&volptr, oldptr, newptr), 0); - test_verify_int(volptr, (void *) 42); + assert(ompi_atomic_cmpset_acq_ptr(&volptr, oldptr, newptr) == 0); + assert(volptr == (void *) 42); volptr = (void *) 42, oldptr = (void *) 42, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset_rel(&volptr, oldptr, newptr), 1); - test_verify_int(volptr, newptr); + assert(ompi_atomic_cmpset_rel_ptr(&volptr, oldptr, newptr) == 1); + assert(volptr == newptr); volptr = (void *) 42, oldptr = (void *) 420, newptr = (void *) 50; - test_verify_int(ompi_atomic_cmpset_rel(&volptr, oldptr, newptr), 0); - test_verify_int(volptr, (void *) 42); + assert(ompi_atomic_cmpset_rel_ptr(&volptr, oldptr, newptr) == 0); + assert(volptr == (void *) 42); /* -- add_32 tests -- */ val32 = 42; - test_verify_int(ompi_atomic_add_32(&val32, 5), (42 + 5)); - test_verify_int((42 + 5), val32); + assert(ompi_atomic_add_32(&val32, 5) == (42 + 5)); + assert((42 + 5) == val32); /* -- add_64 tests -- */ -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 if (enable_64_bit_tests) { val64 = 42; - test_verify_int(ompi_atomic_add_64(&val64, 5), (42 + 5)); - test_verify_int((42 + 5), val64); + assert(ompi_atomic_add_64(&val64, 5) == (42 + 5)); + assert((42 + 5) == val64); } #endif /* -- add_int tests -- */ valint = 42; ompi_atomic_add(&valint, 5); - test_verify_int((42 + 5), valint); + assert((42 + 5) == valint); /* threaded tests */ val32 = 0; -#ifdef ENABLE_64_BIT +#if OMPI_HAVE_ATOMIC_MATH_64 val64 = 0ul; #endif valint = 0; /* -- create the thread set -- */ - +#if HAVE_PTHREAD_H th = (pthread_t *) malloc(nthreads * sizeof(pthread_t)); if (!th) { perror("malloc"); @@ -443,15 +361,14 @@ int main(int argc, char *argv[]) } free(th); - test_verify_int((5 * nthreads * nreps), val32); -#ifdef ENABLE_64_BIT + assert((5 * nthreads * nreps) == val32); +#if OMPI_HAVE_ATOMIC_MATH_64 if (enable_64_bit_tests) { - test_verify_int((5 * nthreads * nreps), val64); + assert((5 * nthreads * nreps) == val64); } #endif - test_verify_int((5 * nthreads * nreps), valint); - - test_finalize(); + assert((5 * nthreads * nreps) == valint); +#endif return 0; } diff --git a/src/asm/test/atomic_barrier.c b/src/asm/test/atomic_barrier.c new file mode 100644 index 0000000000..25db99336f --- /dev/null +++ b/src/asm/test/atomic_barrier.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int +main(int argc, char *argv[]) +{ + /* there really isn't a great way to test that the barriers + actually barrier, but at least make sure they don't kill the + machine.*/ + + ompi_atomic_mb(); + ompi_atomic_rmb(); + ompi_atomic_wmb(); + + return 0; +} + diff --git a/src/asm/test/atomic_cmpset_32_serial.c b/src/asm/test/atomic_cmpset_32_serial.c new file mode 100644 index 0000000000..7ff4dfb33a --- /dev/null +++ b/src/asm/test/atomic_cmpset_32_serial.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" + +volatile int32_t vol32; +int32_t val32; +int32_t old32; +int32_t new32; + +int +main(int argc, char *argv[]) +{ + + vol32 = 42, old32 = 42, new32 = 50; + assert(ompi_atomic_cmpset_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); + + vol32 = 42, old32 = 420, new32 = 50; + assert(ompi_atomic_cmpset_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); + + vol32 = 42, old32 = 42, new32 = 50; + assert(ompi_atomic_cmpset_acq_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); + + vol32 = 42, old32 = 420, new32 = 50; + assert(ompi_atomic_cmpset_acq_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); + + vol32 = 42, old32 = 42, new32 = 50; + assert(ompi_atomic_cmpset_rel_32(&vol32, old32, new32) == 1); + assert(vol32 == new32); + + vol32 = 42, old32 = 420, new32 = 50; + assert(ompi_atomic_cmpset_rel_32(&vol32, old32, new32) == 0); + assert(vol32 == 42); + + return 0; +} diff --git a/src/asm/test/atomic_cmpset_64_serial.c b/src/asm/test/atomic_cmpset_64_serial.c new file mode 100644 index 0000000000..214e03c239 --- /dev/null +++ b/src/asm/test/atomic_cmpset_64_serial.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" + +#if OMPI_HAVE_ATOMIC_MATH_64 +volatile int64_t vol64; +int64_t val64; +int64_t old64; +int64_t new64; +#endif + +int +main(int argc, char *argv[]) +{ +#if OMPI_HAVE_ATOMIC_MATH_64 + vol64 = 42, old64 = 42, new64 = 50; + assert(1 == ompi_atomic_cmpset_64(&vol64, old64, new64)); + assert(new64 == vol64); + + vol64 = 42, old64 = 420, new64 = 50; + assert(ompi_atomic_cmpset_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); + + vol64 = 42, old64 = 42, new64 = 50; + assert(ompi_atomic_cmpset_acq_64(&vol64, old64, new64) == 1); + assert(vol64 == new64); + + vol64 = 42, old64 = 420, new64 = 50; + assert(ompi_atomic_cmpset_acq_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); + + vol64 = 42, old64 = 42, new64 = 50; + assert(ompi_atomic_cmpset_rel_64(&vol64, old64, new64) == 1); + assert(vol64 == new64); + + vol64 = 42, old64 = 420, new64 = 50; + assert(ompi_atomic_cmpset_rel_64(&vol64, old64, new64) == 0); + assert(vol64 == 42); + + return 0; +#else + return 77; +#endif +} diff --git a/src/asm/test/atomic_spinlock.c b/src/asm/test/atomic_spinlock.c new file mode 100644 index 0000000000..b2814243c5 --- /dev/null +++ b/src/asm/test/atomic_spinlock.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include +#ifdef HAVE_PTHREAD_H +#include +#endif +#include +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int atomic_verbose = 0; + +struct start_info { + int tid; + int count; + ompi_lock_t *lock; +}; + +static void* atomic_spinlock_start(void* arg) +{ + struct start_info *data = (struct start_info*) arg; + + return (void*) atomic_spinlock_test(data->lock, data->count, + data->tid); +} + + +int +atomic_spinlock_test_th(ompi_lock_t *lock, int count, int id, int thr_count) +{ +#if HAVE_PTHREAD_H + pthread_t *th; + int tid, ret = 0; + struct start_info *data; + + th = (pthread_t *) malloc(thr_count * sizeof(pthread_t)); + if (!th) { perror("malloc"); exit(EXIT_FAILURE); } + data = (struct start_info *) malloc(thr_count * sizeof(struct start_info)); + if (!th) { perror("malloc"); exit(EXIT_FAILURE); } + + for (tid = 0; tid < thr_count; tid++) { + data[tid].tid = tid; + data[tid].count = count; + data[tid].lock = lock; + + if (pthread_create(&th[tid], NULL, atomic_spinlock_start, (void *) &(data[tid])) != 0) { + perror("pthread_create"); + exit(EXIT_FAILURE); + } + } + + /* -- wait for the thread set to finish -- */ + for (tid = 0; tid < thr_count; tid++) { + void *thread_return; + + if (pthread_join(th[tid], &thread_return) != 0) { + perror("pthread_join"); + exit(EXIT_FAILURE); + } + + ret += (int) thread_return; + } + free(data); + free(th); + + return ret; +#else + return 77; +#endif +} + + +int +atomic_spinlock_test(ompi_lock_t *lock, int count, int id) +{ + int i; + + for (i = 0 ; i < count ; ++i) { + ompi_atomic_lock(lock); + if (atomic_verbose) { printf("id %03d has the lock (lock)\n", id); } + ompi_atomic_unlock(lock); + + while (ompi_atomic_trylock(lock)) { ; } + if (atomic_verbose) { printf("id %03d has the lock (trylock)\n", id); } + ompi_atomic_unlock(lock); + } + + return 0; +} diff --git a/src/asm/test/atomic_spinlock_2.c b/src/asm/test/atomic_spinlock_2.c new file mode 100644 index 0000000000..6556f4223b --- /dev/null +++ b/src/asm/test/atomic_spinlock_2.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int +main(int argc, char *argv[]) +{ + int ret = 77; + ompi_lock_t lock; + + ompi_atomic_init(&lock, OMPI_ATOMIC_UNLOCKED); + ret = atomic_spinlock_test_th(&lock, TEST_REPS, 0, 2); + + return ret; +} diff --git a/src/asm/test/atomic_spinlock_5.c b/src/asm/test/atomic_spinlock_5.c new file mode 100644 index 0000000000..9b357c1ade --- /dev/null +++ b/src/asm/test/atomic_spinlock_5.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int +main(int argc, char *argv[]) +{ + int ret = 77; + ompi_lock_t lock; + + ompi_atomic_init(&lock, OMPI_ATOMIC_UNLOCKED); + ret = atomic_spinlock_test_th(&lock, TEST_REPS, 0, 5); + + return ret; +} diff --git a/src/asm/test/atomic_spinlock_8.c b/src/asm/test/atomic_spinlock_8.c new file mode 100644 index 0000000000..0c9a018392 --- /dev/null +++ b/src/asm/test/atomic_spinlock_8.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int +main(int argc, char *argv[]) +{ + int ret = 77; + ompi_lock_t lock; + + ompi_atomic_init(&lock, OMPI_ATOMIC_UNLOCKED); + ret = atomic_spinlock_test_th(&lock, TEST_REPS, 0, 8); + + return ret; +} diff --git a/src/asm/test/atomic_spinlock_serial.c b/src/asm/test/atomic_spinlock_serial.c new file mode 100644 index 0000000000..1f04b9e560 --- /dev/null +++ b/src/asm/test/atomic_spinlock_serial.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#undef OMPI_BUILDING +#include "ompi_config.h" + +#include + +#include "include/sys/atomic.h" +#include "atomic_test.h" + +int +main(int argc, char *argv[]) +{ + int ret; + ompi_lock_t lock; + + ompi_atomic_init(&lock, OMPI_ATOMIC_UNLOCKED); + ret = atomic_spinlock_test(&lock, TEST_REPS, 0); + + return ret; +} diff --git a/src/include/sys/atomic.h b/src/include/sys/atomic.h index b93c160aa4..c64bc5ba7b 100644 --- a/src/include/sys/atomic.h +++ b/src/include/sys/atomic.h @@ -27,10 +27,10 @@ * The following #defines will be true / false based on * assembly support: * - * \c OMPI_HAVE_MEM_BARRIER atomic memory barriers - * \c OMPI_HAVE_ATOMIC_SPINLOCKS atomic spinlocks - * \c OMPI_HAVE_ATOMIC_MATH_32 if 32 bit add/sub/cmpset can be done "atomicly" - * \c OMPI_HAVE_ATOMIC_MATH_64 if 32 bit add/sub/cmpset can be done "atomicly" + * - \c OMPI_HAVE_MEM_BARRIER atomic memory barriers + * - \c OMPI_HAVE_ATOMIC_SPINLOCKS atomic spinlocks + * - \c OMPI_HAVE_ATOMIC_MATH_32 if 32 bit add/sub/cmpset can be done "atomicly" + * - \c OMPI_HAVE_ATOMIC_MATH_64 if 32 bit add/sub/cmpset can be done "atomicly" * * Note that for the Atomic math, atomic add/sub may be implemented as * C code using ompi_atomic_cmpset. The appearance of atomic @@ -82,6 +82,7 @@ extern "C" { #include "include/sys/sparc64/atomic.h" #endif +#ifndef DOXYGEN /* compare and set operations can't really be emulated from software, so if these defines aren't already set, they should be set to 0 now */ @@ -91,6 +92,7 @@ extern "C" { #ifndef OMPI_HAVE_ATOMIC_CMPSET_64 #define OMPI_HAVE_ATOMIC_CMPSET_64 0 #endif +#endif /* DOXYGEN */ /********************************************************************** * @@ -98,7 +100,7 @@ extern "C" { * but can't inline * *********************************************************************/ -#ifndef OMPI_HAVE_ATOMIC_MEM_BARRIER +#if !defined(OMPI_HAVE_ATOMIC_MEM_BARRIER) && !defined(DOXYGEN) /* no way to emulate in C code */ #define OMPI_HAVE_ATOMIC_MEM_BARRIER 0 #endif @@ -106,16 +108,38 @@ extern "C" { #if defined(DOXYGEN) || OMPI_HAVE_ATOMIC_MEM_BARRIER /** * Memory barrier + * + * Will use system-specific features to instruct the processor and + * memory controller that all writes and reads that have been posted + * before the call to \c ompi_atomic_mb() must appear to have + * completed before the next read or write. + * + * \note This can have some expensive side effects, including flushing + * the pipeline, preventing the cpu from reordering instructions, and + * generally grinding the memory controller's performance. Use only + * if you need *both* read and write barriers. */ void ompi_atomic_mb(void); /** * Read memory barrier + * + * Use system-specific features to instruct the processor and memory + * conrtoller that all reads that have been posted before the call to + * \c ompi_atomic_rmb() must appear to have been completed before the + * next read. Nothing is said about the ordering of writes when using + * \c ompi_atomic_rmb(). */ void ompi_atomic_rmb(void); /** * Write memory barrier. + * + * Use system-specific features to instruct the processor and memory + * conrtoller that all writes that have been posted before the call to + * \c ompi_atomic_rmb() must appear to have been completed before the + * next write. Nothing is said about the ordering of reads when using + * \c ompi_atomic_rmb(). */ void ompi_atomic_wmb(void); @@ -138,13 +162,12 @@ struct ompi_lock_t { }; typedef struct ompi_lock_t ompi_lock_t; -#ifndef OMPI_HAVE_ATOMIC_SPINLOCKS +#if !defined(OMPI_HAVE_ATOMIC_SPINLOCKS) && !defined(DOXYGEN) #define OMPI_HAVE_ATOMIC_SPINLOCKS (OMPI_HAVE_ATOMIC_CMPSET_32 || OMPI_HAVE_ATOMIC_CMPSET_64) #endif #if defined(DOXYGEN) || OMPI_HAVE_ATOMIC_SPINLOCKS - /** * Enumeration of lock states */ @@ -195,7 +218,7 @@ static inline void ompi_atomic_unlock(ompi_lock_t *lock); * Atomic math operations * *********************************************************************/ -#ifndef OMPI_HAVE_ATOMIC_CMPSET_32 +#if !defined(OMPI_HAVE_ATOMIC_CMPSET_32) && !defined(DOXYGEN) #define OMPI_HAVE_ATOMIC_CMPSET_32 0 #endif #if defined(DOXYGEN) || OMPI_HAVE_ATOMIC_CMPSET_32 @@ -208,7 +231,7 @@ int ompi_atomic_cmpset_rel_32(volatile int32_t *addr, int32_t oldval, #endif -#ifndef OMPI_HAVE_ATOMIC_CMPSET_64 +#if !defined(OMPI_HAVE_ATOMIC_CMPSET_64) && !defined(DOXYGEN) #define OMPI_HAVE_ATOMIC_CMPSET_64 0 #endif #if defined(DOXYGEN) || OMPI_HAVE_ATOMIC_CMPSET_64 @@ -220,7 +243,7 @@ int ompi_atomic_cmpset_rel_64(volatile int64_t *addr, int64_t oldval, int64_t newval); #endif -#ifndef OMPI_HAVE_ATOMIC_MATH_32 +#if !defined(OMPI_HAVE_ATOMIC_MATH_32) && !defined(DOXYGEN) /* define to 0 for these tests. WIll fix up later. */ #define OMPI_HAVE_ATOMIC_MATH_32 0 #endif @@ -277,11 +300,26 @@ static inline void ompi_atomic_add_xx(volatile void* addr, static inline void ompi_atomic_sub_xx(volatile void* addr, int32_t value, size_t length); +static inline int ompi_atomic_cmpset_ptr(volatile void* addr, + void* oldval, + void* newval); +static inline int ompi_atomic_cmpset_acq_ptr(volatile void* addr, + void* oldval, + void* newval); +static inline int ompi_atomic_cmpset_rel_ptr(volatile void* addr, + void* oldval, + void* newval); +static inline int ompi_atomic_add_pt(volatile void* addr, + void* delta); +static inline int ompi_atomic_sub_ptr(volatile void* addr, + void* delta); /** * Atomic compare and set of pointer with relaxed semantics. This - * macro detect at compile time the type of the first argument - * and choose the correct function to be called. + * macro detect at compile time the type of the first argument and + * choose the correct function to be called. + * + * \note This macro should only be used for integer types. * * @param addr Address of . * @param oldval Comparison value . @@ -293,12 +331,13 @@ static inline void ompi_atomic_sub_xx(volatile void* addr, ompi_atomic_cmpset_xx( (volatile void*)(ADDR), (int64_t)(OLDVAL), \ (int64_t)(NEWVAL), sizeof(*(ADDR)) ) - /** * Atomic compare and set of pointer with acquire semantics. This * macro detect at compile time the type of the first argument * and choose the correct function to be called. * + * \note This macro should only be used for integer types. + * * @param addr Address of . * @param oldval Comparison value . * @param newval New value to set if comparision is true . @@ -315,6 +354,8 @@ static inline void ompi_atomic_sub_xx(volatile void* addr, * macro detect at compile time the type of the first argument * and choose the correct function to b * + * \note This macro should only be used for integer types. + * * @param addr Address of . * @param oldval Comparison value . * @param newval New value to set if comparision is true . @@ -331,6 +372,8 @@ static inline void ompi_atomic_sub_xx(volatile void* addr, * macro detect at compile time the type of the first argument * and choose the correct function to be called. * + * \note This macro should only be used for integer types. + * * @param addr Address of * @param delta Value to add (converted to ). */ @@ -343,6 +386,8 @@ static inline void ompi_atomic_sub_xx(volatile void* addr, * macro detect at compile time the type of the first argument * and choose the correct function to be called. * + * \note This macro should only be used for integer types. + * * @param addr Address of * @param delta Value to substract (converted to ). */ @@ -366,4 +411,7 @@ static inline void ompi_atomic_sub_xx(volatile void* addr, } #endif + + + #endif /* OMPI_SYS_ATOMIC_H */ diff --git a/src/include/sys/atomic_impl.h b/src/include/sys/atomic_impl.h index af28f3a420..f6452a8107 100644 --- a/src/include/sys/atomic_impl.h +++ b/src/include/sys/atomic_impl.h @@ -221,6 +221,87 @@ ompi_atomic_sub_xx(volatile void* addr, int32_t value, size_t length) #endif /* (OMPI_HAVE_ATOMIC_CMPSET_32 || OMPI_HAVE_ATOMIC_CMPSET_64) */ +static inline int +ompi_atomic_cmpset_ptr(volatile void* addr, + void* oldval, + void* newval) +{ +#if SIZEOF_VOID_P == 4 && OMPI_HAVE_ATOMIC_CMPSET_32 + return ompi_atomic_cmpset_32((int32_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#elif SIZEOF_VOID_P == 8 && OMPI_HAVE_ATOMIC_CMPSET_64 + return ompi_atomic_cmpset_64((int64_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#else + abort(); + return 0; +#endif +} + + +static inline int +ompi_atomic_cmpset_acq_ptr(volatile void* addr, + void* oldval, + void* newval) +{ +#if SIZEOF_VOID_P == 4 && OMPI_HAVE_ATOMIC_CMPSET_32 + return ompi_atomic_cmpset_acq_32((int32_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#elif SIZEOF_VOID_P == 8 && OMPI_HAVE_ATOMIC_CMPSET_64 + return ompi_atomic_cmpset_acq_64((int64_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#else + abort(); + return 0; +#endif +} + + +static inline int ompi_atomic_cmpset_rel_ptr(volatile void* addr, + void* oldval, + void* newval) +{ +#if SIZEOF_VOID_P == 4 && OMPI_HAVE_ATOMIC_CMPSET_32 + return ompi_atomic_cmpset_rel_32((int32_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#elif SIZEOF_VOID_P == 8 && OMPI_HAVE_ATOMIC_CMPSET_64 + return ompi_atomic_cmpset_rel_64((int64_t*) addr, (unsigned long) oldval, + (unsigned long) newval); +#else + abort(); + return 0; +#endif +} + + +static inline int ompi_atomic_add_pt(volatile void* addr, + void* delta) +{ +#if SIZEOF_VOID_P == 4 && OMPI_HAVE_ATOMIC_CMPSET_32 + return ompi_atomic_add_32((int32_t*) addr, (unsigned long) delta); +#elif SIZEOF_VOID_P == 8 && OMPI_HAVE_ATOMIC_CMPSET_64 + return ompi_atomic_add_64((int64_t*) addr, (unsigned long) delta); +#else + abort(); + return 0; +#endif +} + + +static inline int ompi_atomic_sub_ptr(volatile void* addr, + void* delta) +{ +#if SIZEOF_VOID_P == 4 && OMPI_HAVE_ATOMIC_CMPSET_32 + return ompi_atomic_sub_32((int32_t*) addr, (unsigned long) delta); +#elif SIZEOF_VOID_P == 8 && OMPI_HAVE_ATOMIC_CMPSET_64 + return ompi_atomic_sub_64((int64_t*) addr, (unsigned long) delta); +#else + abort(); + return 0; +#endif +} + + /********************************************************************** * * Atomic spinlocks