source: soft/giet_vm/applications/transpose/main.c @ 669

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

Introduce support for the "shared" argument in the giet_tty_alloc() system call,
and replace the giet_shr_printf() system call by giet_tty_printf().

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