[720] | 1 | ///////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 2 | // File : router.c |
---|
| 3 | // Date : november 2014 |
---|
| 4 | // author : Alain Greiner |
---|
| 5 | ///////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 6 | // This multi-threaded application illustrates "task-farm" parallelism. |
---|
| 7 | // It is described as a TCG (Task and Communication Graph). |
---|
| 8 | // It contains 2 + N threads : one "producer", one "consumer" and N "router"), |
---|
| 9 | // plus the "main" thread, that makes the global initialisation, launches the other |
---|
| 10 | // threads, and exit. |
---|
| 11 | // It contains 2 MWMR channels per cluster : "fifo_in" and "fifo_out", that are |
---|
| 12 | // allocated by the main thread in the user heaps distributed in all clusters. |
---|
| 13 | // - The "producer" task writes token in all the "fifo_in". |
---|
| 14 | // - The N "router" tasks read token from "fifo_in" and write them into "fifo_out". |
---|
| 15 | // - The "consumer" task read token from "fifo_out" and displays instrumentation results. |
---|
| 16 | // Token are indexed (by the producer) from 0 to NMAX-1. |
---|
| 17 | // The router task contains a random delay emulating a variable processing time. |
---|
| 18 | // For instrumentation, the "consumer_tab" array is filled by the "consumer" task. |
---|
| 19 | // Each entry contain the arrival order to the consumer task. |
---|
| 20 | ///////////////////////////////////////////////////////////////////////////////////////////// |
---|
| 21 | |
---|
| 22 | |
---|
| 23 | #include "stdio.h" |
---|
| 24 | #include "mwmr_channel.h" |
---|
| 25 | #include "mapping_info.h" |
---|
| 26 | #include "hard_config.h" |
---|
| 27 | #include "malloc.h" |
---|
| 28 | |
---|
| 29 | #define VERBOSE 1 |
---|
| 30 | #define NMAX 32 // total number of token |
---|
| 31 | #define DEPTH 32 // MWMR channels depth |
---|
| 32 | |
---|
| 33 | |
---|
| 34 | // macro to use a shared TTY |
---|
| 35 | #define printf(...); { lock_acquire( &tty_lock ); \ |
---|
| 36 | giet_tty_printf(__VA_ARGS__); \ |
---|
| 37 | lock_release( &tty_lock ); } |
---|
| 38 | |
---|
| 39 | // lock protecting shared TTY |
---|
| 40 | user_lock_t tty_lock; |
---|
| 41 | |
---|
| 42 | |
---|
| 43 | // arguments for the producer, consumer, and router functions |
---|
| 44 | typedef struct |
---|
| 45 | { |
---|
| 46 | mwmr_channel_t* pin; // pointer on the MWMR input fifo |
---|
| 47 | mwmr_channel_t* pout; // pointer on the MWMR output fifo |
---|
| 48 | unsigned int x_size; // number of clusters in a row |
---|
| 49 | unsigned int y_size; // number of clusters in a column |
---|
| 50 | } args_t; |
---|
| 51 | |
---|
| 52 | |
---|
| 53 | // arrays of pointers |
---|
| 54 | mwmr_channel_t* fifo_in[16][16]; |
---|
| 55 | mwmr_channel_t* fifo_out[16][16]; |
---|
| 56 | |
---|
| 57 | |
---|
| 58 | ///////////////////////////////////////////// |
---|
| 59 | __attribute__ ((constructor)) void producer() |
---|
| 60 | { |
---|
| 61 | unsigned int x = 0; // destination cluster coordinate |
---|
| 62 | unsigned int y = 0; // destination cluster coordinate |
---|
| 63 | unsigned int token = 0; // token value |
---|
| 64 | |
---|
| 65 | // get plat-form parameters |
---|
| 66 | unsigned int x_size; // number of clusters in a row |
---|
| 67 | unsigned int y_size; // number of clusters in a column |
---|
| 68 | unsigned int nprocs; // unused |
---|
| 69 | giet_procs_number( &x_size , &y_size , &nprocs ); |
---|
| 70 | |
---|
| 71 | // loop on the clusters |
---|
| 72 | while ( token < NMAX ) |
---|
| 73 | { |
---|
| 74 | // try to write a token in fifo_in[x,y] |
---|
| 75 | if ( nb_mwmr_write( fifo_in[x][y] , &token , 1 ) == 1 ) |
---|
| 76 | { |
---|
| 77 | if ( VERBOSE ) printf("[PRODUCER] token %d sent to cluster(%d,%d)" |
---|
| 78 | " at cycle %d\n", token , x , y , giet_proctime() ); |
---|
| 79 | token++; |
---|
| 80 | } |
---|
| 81 | |
---|
| 82 | // compute next cluster coordinates |
---|
| 83 | x++; |
---|
| 84 | if ( x == x_size ) |
---|
| 85 | { |
---|
| 86 | x = 0; |
---|
| 87 | y++; |
---|
| 88 | if ( y == y_size ) y = 0; |
---|
| 89 | } |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | giet_pthread_exit( "Producer task completed"); |
---|
| 93 | |
---|
| 94 | } // end producer() |
---|
| 95 | |
---|
| 96 | ///////////////////////////////////////////// |
---|
| 97 | __attribute__ ((constructor)) void consumer() |
---|
| 98 | { |
---|
| 99 | unsigned int x = 0; // source cluster coordinate |
---|
| 100 | unsigned int y = 0; // source cluster coordinate |
---|
| 101 | unsigned int n = 0; // index of received token |
---|
| 102 | unsigned int token; // token value |
---|
| 103 | unsigned int consumer_tab[NMAX]; // received token array |
---|
| 104 | |
---|
| 105 | // get plat-form parameters |
---|
| 106 | unsigned int x_size; // number of clusters in a row |
---|
| 107 | unsigned int y_size; // number of clusters in a column |
---|
| 108 | unsigned int nprocs; // unused |
---|
| 109 | giet_procs_number( &x_size , &y_size , &nprocs ); |
---|
| 110 | |
---|
| 111 | // loop on the clusters |
---|
| 112 | while ( n < NMAX ) |
---|
| 113 | { |
---|
| 114 | // try to read a token from fifo_out[x,y] |
---|
| 115 | if ( nb_mwmr_read( fifo_out[x][y] , &token , 1 ) == 1 ) |
---|
| 116 | { |
---|
| 117 | consumer_tab[n] = token; |
---|
| 118 | n++; |
---|
| 119 | |
---|
| 120 | if ( VERBOSE ) printf("[CONSUMER] token %d received at cycle %d\n", |
---|
| 121 | token , giet_proctime() ); |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | // compute next cluster coordinates |
---|
| 125 | x++; |
---|
| 126 | if ( x == x_size ) |
---|
| 127 | { |
---|
| 128 | x = 0; |
---|
| 129 | y++; |
---|
| 130 | if ( y == y_size ) y = 0; |
---|
| 131 | } |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | // instrumentation display |
---|
| 135 | giet_tty_printf("\n[CONSUMER] displays instrumentation results\n"); |
---|
| 136 | for( n = 0 ; n < NMAX ; n++ ) |
---|
| 137 | { |
---|
| 138 | giet_tty_printf(" - arrival = %d / value = %d\n", n , consumer_tab[n] ); |
---|
| 139 | } |
---|
| 140 | |
---|
| 141 | giet_pthread_exit( "Consumer task completed"); |
---|
| 142 | |
---|
| 143 | } // end consumer() |
---|
| 144 | |
---|
| 145 | //////////////////////////////////////////// |
---|
| 146 | __attribute__ ((constructor)) void compute() |
---|
| 147 | { |
---|
| 148 | unsigned int token; // token value |
---|
| 149 | unsigned int count; // tempo |
---|
| 150 | |
---|
| 151 | // get proc coordinates |
---|
| 152 | unsigned int x; |
---|
| 153 | unsigned int y; |
---|
| 154 | unsigned int p; |
---|
| 155 | giet_proc_xyp( &x , &y , &p ); |
---|
| 156 | |
---|
| 157 | // main loop |
---|
| 158 | while(1) |
---|
| 159 | { |
---|
| 160 | mwmr_read( fifo_in[x][y] , &token , 1 ); |
---|
| 161 | for ( count = 0 ; count < (giet_rand() << 2) ; count++ ) asm volatile ( "nop" ); |
---|
| 162 | mwmr_write( fifo_out[x][y] , &token , 1 ); |
---|
| 163 | |
---|
| 164 | if ( VERBOSE ) printf("[COMPUTE] token %d handled at cycle %d on P[%d,%d,%d]\n", |
---|
| 165 | token , giet_proctime() , x , y , p ); |
---|
| 166 | } |
---|
| 167 | } // end compute() |
---|
| 168 | |
---|
| 169 | |
---|
| 170 | ///////////////////////////////////////// |
---|
| 171 | __attribute__ ((constructor)) void main() |
---|
| 172 | { |
---|
| 173 | // get plat-form parameters |
---|
| 174 | unsigned int x_size; // number of clusters in a row |
---|
| 175 | unsigned int y_size; // number of clusters in a column |
---|
| 176 | unsigned int nprocs; // number of processors per cluster |
---|
| 177 | giet_procs_number( &x_size , &y_size , &nprocs ); |
---|
| 178 | |
---|
| 179 | // shared TTY allocation |
---|
| 180 | giet_tty_alloc( 1 ); |
---|
| 181 | lock_init( &tty_lock); |
---|
| 182 | |
---|
| 183 | // check plat-form parameters |
---|
| 184 | giet_pthread_assert( ((nprocs >= 3) && (nprocs <= 8)), |
---|
| 185 | "[ROUTER ERROR] nprocs per cluster must be in [3...8]"); |
---|
| 186 | |
---|
| 187 | giet_pthread_assert( ((x_size >= 1) && (x_size <= 16)), |
---|
| 188 | "[ROUTER ERROR] x_size must be in [1...16]"); |
---|
| 189 | |
---|
| 190 | giet_pthread_assert( ((y_size >= 1) && (y_size <= 16)), |
---|
| 191 | "[ROUTER ERROR] y_size must be in [1...16]"); |
---|
| 192 | |
---|
| 193 | // index for loops |
---|
| 194 | unsigned int x; |
---|
| 195 | unsigned int y; |
---|
| 196 | unsigned int n; |
---|
| 197 | |
---|
| 198 | // distributed heap initialisation, plus |
---|
| 199 | // MWMR channels and associated buffers allocation |
---|
| 200 | for ( x = 0 ; x < x_size ; x++ ) |
---|
| 201 | { |
---|
| 202 | for ( y = 0 ; y < y_size ; y++ ) |
---|
| 203 | { |
---|
| 204 | heap_init( x , y ); |
---|
| 205 | |
---|
| 206 | // allocate MWMR channel descriptors in cluster[x][y] |
---|
| 207 | fifo_in[x][y] = remote_malloc( sizeof( mwmr_channel_t ) , x , y ); |
---|
| 208 | fifo_out[x][y] = remote_malloc( sizeof( mwmr_channel_t ) , x , y ); |
---|
| 209 | |
---|
| 210 | // allocate data buffers in cluster[x][y] |
---|
| 211 | unsigned int* buf_in = remote_malloc( 4*DEPTH , x , y ); |
---|
| 212 | unsigned int* buf_out = remote_malloc( 4*DEPTH , x , y ); |
---|
| 213 | |
---|
| 214 | // initialize MWMR channels |
---|
| 215 | mwmr_init( fifo_in[x][y] , buf_in , 1 , DEPTH ); |
---|
| 216 | mwmr_init( fifo_out[x][y] , buf_out , 1 , DEPTH ); |
---|
| 217 | } |
---|
| 218 | } |
---|
| 219 | |
---|
| 220 | printf("\n[ROUTER] main completes initialisation at cycle %d for %d cores\n", |
---|
| 221 | giet_proctime(), (x_size * y_size * nprocs) ); |
---|
| 222 | |
---|
| 223 | // thread index and function for pthread_create() |
---|
| 224 | pthread_t trdid; |
---|
| 225 | void* function; |
---|
| 226 | |
---|
| 227 | // launch producer, consumer and router threads |
---|
| 228 | for ( x = 0 ; x < x_size ; x++ ) |
---|
| 229 | { |
---|
| 230 | for ( y = 0 ; y < y_size ; y++ ) |
---|
| 231 | { |
---|
| 232 | for ( n = 0 ; n < nprocs ; n++ ) |
---|
| 233 | { |
---|
| 234 | if ( (x==0) && (y==0) && (n==0) ) function = &producer; |
---|
| 235 | else if ( (x==0) && (y==0) && (n==1) ) function = &consumer; |
---|
| 236 | else function = &compute; |
---|
| 237 | |
---|
| 238 | if ( giet_pthread_create( &trdid, |
---|
| 239 | NULL, // no attribute |
---|
| 240 | function, |
---|
| 241 | NULL ) ) // no argument |
---|
| 242 | { |
---|
| 243 | printf("\n[ROUTER ERROR] launching thread on P[%d,%d,%d]\n", x, y, n ); |
---|
| 244 | giet_pthread_exit( NULL ); |
---|
| 245 | } |
---|
| 246 | } |
---|
| 247 | } |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | giet_pthread_exit( "main completed" ); |
---|
| 251 | |
---|
| 252 | } // end main() |
---|