/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ /* * (C) 2008 by Argonne National Laboratory. * See COPYRIGHT in top-level directory. */ /* * Uncomment this definition to disable the OPA library and instead use naive * (non-atomic) operations. This should cause failures. */ /* #define OPA_TEST_NAIVE */ #include "opa_test.h" /* * Uncomment these lines to disable only memory barriers, while leaving the rest * of the OPA functions intact. */ /* #ifdef OPA_write_barrier #undef OPA_write_barrier #endif #define OPA_write_barrier() ((void) 0) #ifdef OPA_read_barrier #undef OPA_read_barrier #endif #define OPA_read_barrier() ((void) 0) #ifdef OPA_read_write_barrier #undef OPA_read_write_barrier #endif #define OPA_read_write_barrier() ((void) 0) */ /* Definitions for test_barriers_linear_array */ #define LINEAR_ARRAY_NITER 4000000 #define LINEAR_ARRAY_LEN 100 typedef struct { OPA_int_t *shared_array; int master_thread; /* Whether this is the master thread */ } linear_array_t; /* Definitions for test_barriers_variables */ #define VARIABLES_NITER 4000000 #define VARIABLES_NVAR 10 typedef struct { OPA_int_t *v_0; OPA_int_t *v_1; OPA_int_t *v_2; OPA_int_t *v_3; OPA_int_t *v_4; OPA_int_t *v_5; OPA_int_t *v_6; OPA_int_t *v_7; OPA_int_t *v_8; OPA_int_t *v_9; int master_thread; /* Whether this is the master thread */ } variables_t; /* Definitions for test_barriers_scattered_array */ #define SCATTERED_ARRAY_SIZE 100000 #define SCATTERED_ARRAY_LOCS {254, 85920, 255, 35529, 75948, 75947, 253, 99999, 11111, 11112} /*------------------------------------------------------------------------- * Function: test_barriers_sanity * * Purpose: Essentially tests that memory barriers don't interfere with * normal single threaded operations. If this fails then * something is *very* wrong. * * Return: Success: 0 * Failure: 1 * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * goodell@, December 1, 2011: load-acquire/store-release sanity test * *------------------------------------------------------------------------- */ static int test_barriers_sanity(void) { OPA_int_t a; int b; OPA_ptr_t op; void *p; struct {int i;} obj = {0xabcdef}; TESTING("memory barrier sanity", 0); /* Store 0 in a and b */ OPA_store_int(&a, 0); OPA_write_barrier(); b = 0; OPA_read_write_barrier(); /* Add INT_MIN */ OPA_add_int(&a, INT_MIN); OPA_read_write_barrier(); b += INT_MIN; OPA_read_write_barrier(); /* Increment */ OPA_incr_int(&a); OPA_read_write_barrier(); b++; OPA_read_write_barrier(); /* Add INT_MAX */ OPA_add_int(&a, INT_MAX); OPA_read_write_barrier(); b += INT_MAX; OPA_read_write_barrier(); /* Decrement */ OPA_decr_int(&a); OPA_read_write_barrier(); b--; OPA_read_write_barrier(); /* Load the result, verify it is correct */ if(OPA_load_int(&a) != INT_MIN + 1 + INT_MAX - 1) TEST_ERROR; OPA_read_barrier(); if(b != OPA_load_int(&a)) TEST_ERROR; OPA_read_write_barrier(); /* Barriers are now the opposite of what they were before */ /* Store 0 in a */ OPA_store_int(&a, 0); OPA_read_barrier(); b = 0; /* Add INT_MAX */ OPA_add_int(&a, INT_MAX); b += INT_MAX; /* Decrement */ OPA_decr_int(&a); b--; /* Add INT_MIN */ OPA_add_int(&a, INT_MIN); b += INT_MIN; /* Increment */ OPA_incr_int(&a); b++; /* Load the result, verify it is correct */ if(OPA_load_int(&a) != INT_MAX - 1 + INT_MIN + 1) TEST_ERROR; OPA_write_barrier(); if(b != OPA_load_int(&a)) TEST_ERROR; /* now provide a quick sanity check that the load-acquire/store-release code * works (as in, successfully compiles and runs single-threaded, no * multithreading is checked here) */ OPA_store_int(&a, 5); b = OPA_load_acquire_int(&a); if (b != 5) TEST_ERROR; OPA_store_release_int(&a, 0); b = OPA_load_acquire_int(&a); if (b != 0) TEST_ERROR; OPA_store_ptr(&op, &obj); p = OPA_load_acquire_ptr(&op); if (p != &obj) TEST_ERROR; OPA_store_release_ptr(&op, NULL); p = OPA_load_acquire_ptr(&op); if (p != NULL) TEST_ERROR; PASSED(); return 0; error: return 1; } /* end test_barriers_sanity() */ #if defined(OPA_HAVE_PTHREAD_H) /*------------------------------------------------------------------------- * Function: test_barriers_linear_array_write * * Purpose: Helper (write thread) routine for test_barriers_linear_array. * Writes successive increments to the shared array with memory * barriers between each increment. * * Return: NULL * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * *------------------------------------------------------------------------- */ static void *test_barriers_linear_array_write(void *_udata) { linear_array_t *udata = (linear_array_t *)_udata; OPA_int_t *shared_array = udata->shared_array; int niter = LINEAR_ARRAY_NITER / LINEAR_ARRAY_LEN / iter_reduction[curr_test]; int i, j; /* Main loop */ for(i=0; imaster_thread) return(NULL); else pthread_exit(NULL); } /* end test_barriers_linear_array_write() */ /*------------------------------------------------------------------------- * Function: test_barriers_linear_array_read * * Purpose: Helper (read thread) routine for test_barriers_linear_array. * Reads successive increments from the shared array in reverse * order with memory barriers between each read. * * Return: Success: NULL * Failure: non-NULL * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * *------------------------------------------------------------------------- */ static void *test_barriers_linear_array_read(void *_udata) { linear_array_t *udata = (linear_array_t *)_udata; OPA_int_t *shared_array = udata->shared_array; int read_buffer[LINEAR_ARRAY_LEN]; int niter = LINEAR_ARRAY_NITER / LINEAR_ARRAY_LEN / iter_reduction[curr_test]; int nerrors = 0; /* Number of errors */ int i, j; /* Main loop */ for(i=0; i= 0; j--) { read_buffer[j] = OPA_load_int(&shared_array[j]); /* Read barrier */ OPA_read_barrier(); } /* end for */ /* Verify that the values never increase when read back in forward * order */ for(j=1; jmaster_thread) return(nerrors ? (void *) 1 : NULL); else pthread_exit(nerrors ? (void *) 1 : NULL); } /* end test_barriers_linear_array_read() */ #endif /* OPA_HAVE_PTHREAD_H */ /*------------------------------------------------------------------------- * Function: test_barriers_linear_array * * Purpose: Tests memory barriers using simultaneous reads and writes to * a linear array. Launches nthreads threads split into read * and write threads. * * Return: Success: 0 * Failure: 1 * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * *------------------------------------------------------------------------- */ static int test_barriers_linear_array(void) { #if defined(OPA_HAVE_PTHREAD_H) pthread_t *threads = NULL; /* Threads */ pthread_attr_t ptattr; /* Thread attributes */ linear_array_t *thread_data = NULL; /* User data structs for each thread */ static OPA_int_t shared_array[LINEAR_ARRAY_LEN]; /* Array to operate on */ void *ret; /* Thread return value */ unsigned nthreads = num_threads[curr_test]; int nerrors = 0; /* number of errors */ int i; TESTING("memory barriers with linear array", nthreads); /* Allocate array of threads */ if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t)))) TEST_ERROR; /* Allocate array of thread data */ if(NULL == (thread_data = (linear_array_t *) calloc(nthreads, sizeof(linear_array_t)))) TEST_ERROR; /* Set threads to be joinable */ pthread_attr_init(&ptattr); pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE); /* Initialize shared array */ for(i=0; iv_0; v_1 = udata->v_1; v_2 = udata->v_2; v_3 = udata->v_3; v_4 = udata->v_4; v_5 = udata->v_5; v_6 = udata->v_6; v_7 = udata->v_7; v_8 = udata->v_8; v_9 = udata->v_9; /* Main loop */ for(i=0; imaster_thread) return(NULL); else pthread_exit(NULL); } /* end test_barriers_variables_write() */ /*------------------------------------------------------------------------- * Function: test_barriers_variables_read * * Purpose: Helper (read thread) routine for test_barriers_variables. * Reads successive increments from the variables in reverse * order with memory barriers between each read. * * Return: Success: NULL * Failure: non-NULL * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * *------------------------------------------------------------------------- */ static void *test_barriers_variables_read(void *_udata) { variables_t *udata = (variables_t *)_udata; OPA_int_t *v_0, *v_1, *v_2, *v_3, *v_4, *v_5, *v_6, *v_7, *v_8, *v_9; int read_buffer[VARIABLES_NVAR]; int niter = VARIABLES_NITER / VARIABLES_NVAR / iter_reduction[curr_test]; int nerrors = 0; /* Number of errors */ int i, j; /* Make local copies of the pointers in udata, to maximize the chance of the * compiler reordering instructions (if the barriers don't work) */ v_0 = udata->v_0; v_1 = udata->v_1; v_2 = udata->v_2; v_3 = udata->v_3; v_4 = udata->v_4; v_5 = udata->v_5; v_6 = udata->v_6; v_7 = udata->v_7; v_8 = udata->v_8; v_9 = udata->v_9; /* Main loop */ for(i=0; imaster_thread) return(nerrors ? (void *) 1 : NULL); else pthread_exit(nerrors ? (void *) 1 : NULL); } /* end test_barriers_variables_read() */ #endif /* OPA_HAVE_PTHREAD_H */ /*------------------------------------------------------------------------- * Function: test_barriers_variables * * Purpose: Tests memory barriers using simultaneous reads and writes to * a linear array. Launches nthreads threads split into read * and write threads. * * Return: Success: 0 * Failure: 1 * * Programmer: Neil Fortner * Wednesday, April 1, 2009 * * Modifications: * *------------------------------------------------------------------------- */ static int test_barriers_variables(void) { #if defined(OPA_HAVE_PTHREAD_H) pthread_t *threads = NULL; /* Threads */ pthread_attr_t ptattr; /* Thread attributes */ variables_t *thread_data = NULL; /* User data structs for each thread */ OPA_int_t v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9; void *ret; /* Thread return value */ unsigned nthreads = num_threads[curr_test]; int nerrors = 0; /* number of errors */ int i; TESTING("memory barriers with local variables", nthreads); /* Allocate array of threads */ if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t)))) TEST_ERROR; /* Allocate array of thread data */ if(NULL == (thread_data = (variables_t *) calloc(nthreads, sizeof(variables_t)))) TEST_ERROR; /* Set threads to be joinable */ pthread_attr_init(&ptattr); pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE); /* Initialize shared variables */ OPA_store_int(&v_0, 0); OPA_store_int(&v_1, 0); OPA_store_int(&v_2, 0); OPA_store_int(&v_3, 0); OPA_store_int(&v_4, 0); OPA_store_int(&v_5, 0); OPA_store_int(&v_6, 0); OPA_store_int(&v_7, 0); OPA_store_int(&v_8, 0); OPA_store_int(&v_9, 0); /* Initialize thread data structs */ for(i=0; i