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

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

cosmetic.

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