source: soft/giet_vm/applications/transpose/transpose.c @ 708

Last change on this file since 708 was 708, checked in by alain, 9 years ago

Adapt the following application to the POSIX threads API

  • convol
  • classif
  • raycast
  • coproc
  • display
  • gameoflife
  • transpose
  • shell
File size: 19.6 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////
2// File   : transpose.c   
3// Date   : september 2015
4// author : Alain Greiner
5///////////////////////////////////////////////////////////////////////////////////////
6// This multi-threaded aplication transposes a raw image (one pbyte per pixel).
7// It can run on a multi-processors, multi-clusters architecture, with one thread
8// per processor, and uses the POSIX threads API.
9//
10// The main() function can be launched on any processor P[x,y,l].
11// It makes the initialisations, launch (N-1) threads to run the execute() function
12// on the (N-1) other processors than P[x,y,l], call himself the execute() function,
13// and finally call the instrument() function to display instrumentation results
14// when the parallel execution is completed.
15//
16// The input and output buffers containing the image are distributed in clusters.
17//
18// The execute() function read a set of lines from an input file on disk,
19// to the local buffer buf_in[x][y], transpose it, write the result to a remote buffer
20// buf_out[x'][y'], display the content of the local buffer buf_out[x][y] to the
21// frame buffer, and store it on disk to another output file.
22//
23// - The image size must fit the frame buffer size.
24// - The block size in block device must be 512 bytes.
25// - The number of clusters  must be a power of 2 no larger than 256.
26// - The number of processors per cluster must be a power of 2 no larger than 4.
27///////////////////////////////////////////////////////////////////////////////////////
28
29#include "stdio.h"
30#include "user_barrier.h"
31#include "malloc.h"
32
33#define BLOCK_SIZE            512                         // block size on disk
34#define X_MAX                 16                          // max number of clusters in row
35#define Y_MAX                 16                          // max number of clusters in column
36#define PROCS_MAX             4                           // max number of procs per cluster
37#define CLUSTER_MAX           (X_MAX * Y_MAX)             // max number of clusters
38#define IMAGE_SIZE            256                         // image size : nlines = npixels
39#define INPUT_FILE_PATH       "/misc/lena_256.raw"        // pathname on virtual disk
40#define OUTPUT_FILE_PATH      "/home/lena_transposed.raw" // pathname on virtual disk
41
42// macro to use a shared TTY
43#define printf(...);    { lock_acquire( &tty_lock ); \
44                          giet_tty_printf(__VA_ARGS__);  \
45                          lock_release( &tty_lock ); }
46
47///////////////////////////////////////////////////////
48// global variables stored in seg_data in cluster(0,0)
49///////////////////////////////////////////////////////
50
51// instrumentation counters for each processor in each cluster
52unsigned int LOAD_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
53unsigned int LOAD_END  [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
54unsigned int TRSP_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
55unsigned int TRSP_END  [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
56unsigned int DISP_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
57unsigned int DISP_END  [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
58unsigned int STOR_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
59unsigned int STOR_END  [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
60
61// arrays of pointers on distributed buffers
62// one input buffer & one output buffer per cluster
63unsigned char*  buf_in [CLUSTER_MAX];
64unsigned char*  buf_out[CLUSTER_MAX];
65
66// checksum variables
67unsigned check_line_before[IMAGE_SIZE];
68unsigned check_line_after[IMAGE_SIZE];
69
70// lock protecting shared TTY
71user_lock_t  tty_lock;
72
73// synchronisation barrier (all threads)
74giet_sqt_barrier_t barrier;
75
76////////////////////////////////////////////
77__attribute__ ((constructor)) void execute()
78////////////////////////////////////////////
79{
80    unsigned int l;                            // line index for loops
81    unsigned int p;                            // pixel index for loops
82
83    // get processor identifiers
84    unsigned int x_id;                         // x cluster coordinate
85    unsigned int y_id;                         // y cluster coordinate
86    unsigned int p_id;                         // local processor index
87
88    giet_proc_xyp( &x_id, &y_id, &p_id);             
89
90    // get & check plat-form parameters
91    unsigned int x_size;                       // number of clusters in a row
92    unsigned int y_size;                       // number of clusters in a column
93    unsigned int nprocs;                       // number of processors per cluster
94   
95    giet_procs_number( &x_size , &y_size , &nprocs );
96
97    unsigned int nclusters     = x_size * y_size;               // number of clusters
98    unsigned int nthreads      = x_size * y_size * nprocs;      // number of threads
99    unsigned int npixels       = IMAGE_SIZE * IMAGE_SIZE;       // pixels per image
100    int          fd_in         = 0;                             // initial file descriptor
101    int          fd_out        = 0;                             // output file descriptor
102    unsigned int cluster_id    = (x_id * y_size) + y_id;        // "continuous" index   
103    unsigned int thread_id     = (cluster_id * nprocs) + p_id;  // "continuous" thread index
104
105    // parallel load of image:
106    // allocate buf_in and buf_out distributed buffers (one buf_in & one buf_out per cluster).
107    // open input and output files, and load the relevant lines in local buf_in.
108    // only thread running on processor[x,y,0] does it.
109
110    LOAD_START[x_id][y_id][p_id] = giet_proctime();
111
112    if ( p_id == 0 ) 
113    {
114        buf_in[cluster_id]  = remote_malloc( npixels/nclusters, x_id, y_id );
115        buf_out[cluster_id] = remote_malloc( npixels/nclusters, x_id, y_id );
116
117        if ( (x_id==0) && (y_id==0) )
118        {
119            printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes buffer allocation at cycle %d\n",
120                   x_id, y_id, p_id, giet_proctime() );
121        }
122
123        // open input file
124        fd_in = giet_fat_open( INPUT_FILE_PATH , O_RDONLY );  // read_only
125        if ( fd_in < 0 ) 
126        { 
127            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot open file %s\n",
128                   x_id , y_id , p_id , INPUT_FILE_PATH );
129            giet_pthread_exit(" open() failure");
130        }
131        else if ( (x_id==0) && (y_id==0) )
132        {
133            printf("\n[TRANSPOSE] Proc [0,0,0] open file %s / fd = %d\n",
134                   INPUT_FILE_PATH , fd_in );
135        }
136
137        // open output file
138        fd_out = giet_fat_open( OUTPUT_FILE_PATH , O_CREATE );   // create if required
139        if ( fd_out < 0 ) 
140        { 
141            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot open file %s\n",
142                            x_id , y_id , p_id , OUTPUT_FILE_PATH );
143            giet_pthread_exit(" open() failure");
144        }
145        else if ( (x_id==0) && (y_id==0) )
146        {
147            printf("\n[TRANSPOSE] Proc [0,0,0] open file %s / fd = %d\n",
148                   OUTPUT_FILE_PATH , fd_out );
149        }
150
151
152        unsigned int offset = ((npixels*cluster_id)/nclusters);
153        if ( giet_fat_lseek( fd_in,
154                             offset,
155                             SEEK_SET ) != offset )
156        {
157            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot seek fd = %d\n",
158                   x_id , y_id , p_id , fd_in );
159            giet_pthread_exit(" seek() failure");
160        }
161
162        unsigned int pixels = npixels / nclusters;
163        if ( giet_fat_read( fd_in,
164                            buf_in[cluster_id],
165                            pixels ) != pixels )
166        {
167            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot read fd = %d\n",
168                   x_id , y_id , p_id , fd_in );
169            giet_pthread_exit(" read() failure");
170        }
171
172        if ( (x_id==0) && (y_id==0) )
173        {
174            printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes load at cycle %d\n",
175                   x_id, y_id, p_id, giet_proctime() );
176        }
177    }
178
179    LOAD_END[x_id][y_id][p_id] = giet_proctime();
180
181    /////////////////////////////
182    sqt_barrier_wait( &barrier );
183    /////////////////////////////
184
185    // parallel transpose from buf_in to buf_out
186    // each thread makes the transposition for nlt lines (nlt = IMAGE_SIZE/nthreads)
187    // from line [thread_id*nlt] to line [(thread_id + 1)*nlt - 1]
188    // (p,l) are the absolute pixel coordinates in the source image
189
190    TRSP_START[x_id][y_id][p_id] = giet_proctime();
191
192    unsigned int nlt   = IMAGE_SIZE / nthreads;    // number of lines per thread
193    unsigned int nlc   = IMAGE_SIZE / nclusters;   // number of lines per cluster
194
195    unsigned int src_cluster;
196    unsigned int src_index;
197    unsigned int dst_cluster;
198    unsigned int dst_index;
199
200    unsigned char byte;
201
202    unsigned int first = thread_id * nlt;  // first line index for a given thread
203    unsigned int last  = first + nlt;      // last line index for a given thread
204
205    for ( l = first ; l < last ; l++ )
206    {
207        check_line_before[l] = 0;
208     
209        // in each iteration we transfer one byte
210        for ( p = 0 ; p < IMAGE_SIZE ; p++ )
211        {
212            // read one byte from local buf_in
213            src_cluster = l / nlc;
214            src_index   = (l % nlc)*IMAGE_SIZE + p;
215            byte        = buf_in[src_cluster][src_index];
216
217            // compute checksum
218            check_line_before[l] = check_line_before[l] + byte;
219
220            // write one byte to remote buf_out
221            dst_cluster = p / nlc; 
222            dst_index   = (p % nlc)*IMAGE_SIZE + l;
223            buf_out[dst_cluster][dst_index] = byte;
224        }
225    }
226
227    if ( (p_id == 0) && (x_id==0) && (y_id==0) )
228    {
229        printf("\n[TRANSPOSE] proc [%d,%d,%d] completes transpose at cycle %d\n", 
230        x_id, y_id, p_id, giet_proctime() );
231    }
232
233    TRSP_END[x_id][y_id][p_id] = giet_proctime();
234
235    /////////////////////////////
236    sqt_barrier_wait( &barrier );
237    /////////////////////////////
238
239    // parallel display from local buf_out to frame buffer
240    // all threads contribute to display using memcpy...
241
242    DISP_START[x_id][y_id][p_id] = giet_proctime();
243
244    unsigned int  npt   = npixels / nthreads;   // number of pixels per thread
245
246    giet_fbf_sync_write( npt * thread_id, 
247                         &buf_out[cluster_id][p_id*npt], 
248                         npt );
249
250    if ( (x_id==0) && (y_id==0) && (p_id==0) )
251    {
252        printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes display at cycle %d\n",
253               x_id, y_id, p_id, giet_proctime() );
254    }
255
256    DISP_END[x_id][y_id][p_id] = giet_proctime();
257
258    /////////////////////////////
259    sqt_barrier_wait( &barrier );
260    /////////////////////////////
261
262    // parallel store : buf_out buffers to disk
263    // only thread running on processor(x,y,0) does it
264
265    STOR_START[x_id][y_id][p_id] = giet_proctime();
266
267    if ( p_id == 0 )
268    {
269        unsigned int offset = ((npixels*cluster_id)/nclusters);
270        if ( giet_fat_lseek( fd_out,
271                             offset,
272                             SEEK_SET ) != offset )
273        {
274            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot seek fr = %d\n",
275                   x_id , y_id , p_id , fd_out );
276            giet_pthread_exit(" seek() failure");
277        }
278
279        unsigned int pixels = npixels / nclusters;
280        if ( giet_fat_write( fd_out,
281                             buf_out[cluster_id],
282                             pixels ) != pixels )
283        {
284            printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot write fd = %d\n",
285                   x_id , y_id , p_id , fd_out );
286            giet_pthread_exit(" write() failure");
287        }
288
289        if ( (x_id==0) && (y_id==0) )
290        {
291            printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes store at cycle %d\n",
292                   x_id, y_id, p_id, giet_proctime() );
293        }
294    }
295
296    STOR_END[x_id][y_id][p_id] = giet_proctime();
297
298    // In each cluster, only thread running on Processor[x,y,0] releases
299    // the distributed buffers and close the file descriptors.
300
301    if ( p_id==0 )
302    {
303        free( buf_in[cluster_id] );
304        free( buf_out[cluster_id] );
305
306        giet_fat_close( fd_in );
307        giet_fat_close( fd_out );
308    }
309
310    if ( (x_id != 0) || (y_id != 0) || (p_id != 0) ) 
311    giet_pthread_exit( "completed" );
312
313} // end execute()
314
315
316
317//////////////////////////////////////
318void instrument( unsigned int x_size,
319                 unsigned int y_size,
320                 unsigned int nprocs )
321//////////////////////////////////////
322{
323    unsigned int x, y, l;
324
325    unsigned int min_load_start = 0xFFFFFFFF;
326    unsigned int max_load_start = 0;
327    unsigned int min_load_ended = 0xFFFFFFFF;
328    unsigned int max_load_ended = 0;
329    unsigned int min_trsp_start = 0xFFFFFFFF;
330    unsigned int max_trsp_start = 0;
331    unsigned int min_trsp_ended = 0xFFFFFFFF;
332    unsigned int max_trsp_ended = 0;
333    unsigned int min_disp_start = 0xFFFFFFFF;
334    unsigned int max_disp_start = 0;
335    unsigned int min_disp_ended = 0xFFFFFFFF;
336    unsigned int max_disp_ended = 0;
337    unsigned int min_stor_start = 0xFFFFFFFF;
338    unsigned int max_stor_start = 0;
339    unsigned int min_stor_ended = 0xFFFFFFFF;
340    unsigned int max_stor_ended = 0;
341
342    for (x = 0; x < x_size; x++)
343    {
344        for (y = 0; y < y_size; y++)
345        {
346            for ( l = 0 ; l < nprocs ; l++ )
347            {
348                if (LOAD_START[x][y][l] < min_load_start)  min_load_start = LOAD_START[x][y][l];
349                if (LOAD_START[x][y][l] > max_load_start)  max_load_start = LOAD_START[x][y][l];
350                if (LOAD_END[x][y][l]   < min_load_ended)  min_load_ended = LOAD_END[x][y][l]; 
351                if (LOAD_END[x][y][l]   > max_load_ended)  max_load_ended = LOAD_END[x][y][l];
352                if (TRSP_START[x][y][l] < min_trsp_start)  min_trsp_start = TRSP_START[x][y][l];
353                if (TRSP_START[x][y][l] > max_trsp_start)  max_trsp_start = TRSP_START[x][y][l];
354                if (TRSP_END[x][y][l]   < min_trsp_ended)  min_trsp_ended = TRSP_END[x][y][l];
355                if (TRSP_END[x][y][l]   > max_trsp_ended)  max_trsp_ended = TRSP_END[x][y][l];
356                if (DISP_START[x][y][l] < min_disp_start)  min_disp_start = DISP_START[x][y][l];
357                if (DISP_START[x][y][l] > max_disp_start)  max_disp_start = DISP_START[x][y][l];
358                if (DISP_END[x][y][l]   < min_disp_ended)  min_disp_ended = DISP_END[x][y][l];
359                if (DISP_END[x][y][l]   > max_disp_ended)  max_disp_ended = DISP_END[x][y][l];
360                if (STOR_START[x][y][l] < min_stor_start)  min_stor_start = STOR_START[x][y][l];
361                if (STOR_START[x][y][l] > max_stor_start)  max_stor_start = STOR_START[x][y][l];
362                if (STOR_END[x][y][l]   < min_stor_ended)  min_stor_ended = STOR_END[x][y][l];
363                if (STOR_END[x][y][l]   > max_stor_ended)  max_stor_ended = STOR_END[x][y][l];
364            }
365        }
366    }
367
368    printf("\n   ---------------- Instrumentation Results ---------------------\n");
369
370    printf(" - LOAD_START : min = %d / max = %d / med = %d / delta = %d\n",
371           min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
372           max_load_start-min_load_start); 
373
374    printf(" - LOAD_END   : min = %d / max = %d / med = %d / delta = %d\n",
375           min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
376           max_load_ended-min_load_ended); 
377
378    printf(" - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
379           min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
380           max_trsp_start-min_trsp_start); 
381
382    printf(" - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
383           min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
384           max_trsp_ended-min_trsp_ended); 
385
386    printf(" - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
387           min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
388           max_disp_start-min_disp_start); 
389
390    printf(" - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
391           min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
392           max_disp_ended-min_disp_ended); 
393
394    printf(" - STOR_START : min = %d / max = %d / med = %d / delta = %d\n",
395           min_stor_start, max_stor_start, (min_stor_start+max_stor_start)/2, 
396           max_stor_start-min_stor_start); 
397
398    printf(" - STOR_END   : min = %d / max = %d / med = %d / delta = %d\n",
399           min_stor_ended, max_stor_ended, (min_stor_ended+max_stor_ended)/2, 
400           max_stor_ended-min_stor_ended); 
401
402}  // end instrument()
403
404
405
406//////////////////////////////////////////
407__attribute__ ((constructor)) void main()
408//////////////////////////////////////////
409{
410    // indexes for loops
411    unsigned int x , y , n;
412
413    // get identifiers for proc executing main
414    unsigned int x_id;                          // x cluster coordinate
415    unsigned int y_id;                          // y cluster coordinate
416    unsigned int p_id;                          // local processor index
417
418    giet_proc_xyp( &x_id , &y_id , &p_id );
419
420    // get & check plat-form parameters
421    unsigned int x_size;                       // number of clusters in a row
422    unsigned int y_size;                       // number of clusters in a column
423    unsigned int nprocs;                       // number of processors per cluster
424
425    giet_procs_number( &x_size , &y_size , &nprocs );
426
427    giet_pthread_assert( ((nprocs == 1) || (nprocs == 2) || (nprocs == 4)),
428                         "[TRANSPOSE ERROR] number of procs per cluster must be 1, 2 or 4");
429
430    giet_pthread_assert( ((x_size == 1) || (x_size == 2) || (x_size == 4) || 
431                  (x_size == 8) || (x_size == 16)),
432                         "[TRANSPOSE ERROR] x_size must be 1,2,4,8,16");
433
434    giet_pthread_assert( ((y_size == 1) || (y_size == 2) || (y_size == 4) || 
435                  (y_size == 8) || (y_size == 16)),
436                         "[TRANSPOSE ERROR] y_size must be 1,2,4,8,16");
437
438    giet_pthread_assert( (nprocs * x_size * y_size <= IMAGE_SIZE ),
439                         "[TRANSPOSE ERROR] number of threads larger than number of lines");
440
441    unsigned int nthreads = x_size * y_size * nprocs;
442
443    // shared TTY allocation
444    giet_tty_alloc( 1 );     
445    lock_init( &tty_lock);
446
447    printf("\n[TRANSPOSE] start at cycle %d on %d cores\n", giet_proctime(), nthreads );
448
449    // distributed heap initialisation
450    for ( x = 0 ; x < x_size ; x++ ) 
451    {
452        for ( y = 0 ; y < y_size ; y++ ) 
453        {
454            heap_init( x , y );
455        }
456    }
457
458    // allocate thread[] array
459    pthread_t* thread = malloc( nthreads * sizeof(pthread_t) );
460
461    // barrier initialisation
462    sqt_barrier_init( &barrier, x_size , y_size , nprocs );
463
464    // Initialisation completed
465    printf("\n[TRANSPOSE] initialisation completed at cycle %d\n", giet_proctime() );
466   
467    // launch other threads to run execute() function
468    for ( n = 1 ; n < nthreads ; n++ )
469    {
470        if ( giet_pthread_create( &thread[n],
471                                  NULL,                  // no attribute
472                                  &execute,
473                                  NULL ) )               // no argument
474        {
475            printf("\n[TRANSPOSE ERROR] creating thread %x\n", thread[n] );
476            giet_pthread_exit( NULL );
477        }
478    }
479
480    // run the execute() function
481    execute();
482
483    // wait other threads completion
484    for ( n = 1 ; n < nthreads ; n++ )
485    {
486        if ( giet_pthread_join( thread[n], NULL ) )
487        {
488            printf("\n[TRANSPOSE ERROR] joining thread %x\n", thread[n] );
489            giet_pthread_exit( NULL );
490        }
491        else
492        {
493            printf("\n[TRANSPOSE] thread %x joined at cycle %d\n",
494                   thread[n] , giet_proctime() );
495        }
496    }
497
498    // call the instrument() function
499    instrument( x_size , y_size , nprocs );
500
501    giet_pthread_exit( "completed" );
502   
503} // end main()
504
Note: See TracBrowser for help on using the repository browser.