source: soft/giet_vm/applications/transpose/transpose_rw.c @ 764

Last change on this file since 764 was 764, checked in by alain, 8 years ago

Modify the transpose application to use replace the
giet_fat_read() / giet_fat_write() system calls
by the giet_far_mmap() system call, in order to
avoid one copy of data in user space.

The read/write version is still available as transpose_rw.c

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