source: trunk/user/transpose/transpose.c @ 646

Last change on this file since 646 was 646, checked in by alain, 3 years ago

Introducing application "transpose".

File size: 22.5 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////////////
2// File   : transpose.c   
3// Date   : september 2019
4// author : Alain Greiner
5//////////////////////////////////////////////////////////////////////////////////////////
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// It can run on a multi-cores, multi-clusters architecture, with one thread
10//
11// per core, and uses the POSIX threads API.
12// It uses the mmap() syscall to directly access the input and output files
13// and the fbf_write() syscall to display the images.
14//
15// The main() function can be launched on any core[cxy,l].
16// It makes the initialisations, launch (N-1) threads to run the execute() function
17// on the (N-1) other cores, calls himself the execute() function, and finally calls
18// the instrument() function to display instrumentation results when the parallel
19// execution is completed. The placement of threads on the cores can be done
20// automatically by the operating system, or can be done explicitely by the main thread
21// (when the EXPLICIT_PLACEMENT global parameter is set).
22//
23// The buf_in[x,y] and buf_out[put buffers containing the direct ans transposed images
24// are distributed in clusters: In each cluster[cxy], the thread running on core[cxy,0]
25// map the buf_in[cxy] and // buf_out[cxy] buffers containing a subset of lines.
26// Then, all threads in cluster[xy] read pixels from the local buf_in[cxy] buffer, and
27// write the pixels to all remote buf_out[cxy] buffers. Finally, each thread display
28// a part of the transposed image to the frame buffer.
29//
30// - The image  must fit the frame buffer size, that must be power of 2.
31// - The number of clusters  must be a power of 2 no larger than 256.
32// - The number of cores per cluster must be a power of 2 no larger than 4.
33// - The number of clusters cannot be larger than (IMAGE_SIZE * IMAGE_SIZE) / 4096,
34//   because the size of buf_in[x,y] and buf_out[x,y] must be multiple of 4096.
35//
36//////////////////////////////////////////////////////////////////////////////////////////
37
38#include <sys/mman.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include <pthread.h>
43#include <string.h>
44#include <almosmkh.h>
45#include <fcntl.h>
46#include <hal_macros.h>
47
48#define X_MAX                 16                           // max number of clusters in row
49#define Y_MAX                 16                           // max number of clusters in column
50#define CORES_MAX             4                            // max number of cores per cluster
51#define CLUSTERS_MAX          (X_MAX * Y_MAX)              // max number of clusters
52
53#define IMAGE_SIZE            256                          // image size
54#define IMAGE_TYPE            420                          // pixel encoding type
55#define INPUT_FILE_PATH       "/misc/lena_256.raw"         // input file pathname
56#define OUTPUT_FILE_PATH      "/home/trsp_256.raw"         // output file pathname
57
58#define USE_DQT_BARRIER       1                            // quad-tree barrier if non zero
59#define EXPLICIT_PLACEMENT    1                            // explicit thread placement
60#define VERBOSE               1                            // print comments on TTY
61
62
63///////////////////////////////////////////////////////
64//                global variables
65///////////////////////////////////////////////////////
66
67// instrumentation counters for each processor in each cluster
68unsigned int MMAP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
69unsigned int MMAP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
70unsigned int TRSP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
71unsigned int TRSP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
72unsigned int DISP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
73unsigned int DISP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
74
75// arrays of pointers on distributed buffers
76// one input buffer & one output buffer per cluster
77unsigned char *  buf_in [CLUSTERS_MAX];
78unsigned char *  buf_out[CLUSTERS_MAX];
79
80// synchronisation barrier (all threads)
81pthread_barrier_t   barrier;
82
83// platform parameters
84unsigned int  x_size;                       // number of clusters in a row
85unsigned int  y_size;                       // number of clusters in a column
86unsigned int  ncores;                       // number of processors per cluster
87
88// cluster identifier & local index of core running the main thread
89unsigned int  cxy_main;
90unsigned int  lid_main;
91
92// input & output file descriptors
93int  fd_in;
94int  fd_out;
95
96#if EXPLICIT_PLACEMENT
97
98// thread index allocated by the kernel
99pthread_t        trdid[CLUSTERS_MAX][CORES_MAX];   
100
101// user defined continuous thread index
102unsigned int     tid[CLUSTERS_MAX][CORES_MAX];
103
104// thread attributes only used if explicit placement
105pthread_attr_t   attr[CLUSTERS_MAX][CORES_MAX];
106
107#else
108
109// thread index allocated by the kernel
110pthread_t        trdid[CLUSTERS_MAX * CORES_MAX];   
111
112// user defined continuous thread index
113unsigned int     tid[CLUSTERS_MAX * CORES_MAX];
114
115#endif
116
117//return values at thread exit
118unsigned int THREAD_EXIT_SUCCESS = 0;
119unsigned int THREAD_EXIT_FAILURE = 1;
120
121////////////////////////////////////////////////////////////////
122//             functions declaration
123////////////////////////////////////////////////////////////////
124
125void execute( unsigned int * ptid );
126
127void instrument( void );
128
129///////////
130void main()
131{
132    unsigned long long date;
133
134    int error;
135
136printf("\n bloup 0\n");
137
138    // get identifiers for core executing main
139    get_core_id( &cxy_main , &lid_main );
140
141printf("\n bloup 1\n");
142
143    // get & check plat-form parameters
144    get_config( &x_size , &y_size , &ncores );
145
146printf("\n bloup 2\n");
147
148    if((ncores != 1) && (ncores != 2) && (ncores == 4))
149    {
150        printf("\n[transpose error] number of cores per cluster must be 1/2/4\n");
151        exit( 0 );
152    }
153
154    if( (x_size != 1) && (x_size != 2) && (x_size != 4) && 
155        (x_size != 8) && (x_size != 16) )
156    {
157        printf("\n[transpose error] x_size must be 1/2/4/8/16\n");
158        exit( 0 );
159    }
160       
161    if( (y_size != 1) && (y_size != 2) && (y_size != 4) && 
162        (y_size != 8) && (y_size != 16) )
163    {
164        printf("\n[transpose error] y_size must be 1/2/4/8/16\n");
165        exit( 0 );
166    }
167       
168printf("\n bloup 3\n");
169
170    // compute number of threads
171    unsigned int nclusters = x_size * y_size;
172    unsigned int nthreads  = nclusters * ncores;
173
174printf("\n bloup 4\n");
175
176    // get FBF ownership and FBF size
177    unsigned int   fbf_width;
178    unsigned int   fbf_height;
179    unsigned int   fbf_type;
180    fbf_get_config( &fbf_width , &fbf_height , &fbf_type );
181
182printf("\n bloup 5\n");
183
184    if( (fbf_width != IMAGE_SIZE) || (fbf_height != IMAGE_SIZE) || (fbf_type != IMAGE_TYPE) )
185    {
186        printf("\n[transpose error] image does not fit FBF size or type\n");
187        exit( 0 );
188    }
189
190    get_cycle( &date );
191    printf("\n[transpose] starts at cycle %d on %d cores / FBF = %d * %d pixels\n",
192    (unsigned int)date , nthreads , fbf_width , fbf_height );
193
194    // open input file
195    fd_in = open( INPUT_FILE_PATH , O_RDONLY , 0 );    // read-only
196    if ( fd_in < 0 ) 
197    { 
198        printf("\n[transpose error] main cannot open file %s\n", INPUT_FILE_PATH );
199        exit( 0 );
200    } 
201
202#if VERBOSE
203printf("\n[transpose] main open file %s / fd = %d\n", INPUT_FILE_PATH , fd_in );
204#endif
205
206    // open output file
207    fd_out = open( OUTPUT_FILE_PATH , O_CREAT , 0 );   // create if required
208    if ( fd_out < 0 ) 
209    { 
210        printf("\n[transpose error] main cannot open file %s\n", OUTPUT_FILE_PATH );
211        exit( 0 );
212    }
213
214#if  VERBOSE
215printf("\n[transpose] main open file %s / fd = %d\n", OUTPUT_FILE_PATH , fd_out );
216#endif
217
218    // initialise barrier
219    if( USE_DQT_BARRIER )
220    {
221        pthread_barrierattr_t attr;
222        attr.x_size   = x_size;
223        attr.y_size   = y_size;
224        attr.nthreads = ncores;
225        error = pthread_barrier_init( &barrier, &attr , nthreads );
226    }
227    else
228    {
229        error = pthread_barrier_init( &barrier, NULL , nthreads );
230    }
231
232    if( error )
233    { 
234        printf("\n[transpose error] main cannot initialize barrier\n" );
235        exit( 0 );
236    }
237
238    get_cycle( &date );
239    printf("\n[transpose] main on core[%x,%d] completes initialisation at cycle %d\n" 
240           "- CLUSTERS     = %d\n"
241           "- PROCS        = %d\n" 
242           "- THREADS      = %d\n",
243           cxy_main, lid_main, (unsigned int)date, nclusters, ncores, nthreads );
244
245//////////////////////
246#if EXPLICIT_PLACEMENT
247
248    // main thread launch other threads
249    unsigned int x;
250    unsigned int y;
251    unsigned int l;
252    unsigned int cxy;
253    for( x = 0 ; x < x_size ; x++ )
254    {
255        for( y = 0 ; y < y_size ; y++ )
256        {
257            cxy = HAL_CXY_FROM_XY( x , y );
258            for( l = 0 ; l < ncores ; l++ )
259            {
260                // no other thread on the core running the main
261                if( (cxy != cxy_main) || (l != lid_main) )
262                {
263                    // define thread attributes
264                    attr[cxy][l].attributes = PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
265                    attr[cxy][l].cxy        = cxy;
266                    attr[cxy][l].lid        = l;
267
268                    tid[cxy][l] = (((* y_size) + y) * ncores) + l;
269 
270                    // create thread on core[cxy,l]
271                    if (pthread_create( &trdid[cxy][l],   
272                                        &attr[cxy][l],   
273                                        &execute,
274                                        &tid[cxy][l] ) )       
275                    {
276                        printf("\n[convol error] created thread %x on core[%x][%d]\n",
277                        trdid[cxy][l] , cxy , l );
278                        exit( 0 );
279                    }
280#if VERBOSE
281printf("\n[transpose] main created thread[%x,%d]\n", cxy, l );
282#endif
283                }
284            }
285        }
286    }   
287
288    // main thread calls itself the execute() function
289    execute( &tid[cxy_main][lid_main] );
290
291    // main thread wait other threads completion
292    for( x = 0 ; x < x_size ; x++ )
293    {
294        for( y = 0 ; y < y_size ; y++ )
295        {
296            cxy = HAL_CXY_FROM_XY( x , y );
297            for( l = 0 ; l < ncores ; l++ )
298            {
299                // no other thread on the core running the main
300                if( (cxy != cxy_main) || (l != lid_main) )
301                {
302                    unsigned int * status;
303
304                    // wait thread[cxy][l]
305                    if( pthread_join( trdid[cxy][l] , (void*)(&status) ) )
306                    {
307                        printf("\n[transpose error] main cannot join thread[%x,%d]\n", cxy, l );
308                        exit( 0 );
309                    }
310       
311                    // check status
312                    if( *status != THREAD_EXIT_SUCCESS )
313                    {
314                        printf("\n[transpose error] thread[%x,%d] returned failure\n", cxy, l );
315                        exit( 0 );
316                    }
317#if VERBOSE
318printf("\n[transpose] main joined thread[%x,%d]\n", cxy, l );
319#endif
320                }
321            }
322        }
323    }
324
325///////////////////////////////
326#else  // no explicit placement
327
328    // main thread launch other threads
329    unsigned int n;
330    for ( n = 1 ; n < nthreads ; n++ )
331    {
332        tid[n] = n;
333        if ( pthread_create( &trdid[n], 
334                             NULL,                  // no attribute
335                             &execute,
336                             &tid[n] ) ) 
337        {
338            printf("\n[transpose error] cannot create thread %d\n", n );
339            exit( 0 );
340        }
341
342#if VERBOSE
343printf("\n[transpose] main created thread %d\n", tid[n] );
344#endif
345
346    }
347
348    // main thread calls itself the execute() function
349    execute( &tid[0] );
350
351    // main thread wait other threads completion
352    for ( n = 1 ; n < nthreads ; n++ )
353    {
354        unsigned int * status;
355
356        // main wait thread[n] status
357        if ( pthread_join( trdid[n], (void*)(&status)) )
358        {
359            printf("\n[transpose error] main cannot join thread %d\n", n );
360            exit( 0 );
361        }
362       
363        // check status
364        if( *status != THREAD_EXIT_SUCCESS )
365        {
366            printf("\n[transpose error] thread %x returned failure\n", n );
367            exit( 0 );
368        }
369
370#if VERBOSE
371printf("\n[transpose] main successfully joined thread %x\n", tid[n] );
372#endif
373       
374    }
375
376#endif
377
378    // instrumentation
379    instrument();
380
381    // close input and output files
382    close( fd_in );
383    close( fd_out );
384
385    // suicide
386    exit( 0 );
387   
388} // end main()
389
390
391
392///////////////////////////////////
393void execute( unsigned int * ptid )
394{
395    unsigned long long   date;
396 
397    unsigned int l;                         // line index for loops
398    unsigned int p;                         // pixel index for loops
399
400    // get thread continuous index
401    unsigned int my_tid = *ptid;
402
403    // build total number of pixels per image
404    unsigned int npixels = IMAGE_SIZE * IMAGE_SIZE;     
405
406    // nuild total number of threads and clusters
407    unsigned int nthreads  = x_size * y_size * ncores;
408    unsigned int nclusters = x_size * y_size;
409
410    // get cluster continuous index and core index from tid
411    // we use (tid == cid * ncores + lid)
412    unsigned int cid = my_tid / ncores;     // continuous index   
413    unsigned int lid = my_tid % ncores;     // core local index
414
415    // get cluster identifier from cid
416    // we use (cid == x * y_size + y)
417    unsigned int x   = cid / y_size;        // X cluster coordinate
418    unsigned int y   = cid % y_size;        // Y cluster coordinate
419    unsigned int cxy = HAL_CXY_FROM_XY(x,y);
420   
421#if VERBOSE
422printf("\n[transpose] thread[%d] start on core[%x,%d]\n", my_tid , cxy , lid );
423#endif
424
425    // In each cluster cxy,  thread[cxy,0] map input file
426    // to buf_in[cxy] and map output file to buf_in[cxy]
427
428    get_cycle( &date );
429    MMAP_START[cxy][lid] = (unsigned int)date;
430
431    if ( lid == 0 ) 
432    {
433        unsigned int length = npixels / nclusters;
434        unsigned int offset = length * cid;
435       
436        // map buf_in
437        buf_in[cid] =  mmap( NULL,
438                             length,
439                             PROT_READ,
440                             MAP_SHARED,
441                             fd_in,
442                             offset );
443
444        if ( buf_in[cid] == NULL )
445        {
446            printf("\n[transpose error] thread[%x,%d] cannot map input file\n", cxy, lid);
447            pthread_exit( &THREAD_EXIT_FAILURE );
448        }
449                 
450#if VERBOSE
451printf("\n[transpose] thread[%x,%d] map input file / length %x / offset %x / buf_in %x\n",
452cxy, lid, length, offset, buf_in[cid] );
453#endif
454
455        // map buf_out           
456        buf_out[cid] = mmap( NULL,
457                             length,
458                             PROT_WRITE,
459                             MAP_SHARED,
460                             fd_out,
461                             offset );
462
463        if ( buf_out[cid] == NULL )
464        {
465            printf("\n[transpose error] thread[%x,%d] cannot map output file\n", cxy, lid);
466            pthread_exit( &THREAD_EXIT_FAILURE );
467        }
468                   
469#if VERBOSE
470printf("\n[transpose] thread[%x,%d] map output file / length %x / offset %x / buf_out %x\n",
471cxy, lid, length, offset, buf_out[cid] );
472#endif
473
474    }
475
476    get_cycle( &date );
477    MMAP_END[cxy][lid] = (unsigned int)date;
478
479    /////////////////////////////////
480    pthread_barrier_wait( &barrier );
481
482    // parallel transpose from buf_in to buf_out
483    // each thread makes the transposition for nlt lines (nlt = IMAGE_SIZE/nthreads)
484    // from line [tid*nlt] to line [(tid + 1)*nlt - 1]
485    // (p,l) are the absolute pixel coordinates in the source image
486
487    get_cycle( &date );
488    TRSP_START[cxy][lid] = (unsigned int)date;
489
490    unsigned int nlt   = IMAGE_SIZE / nthreads;    // number of lines per thread
491    unsigned int nlc   = IMAGE_SIZE / nclusters;   // number of lines per cluster
492
493    unsigned int src_cluster;
494    unsigned int src_index;
495    unsigned int dst_cluster;
496    unsigned int dst_index;
497
498    unsigned char byte;
499
500    unsigned int first = my_tid * nlt;     // first line index for a given thread
501    unsigned int last  = first + nlt;      // last line index for a given thread
502
503    for ( l = first ; l < last ; l++ )
504    {
505        // in each iteration we transfer one byte
506        for ( p = 0 ; p < IMAGE_SIZE ; p++ )
507        {
508            // read one byte from local buf_in
509            src_cluster = l / nlc;
510            src_index   = (l % nlc) * IMAGE_SIZE + p;
511            byte        = buf_in[src_cluster][src_index];
512
513            // write one byte to remote buf_out
514            dst_cluster = p / nlc; 
515            dst_index   = (p % nlc) * IMAGE_SIZE + l;
516
517            buf_out[dst_cluster][dst_index] = byte;
518        }
519    }
520
521#if VERBOSE
522printf("\n[transpose] thread[%x,%d] completes transposed\n", cxy, lid );
523#endif
524
525    get_cycle( &date );
526    TRSP_END[cxy][lid] = (unsigned int)date;
527
528    /////////////////////////////////
529    pthread_barrier_wait( &barrier );
530
531    // parallel display from local buf_out to frame buffer
532    // all threads contribute to display
533
534    get_cycle( &date );
535    DISP_START[cxy][lid] = (unsigned int)date;
536
537    unsigned int  npt   = npixels / nthreads;   // number of pixels per thread
538
539    if( fbf_write( &buf_out[cid][lid * npt], 
540                   npt,
541                   npt * my_tid ) )
542    {
543        printf("\n[transpose error] thread[%x,%d] cannot access FBF\n", cxy, lid );
544        pthread_exit( &THREAD_EXIT_FAILURE );
545    }
546
547#if VERBOSE
548printf("\n[transpose] thread[%x,%d] completes display\n", cxy, lid );
549#endif
550
551    get_cycle( &date );
552    DISP_END[cxy][lid] = (unsigned int)date;
553
554    /////////////////////////////////
555    pthread_barrier_wait( &barrier );
556
557    // all threads, but thread[0,0,0], suicide
558    if ( (cxy != cxy_main) || (lid !=  lid_main) )
559    { 
560        pthread_exit( &THREAD_EXIT_SUCCESS );
561    }
562
563} // end execute()
564
565
566
567///////////////////////
568void instrument( void )
569{
570    unsigned int x, y, l;
571
572    unsigned int min_load_start = 0xFFFFFFFF;
573    unsigned int max_load_start = 0;
574    unsigned int min_load_ended = 0xFFFFFFFF;
575    unsigned int max_load_ended = 0;
576    unsigned int min_trsp_start = 0xFFFFFFFF;
577    unsigned int max_trsp_start = 0;
578    unsigned int min_trsp_ended = 0xFFFFFFFF;
579    unsigned int max_trsp_ended = 0;
580    unsigned int min_disp_start = 0xFFFFFFFF;
581    unsigned int max_disp_start = 0;
582    unsigned int min_disp_ended = 0xFFFFFFFF;
583    unsigned int max_disp_ended = 0;
584 
585    char string[64];
586
587    snprintf( string , 64 , "/home/transpose_%d_%d_%d" , x_size , y_size , ncores );
588
589    // open instrumentation file
590    FILE * f = fopen( string , NULL );
591    if ( f == NULL ) 
592    { 
593        printf("\n[transpose error] cannot open instrumentation file %s\n", string );
594        exit( 0 );
595    }
596
597    for (x = 0; x < x_size; x++)
598    {
599        for (y = 0; y < y_size; y++)
600        {
601            unsigned int cxy = HAL_CXY_FROM_XY( x , y );
602
603            for ( l = 0 ; l < ncores ; l++ )
604            {
605                if (MMAP_START[cxy][l] < min_load_start)  min_load_start = MMAP_START[cxy][l];
606                if (MMAP_START[cxy][l] > max_load_start)  max_load_start = MMAP_START[cxy][l];
607                if (MMAP_END[cxy][l]   < min_load_ended)  min_load_ended = MMAP_END[cxy][l]; 
608                if (MMAP_END[cxy][l]   > max_load_ended)  max_load_ended = MMAP_END[cxy][l];
609                if (TRSP_START[cxy][l] < min_trsp_start)  min_trsp_start = TRSP_START[cxy][l];
610                if (TRSP_START[cxy][l] > max_trsp_start)  max_trsp_start = TRSP_START[cxy][l];
611                if (TRSP_END[cxy][l]   < min_trsp_ended)  min_trsp_ended = TRSP_END[cxy][l];
612                if (TRSP_END[cxy][l]   > max_trsp_ended)  max_trsp_ended = TRSP_END[cxy][l];
613                if (DISP_START[cxy][l] < min_disp_start)  min_disp_start = DISP_START[cxy][l];
614                if (DISP_START[cxy][l] > max_disp_start)  max_disp_start = DISP_START[cxy][l];
615                if (DISP_END[cxy][l]   < min_disp_ended)  min_disp_ended = DISP_END[cxy][l];
616                if (DISP_END[cxy][l]   > max_disp_ended)  max_disp_ended = DISP_END[cxy][l];
617            }
618        }
619    }
620
621    printf( "\n ------ %s ------\n" , string );
622    fprintf( f , "\n ------ %s ------\n" , string );
623
624    printf( " - MMAP_START : min = %d / max = %d / med = %d / delta = %d\n",
625           min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
626           max_load_start-min_load_start ); 
627
628    fprintf( f , " - MMAP_START : min = %d / max = %d / med = %d / delta = %d\n",
629           min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
630           max_load_start-min_load_start ); 
631
632    printf( " - MMAP_END   : min = %d / max = %d / med = %d / delta = %d\n",
633           min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
634           max_load_ended-min_load_ended ); 
635
636    fprintf( f , " - MMAP_END   : min = %d / max = %d / med = %d / delta = %d\n",
637           min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
638           max_load_ended-min_load_ended ); 
639
640    printf( " - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
641           min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
642           max_trsp_start-min_trsp_start ); 
643
644    fprintf( f , " - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
645           min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
646           max_trsp_start-min_trsp_start ); 
647
648    printf( " - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
649           min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
650           max_trsp_ended-min_trsp_ended ); 
651
652    fprintf( f , " - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
653           min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
654           max_trsp_ended-min_trsp_ended ); 
655
656    printf( " - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
657           min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
658           max_disp_start-min_disp_start ); 
659
660    fprintf( f , " - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
661           min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
662           max_disp_start-min_disp_start ); 
663
664    printf( " - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
665           min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
666           max_disp_ended-min_disp_ended ); 
667
668    fprintf( f , " - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
669           min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
670           max_disp_ended-min_disp_ended ); 
671
672    fclose( f );
673
674}  // end instrument()
675
676
677
678
Note: See TracBrowser for help on using the repository browser.