(original) (raw)
/******************************************************************************************************************************* * * Program: raw_s11n_page.cpp * Author: A. Sch�sser * Date: 2014-01-17 * * Build: g++ [-DPPC64|-DAIX] raw_s11n_page.cpp -lpthread -o raw_ * * Usage: raw_ [number of iterations] * where [number_of_iterations]: default = 1000 * endless = -1 * * Notes: Currently Linux X86, Linux PPC64 and AIX PPC64 are supported * Original Test by Doug Lea: http://www.cs.umd.edu/\~pugh/java/memoryModel/ReadAfterWrite.java * S11n Page: http://home.comcast.net/\~pjbishop/Dave/Asymmetric-Dekker-Synchronization.txt * *******************************************************************************************************************************/ #include #include #include #include #include #include #include #include // Config: Switch between normal read after write (1) or // read after write with serialization page (0) #define USE_MEMBAR 0 // Result arrays #define NUM_ELEMENTS 10000000 int AA[NUM_ELEMENTS]; int BB[NUM_ELEMENTS]; // Exchange fields volatile int a; int padding[128]; // force b on different cache line volatile int b; // Serialization page long long page_size; char *s11n_page = NULL; // Trapped counter long long trapped; // Platform dependent memory fence operation #ifdef PPC64 // GCC version #define MFENCE __asm__ volatile ("sync") #elif defined AIX // XLC version #define MFENCE __asm__ __volatile__ ("sync" : : : " ") #else // GCC/X86 version #define MFENCE __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory") #endif // ---------------------------------------------------------------------------- // T1: Write b and AA, read a void *write_b_AA(void *env) { for (int i = 0; i < NUM_ELEMENTS; i++) { b = i; #if !USE_MEMBAR *s11n_page = 0; #else MFENCE; #endif AA[i] = a; } return NULL; } // ---------------------------------------------------------------------------- // T2: Write a and BB, read b void *write_a_BB(void *env) { for (int i = 0; i < NUM_ELEMENTS; i++) { a = i; MFENCE; #if !USE_MEMBAR bool res; res = mprotect(s11n_page, page_size, PROT_NONE) == 0; assert(res == true); res = mprotect(s11n_page, page_size, PROT_WRITE | PROT_READ) == 0; assert(res == true); #endif BB[i] = b; } return NULL; } // ---------------------------------------------------------------------------- // Sighandler, do nothing for SIGSEGV since we only trap for serialization page access void sigsegv_handler(int sig) { trapped++; return; } // ---------------------------------------------------------------------------- void alloc_serialization_page() { // Alloc memory for serialization page, align address and install signal handler page_size = getpagesize(); printf("array size: %d\n", NUM_ELEMENTS); printf("page size: %llx\n", page_size); s11n_page = (char* ) malloc(10 * page_size); printf("allocated: %p-%p\n", s11n_page, s11n_page + 10*page_size); unsigned long long align = (unsigned long long) s11n_page; align = (align + 2 * page_size) & ~(page_size-1); s11n_page = (char *) align; printf("page address: %p\n\n", s11n_page); // Install signal handler #ifdef AIX struct sigaction sa; sa.sa_handler = sigsegv_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; /* Restart functions if interrupted by handler */ if (sigaction(SIGSEGV, &sa, NULL) == -1) { printf("Failed to install sig handler"); exit(1); } #else signal(SIGSEGV, sigsegv_handler); #endif } // ---------------------------------------------------------------------------- main(int argc, char** argv) { printf("RAW with serialization page test\n\n"); alloc_serialization_page(); // Parse command line long num_iterations = 1000; if (argc > 1) num_iterations = atoi(argv[1]); printf("Runnig read_after_cas test %dx...\n", num_iterations); // Run the test in a loop for (unsigned long long run = 0; run < num_iterations; run++) { // Init a = -1; b = -1; memset(AA, NUM_ELEMENTS*sizeof(int), 0); memset(BB, NUM_ELEMENTS*sizeof(int), 0); // Start 2 threads trapped = 0; pthread_t p1, p2; pthread_create (&p1, NULL, write_a_BB, (void *) run); pthread_create (&p2, NULL, write_b_AA, (void *) run); // Sync pthread_join (p1, NULL); pthread_join (p2, NULL); // Check result // The following condition must hold: // BB[AA[i] + 1] >= i int checked_entries = 0; int maxAA = -1, maxBB = -1; for (int i = 0; i < NUM_ELEMENTS; i++) { int j = AA[i] + 1; if (j < NUM_ELEMENTS && BB[j] < i) { printf("failed.\n"); printf("ERROR:\n"); printf("expected: i=%d <= BB[AA[i] + 1]=%d\n", i, BB[j]); exit(1); } if (j < NUM_ELEMENTS && AA[i] != -1 && BB[j] != -1) { checked_entries++; } // Record the progress of each thread if (AA[i] > maxAA) maxAA = AA[i]; if (BB[i] > maxBB) maxBB = BB[i]; } if (checked_entries == 0) { printf("[%05lld] no outcome (no entries checked).\n", run); } else { printf("[%05lld] passed (checked entries: %d, trapped: %lld, maxAA: %d, maxBB: %d).\n", run, checked_entries, trapped, maxAA, maxBB); } } }