Line data Source code
1 : //: multi-level barrier code; predefined to a max of 64 threads, as below 2 : 3 : // We need to define the Log2 of the maximum number of threads: 4 : #define LOG2MAX 6 5 : #define NTHREADS 64 6 : 7 : #include <sched.h> 8 : #include <math.h> 9 : #include <stdlib.h> 10 : #include <time.h> 11 : #include <stdio.h> 12 : #include <omp.h> 13 : #include <stdbool.h> 14 : #include <stdint.h> 15 : 16 : // utility functions: 17 0 : int ipow2 (int val) { 18 0 : int result = 1; 19 0 : while (val > 0) { 20 0 : result *= 2; 21 0 : --val; 22 : } 23 0 : return result; 24 : } 25 : 26 : // Define the data associated with a global barrier: 27 : typedef struct gbt { 28 : volatile bool LocalFlags [2][LOG2MAX]; 29 : volatile bool *PartnerFlags [2][LOG2MAX]; 30 : bool sense; 31 : int parity; 32 : int id; 33 : } GBarrier_Type; 34 : 35 : // Define a singular type for the global barrier: 36 : typedef struct gb { 37 : GBarrier_Type threadData[NTHREADS]; 38 : int numThreads; 39 : int log2Threads; 40 : } GBarrier; 41 : 42 33024 : void initializeThread(GBarrier_Type *threadData, int thread, int numThreads) { 43 : // Local loop variables: (p)arity, (r)ound and (x) [temporary] 44 33024 : int p, r; 45 33024 : unsigned int x; 46 : 47 : // local log2 threads: 48 33024 : int log2Threads = ceil(log2(numThreads)); 49 : 50 33024 : threadData[thread].id = thread; 51 33024 : threadData[thread].sense = true; 52 33024 : threadData[thread].parity = 0; 53 : 54 99072 : for (p = 0; p < 2; p++) { 55 66048 : for (r = 0; r < log2Threads; r++) { 56 0 : x = (threadData[thread].id + ipow2(r)) % numThreads; 57 0 : threadData[thread].LocalFlags[p][r] = 0; 58 0 : threadData[thread].PartnerFlags[p][r] = &threadData[x].LocalFlags[p][r]; 59 : } 60 : } 61 33024 : } 62 : 63 3013632 : void gbarrier_synchronize(GBarrier* b, int thread) 64 : { 65 : // Local: 66 3013632 : int i; 67 : 68 : // Get the pointer to our thread's data: 69 3013632 : GBarrier_Type *my = &b->threadData[thread]; 70 : 71 : // Loop through the log2 rounds: 72 3013632 : for (i = 0; i < b->log2Threads; i++) { 73 0 : *my->PartnerFlags[my->parity][i] = my->sense; 74 : 75 0 : while (my->LocalFlags[my->parity][i] != my->sense) { sched_yield(); } 76 : } 77 : 78 : // Reverse the sense for reuse on parity=1 79 3013632 : if (my->parity == 1) { my->sense = !my->sense; } 80 : 81 : // Swap our parity between 0 & 1: 82 3013632 : my->parity = 1 - my->parity; 83 3013632 : } 84 : 85 33024 : void gbarrier_initialize(GBarrier **ptb, int numThreads) { 86 : // Local variables: 87 33024 : int t; 88 : 89 33024 : GBarrier *b; 90 33024 : (*ptb) = malloc(sizeof(GBarrier)); 91 33024 : b = (*ptb); 92 : 93 33024 : b->numThreads = numThreads; 94 33024 : b->log2Threads = ceil(log2(b->numThreads)); 95 : 96 66048 : for (t = 0; t < b->numThreads; t++) { 97 33024 : initializeThread(b->threadData, t, b->numThreads); 98 : } 99 33024 : } 100 : 101 0 : void gbarrier_print(GBarrier *b) { 102 0 : printf("GBarrier Info: %d threads \n", b->numThreads); 103 0 : } 104 : 105 8448 : void gbarrier_free(GBarrier **ptb) { 106 8448 : GBarrier *b = (*ptb); 107 8448 : free(b); 108 8448 : } 109 :