| [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() | 
|---|