Index: trunk/user/transpose/transpose.c
===================================================================
--- trunk/user/transpose/transpose.c	(revision 646)
+++ trunk/user/transpose/transpose.c	(revision 652)
@@ -5,32 +5,62 @@
 //////////////////////////////////////////////////////////////////////////////////////////
 // This multi-threaded aplication read a raw image (one byte per pixel)
-// stored on disk, transpose it, display the result on the frame buffer,
-// and store the transposed image on disk.
-// It can run on a multi-cores, multi-clusters architecture, with one thread
+// stored on disk, transposes it, displays the result on the frame buffer,
+// and stores the transposed image on disk.
 //
-// per core, and uses the POSIX threads API. 
-// It uses the mmap() syscall to directly access the input and output files
-// and the fbf_write() syscall to display the images.
+// The image size and the pixel encoding type are defined by the IMAGE_SIZE and
+// IMAGE_TYPE global parameters.
 //
-// The main() function can be launched on any core[cxy,l].
-// It makes the initialisations, launch (N-1) threads to run the execute() function
-// on the (N-1) other cores, calls himself the execute() function, and finally calls
-// the instrument() function to display instrumentation results when the parallel 
-// execution is completed. The placement of threads on the cores can be done
-// automatically by the operating system, or can be done explicitely by the main thread
-// (when the EXPLICIT_PLACEMENT global parameter is set). 
+// It can run on a multi-cores, multi-clusters architecture, where (X_SIZE * Y_SIZE)
+// is the number of clusters and NCORES the number of cores per cluster.
+// A core is identified by two indexes [cxy,lid] : cxy is the cluster identifier,
+// (that is NOT required to be a continuous index), and lid is the local core index,
+// (that must be in the [Ø,NCORES-1] range).
 //
-// The buf_in[x,y] and buf_out[put buffers containing the direct ans transposed images
-// are distributed in clusters: In each cluster[cxy], the thread running on core[cxy,0]
-// map the buf_in[cxy] and // buf_out[cxy] buffers containing a subset of lines.
-// Then, all threads in cluster[xy] read pixels from the local buf_in[cxy] buffer, and
-// write the pixels to all remote buf_out[cxy] buffers. Finally, each thread display
-// a part of the transposed image to the frame buffer.
+// The main() function can run on any core in any cluster. This main thread
+// makes the initialisations, uses the pthread_create() syscall to launch (NTHREADS-1)
+// other threads in "attached" mode running in parallel the execute() function, calls 
+// himself the execute() function, wait completion of the (NTHREADS-1) other threads 
+// with a pthread_join(), and finally calls the instrument() function to display
+// and register the instrumentation results when execution is completed.
+// All threads run the execute() function, but each thread transposes only
+// (NLINES / NTHREADS) lines. This requires that NLINES == k * NTHREADS.
+//
+// The number N of working threads is always defined by the number of cores availables
+// in the architecture, but this application supports three placement modes.
+// In all modes, the working threads are identified by the [tid] continuous index 
+// in range [0, NTHREADS-1], and defines how the lines are shared amongst the threads.
+// This continuous index can always be decomposed in two continuous sub-indexes:
+// tid == cid * ncores + lid,  where cid is in [0,NCLUSTERS-1] and lid in [0,NCORES-1].
+//
+// - NO_PLACEMENT: the main thread is itsef a working thread. The (N_1) other working
+//   threads are created by the main thread, but the placement is done by the OS, using
+//   the DQDT for load balancing, and two working threads can be placed on the same core.
+//   The [cid,lid] are only abstract identifiers, and cannot be associated to a physical
+//   cluster or a physical core. In this mode, the main thread run on any cluster, 
+//   but has tid = 0 (i.e. cid = 0 & tid = 0).
+//
+// - EXPLICIT_PLACEMENT: the main thread is again a working thread, but the placement of
+//   of the threads on the cores is explicitely controled by the main thread to have
+//   exactly one working thread per core, and the [cxy][lpid] core coordinates for a given
+//   thread[tid] can be directly derived from the [tid] value: [cid] is an alias for the
+//   physical cluster identifier, and [lid] is the local core index.
+//
+// - PARALLEL_PLACEMENT: the main thread is not anymore a working thread, and uses the
+//   non standard pthread_parallel_create() function to avoid the costly sequencial
+//   loops for pthread_create() and pthread_join(). It garanty one working thread 
+//   per core, and the same relation between the thread[tid] and the core[cxy][lpid].
+//    
+// The buf_in[x,y] and buf_out[put buffers containing the direct and transposed images
+// are distributed in clusters: each thread[cid][0] allocate a local input buffer
+// and load in this buffer all lines that must be handled by the threads sharing the
+// same cid, from the mapper of the input image file.
+// In the execute function, all threads in the group defined by the cid index read pixels
+// from the local buf_in[cid] buffer, and write pixels to all remote buf_out[cid] buffers.
+// Finally, each thread displays a part of the transposed image to the frame buffer.
 //
 // - The image  must fit the frame buffer size, that must be power of 2.
 // - The number of clusters  must be a power of 2 no larger than 256.
 // - The number of cores per cluster must be a power of 2 no larger than 4.
-// - The number of clusters cannot be larger than (IMAGE_SIZE * IMAGE_SIZE) / 4096,
-//   because the size of buf_in[x,y] and buf_out[x,y] must be multiple of 4096.
+// - The number of threads cannot be larger than IMAGE_SIZE.
 //
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -50,13 +80,21 @@
 #define CORES_MAX             4                            // max number of cores per cluster
 #define CLUSTERS_MAX          (X_MAX * Y_MAX)              // max number of clusters
-
-#define IMAGE_SIZE            256                          // image size 
+#define THREADS_MAX           (X_MAX * Y_MAX * CORES_MAX)  // max number of threads
+
+#define IMAGE_SIZE            512                          // image size 
 #define IMAGE_TYPE            420                          // pixel encoding type
-#define INPUT_FILE_PATH       "/misc/lena_256.raw"         // input file pathname 
-#define OUTPUT_FILE_PATH      "/home/trsp_256.raw"         // output file pathname 
-
+#define INPUT_FILE_PATH       "/misc/couple_512.raw"       // input file pathname 
+#define OUTPUT_FILE_PATH      "/misc/transposed_512.raw"   // output file pathname 
+
+#define SAVE_RESULT_FILE      0                            // save result image on disk
 #define USE_DQT_BARRIER       1                            // quad-tree barrier if non zero 
-#define EXPLICIT_PLACEMENT    1                            // explicit thread placement
-#define VERBOSE               1                            // print comments on TTY
+
+#define NO_PLACEMENT          0                            // uncontrolefdthread placement
+#define EXPLICIT_PLACEMENT    0                            // explicit threads placement
+#define PARALLEL_PLACEMENT    1                            // parallel threads placement
+
+#define VERBOSE_MAIN          0                            // main function print comments
+#define VERBOSE_EXEC          0                            // exec function print comments
+#define VERBOSE_INSTRU        0                            // instru function print comments
 
 
@@ -65,7 +103,12 @@
 ///////////////////////////////////////////////////////
 
-// instrumentation counters for each processor in each cluster 
-unsigned int MMAP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
-unsigned int MMAP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
+// global instrumentation counters for the main thread
+unsigned int SEQUENCIAL_TIME = 0;
+unsigned int PARALLEL_TIME   = 0;
+
+// instrumentation counters for each thread in each cluster 
+// indexed by [cid][lid] : cluster continuous index / thread local index
+unsigned int LOAD_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
+unsigned int LOAD_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
 unsigned int TRSP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
 unsigned int TRSP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
@@ -73,45 +116,24 @@
 unsigned int DISP_END  [CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
 
-// arrays of pointers on distributed buffers
-// one input buffer & one output buffer per cluster
-unsigned char *  buf_in [CLUSTERS_MAX];
-unsigned char *  buf_out[CLUSTERS_MAX];
-
-// synchronisation barrier (all threads)
+// pointer on buffer containing the input image, maped by the main to the input file
+unsigned char *  image_in;
+
+// pointer on buffer containing the output image, maped by the main to the output file
+unsigned char *  image_out;
+
+// arrays of pointers on distributed buffers indexed by [cid] : cluster continuous index
+unsigned char *  buf_in_ptr [CLUSTERS_MAX];
+unsigned char *  buf_out_ptr[CLUSTERS_MAX];
+
+// synchronisation barrier (all working threads)
 pthread_barrier_t   barrier;
 
 // platform parameters
-unsigned int  x_size;                       // number of clusters in a row
-unsigned int  y_size;                       // number of clusters in a column
-unsigned int  ncores;                       // number of processors per cluster
-
-// cluster identifier & local index of core running the main thread
-unsigned int  cxy_main;
-unsigned int  lid_main;
-
-// input & output file descriptors
-int  fd_in;
-int  fd_out;
-
-#if EXPLICIT_PLACEMENT
-
-// thread index allocated by the kernel 
-pthread_t        trdid[CLUSTERS_MAX][CORES_MAX];   
-
-// user defined continuous thread index 
-unsigned int     tid[CLUSTERS_MAX][CORES_MAX];
-
-// thread attributes only used if explicit placement
-pthread_attr_t   attr[CLUSTERS_MAX][CORES_MAX];
-
-#else 
-
-// thread index allocated by the kernel
-pthread_t        trdid[CLUSTERS_MAX * CORES_MAX];   
-
-// user defined continuous thread index
-unsigned int     tid[CLUSTERS_MAX * CORES_MAX];
-
-#endif
+unsigned int  x_size;              // number of clusters in a row
+unsigned int  y_size;              // number of clusters in a column
+unsigned int  ncores;              // number of cores per cluster
+
+// main thread continuous index
+unsigned int     tid_main; 
 
 //return values at thread exit
@@ -119,32 +141,49 @@
 unsigned int THREAD_EXIT_FAILURE = 1;
 
+// array of kernel thread identifiers / indexed by [tid]
+pthread_t                     exec_trdid[THREADS_MAX];   
+
+// array of execute function arguments / indexed by [tid]
+pthread_parallel_work_args_t  exec_args[THREADS_MAX];
+
+// array of thread attributes / indexed by [tid]
+pthread_attr_t                exec_attr[THREADS_MAX];
+
 ////////////////////////////////////////////////////////////////
 //             functions declaration
 ////////////////////////////////////////////////////////////////
 
-void execute( unsigned int * ptid );
-
-void instrument( void );
-
-///////////
-void main()
+void execute( pthread_parallel_work_args_t * args );
+
+void instrument( FILE * f , char * filename );
+
+/////////////////
+void main( void )
 {
-    unsigned long long date;
+    unsigned long long start_cycle;
+    unsigned long long end_sequencial_cycle;
+    unsigned long long end_parallel_cycle;
+
+    char               filename[32];      // instrumentation file name
+    char               pathname[64];      // instrumentation file pathname
 
     int error;
 
-printf("\n bloup 0\n");
-
-    // get identifiers for core executing main
-    get_core_id( &cxy_main , &lid_main );
-
-printf("\n bloup 1\n");
+    /////////////////////////////////////////////////////////////////////////////////
+    get_cycle( &start_cycle );
+    /////////////////////////////////////////////////////////////////////////////////
+
+    if( (NO_PLACEMENT + EXPLICIT_PLACEMENT + PARALLEL_PLACEMENT) != 1 )
+    {
+        printf("\n[transpose error] illegal placement\n");
+        exit( 0 );
+    }
 
     // get & check plat-form parameters
-    get_config( &x_size , &y_size , &ncores );
-
-printf("\n bloup 2\n");
-
-    if((ncores != 1) && (ncores != 2) && (ncores == 4))
+    get_config( &x_size,
+                &y_size,
+                &ncores );
+
+    if((ncores != 1) && (ncores != 2) && (ncores != 4))
     {
         printf("\n[transpose error] number of cores per cluster must be 1/2/4\n");
@@ -166,5 +205,8 @@
     }
         
-printf("\n bloup 3\n");
+    // main thread get identifiers for core executing main
+    unsigned int  cxy_main;
+    unsigned int  lid_main;
+    get_core_id( &cxy_main , &lid_main );
 
     // compute number of threads
@@ -172,7 +214,5 @@
     unsigned int nthreads  = nclusters * ncores;
 
-printf("\n bloup 4\n");
-
-    // get FBF ownership and FBF size
+    // main thread get FBF size and type
     unsigned int   fbf_width;
     unsigned int   fbf_height;
@@ -180,6 +220,4 @@
     fbf_get_config( &fbf_width , &fbf_height , &fbf_type );
 
-printf("\n bloup 5\n");
-
     if( (fbf_width != IMAGE_SIZE) || (fbf_height != IMAGE_SIZE) || (fbf_type != IMAGE_TYPE) )
     {
@@ -188,33 +226,70 @@
     }
 
-    get_cycle( &date );
-    printf("\n[transpose] starts at cycle %d on %d cores / FBF = %d * %d pixels\n",
-    (unsigned int)date , nthreads , fbf_width , fbf_height );
-
-    // open input file
-    fd_in = open( INPUT_FILE_PATH , O_RDONLY , 0 );    // read-only
-    if ( fd_in < 0 ) 
+    if( nthreads > IMAGE_SIZE )
+    {
+        printf("\n[transpose error] number of threads larger than number of lines\n");
+        exit( 0 );
+    }
+
+    unsigned int npixels = IMAGE_SIZE * IMAGE_SIZE;
+
+    // define instrumentation file name
+    if( NO_PLACEMENT )
+    {
+        printf("\n[transpose] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / NO_PLACE\n",
+        nclusters, ncores, fbf_width, fbf_height, getpid() );
+
+        // build instrumentation file name
+        if( USE_DQT_BARRIER )
+        snprintf( filename , 32 , "trsp_dqt_no_place_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+        else
+        snprintf( filename , 32 , "trsp_smp_no_place_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+    }
+
+    if( EXPLICIT_PLACEMENT )
+    {
+        printf("\n[transpose] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / EXPLICIT\n",
+        nclusters, ncores, fbf_width, fbf_height, getpid() );
+
+        // build instrumentation file name
+        if( USE_DQT_BARRIER )
+        snprintf( filename , 32 , "trsp_dqt_explicit_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+        else
+        snprintf( filename , 32 , "trsp_smp_explicit_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+    }
+
+    if( PARALLEL_PLACEMENT )
+    {
+        printf("\n[transpose] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / PARALLEL\n",
+        nclusters, ncores, fbf_width, fbf_height, getpid() );
+
+        // build instrumentation file name
+        if( USE_DQT_BARRIER )
+        snprintf( filename , 32 , "trsp_dqt_parallel_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+        else
+        snprintf( filename , 32 , "trsp_smp_parallel_%d_%d_%d",
+        IMAGE_SIZE , x_size * y_size , ncores );
+    }
+
+    // open instrumentation file
+    snprintf( pathname , 64 , "/home/%s", filename );
+    FILE * f = fopen( pathname , NULL );
+    if ( f == NULL ) 
     { 
-        printf("\n[transpose error] main cannot open file %s\n", INPUT_FILE_PATH );
-        exit( 0 );
-    } 
-
-#if VERBOSE
-printf("\n[transpose] main open file %s / fd = %d\n", INPUT_FILE_PATH , fd_in );
-#endif
-
-    // open output file
-    fd_out = open( OUTPUT_FILE_PATH , O_CREAT , 0 );   // create if required
-    if ( fd_out < 0 ) 
-    { 
-        printf("\n[transpose error] main cannot open file %s\n", OUTPUT_FILE_PATH );
-        exit( 0 );
-    }
-
-#if  VERBOSE
-printf("\n[transpose] main open file %s / fd = %d\n", OUTPUT_FILE_PATH , fd_out );
-#endif
-
-    // initialise barrier 
+        printf("\n[transpose error] cannot open instrumentation file %s\n", pathname );
+        exit( 0 );
+    }
+
+#if  VERBOSE_MAIN
+printf("\n[transpose] main on core[%x,%d] open instrumentation file %s\n",
+cxy_main, lid_main, pathname );
+#endif
+
+    // main thread initializes barrier 
     if( USE_DQT_BARRIER )
     {
@@ -236,152 +311,277 @@
     }
 
-    get_cycle( &date );
-    printf("\n[transpose] main on core[%x,%d] completes initialisation at cycle %d\n" 
-           "- CLUSTERS     = %d\n"
-           "- PROCS        = %d\n" 
-           "- THREADS      = %d\n",
-           cxy_main, lid_main, (unsigned int)date, nclusters, ncores, nthreads );
-
-//////////////////////
-#if EXPLICIT_PLACEMENT
-
-    // main thread launch other threads
-    unsigned int x;
-    unsigned int y;
-    unsigned int l;
-    unsigned int cxy;
-    for( x = 0 ; x < x_size ; x++ )
-    {
-        for( y = 0 ; y < y_size ; y++ )
+#if  VERBOSE_MAIN
+printf("\n[transpose] main on core[%x,%d] completes barrier initialisation\n",
+cxy_main, lid_main );
+#endif
+
+    // main thread open input file
+    int fd_in = open( INPUT_FILE_PATH , O_RDONLY , 0 ); 
+
+    if ( fd_in < 0 ) 
+    { 
+        printf("\n[transpose error] main cannot open file %s\n", INPUT_FILE_PATH );
+        exit( 0 );
+    }
+
+#if  VERBOSE_MAIN
+printf("\n[transpose] main open file <%s> / fd = %d\n", INPUT_FILE_PATH , fd_in );
+#endif
+
+    // main thread map image_in buffer to input image file
+    image_in = (unsigned char *)mmap( NULL,
+                                      npixels,
+                                      PROT_READ,
+                                      MAP_FILE | MAP_SHARED,
+                                      fd_in,
+                                      0 );     // offset 
+    if ( image_in == NULL ) 
+    { 
+        printf("\n[transpose error] main cannot map buffer to file %s\n", INPUT_FILE_PATH );
+        exit( 0 );
+    }
+
+#if  VERBOSE_MAIN
+printf("\n[transpose] main map buffer to file <%s>\n", INPUT_FILE_PATH );
+#endif
+
+    // main thread display input image on FBF
+    if( fbf_write( image_in, 
+                   npixels,
+                   0 ) )
+    {
+        printf("\n[transpose error] main cannot access FBF\n");
+        exit( 0 );
+    }
+
+#if SAVE_RESULT_IMAGE
+
+    // main thread open output file
+    int fd_out = open( OUTPUT_FILE_PATH , O_CREAT , 0 ); 
+
+    if ( fd_out < 0 ) 
+    { 
+        printf("\n[transpose error] main cannot open file %s\n", OUTPUT_FILE_PATH );
+        exit( 0 );
+    }
+
+#if  VERBOSE_MAIN
+printf("\n[transpose] main open file <%s> / fd = %d\n", OUTPUT_FILE_PATH , fd_out );
+#endif
+
+    // main thread map image_out buffer to output image file
+    image_out = (unsigned char *)mmap( NULL,
+                                       npixels,
+                                       PROT_WRITE,
+                                       MAP_FILE | MAP_SHARED,
+                                       fd_out,
+                                       0 );     // offset 
+    if ( image_out == NULL ) 
+    { 
+        printf("\n[transpose error] main cannot map buf_out to file %s\n", OUTPUT_FILE_PATH );
+        exit( 0 );
+    }
+
+#if  VERBOSE_MAIN
+printf("\n[transpose] main map buffer to file <%s>\n", OUTPUT_FILE_PATH );
+#endif
+
+#endif  // SAVE_RESULT_IMAGE
+
+    /////////////////////////////////////////////////////////////////////////////////////
+    get_cycle( &end_sequencial_cycle );
+    SEQUENCIAL_TIME = (unsigned int)(end_sequencial_cycle - start_cycle);
+    /////////////////////////////////////////////////////////////////////////////////////
+
+    //////////////////
+    if( NO_PLACEMENT )
+    {
+        // the tid value for the main thread is always 0
+        // main thread creates new threads with tid in [1,nthreads-1]  
+        unsigned int tid;
+        for ( tid = 0 ; tid < nthreads ; tid++ )
         {
-            cxy = HAL_CXY_FROM_XY( x , y );
-            for( l = 0 ; l < ncores ; l++ )
+            // register tid value in exec_args[tid] array
+            exec_args[tid].tid = tid;
+            
+            // create other threads
+            if( tid > 0 )
             {
-                // no other thread on the core running the main
-                if( (cxy != cxy_main) || (l != lid_main) )
+                if ( pthread_create( &exec_trdid[tid], 
+                                     NULL,                  // no attribute
+                                     &execute,
+                                     &exec_args[tid] ) ) 
                 {
-                    // define thread attributes
-                    attr[cxy][l].attributes = PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
-                    attr[cxy][l].cxy        = cxy;
-                    attr[cxy][l].lid        = l;
-
-                    tid[cxy][l] = (((x  * y_size) + y) * ncores) + l;
+                    printf("\n[transpose error] cannot create thread %d\n", tid );
+                    exit( 0 );
+                }
+
+#if VERBOSE_MAIN
+printf("\n[transpose] main created thread %d\n", tid );
+#endif
+
+            }
+            else
+            {
+                tid_main = 0;
+            }
+        }  // end for tid
+
+        // main thread calls itself the execute() function
+        execute( &exec_args[0] );
+
+        // main thread wait other threads completion
+        for ( tid = 1 ; tid < nthreads ; tid++ )
+        {
+            unsigned int * status;
+
+            // main wait thread[tid] status
+            if ( pthread_join( exec_trdid[tid], (void*)(&status)) )
+            {
+                printf("\n[transpose error] main cannot join thread %d\n", tid );
+                exit( 0 );
+            }
+       
+            // check status
+            if( *status != THREAD_EXIT_SUCCESS )
+            {
+                printf("\n[transpose error] thread %x returned failure\n", tid );
+                exit( 0 );
+            }
+
+#if VERBOSE_MAIN 
+printf("\n[transpose] main successfully joined thread %x\n", tid );
+#endif
+        
+        }  // end for tid
+
+    }  // end if no_placement
+
+    ////////////////////////
+    if( EXPLICIT_PLACEMENT )
+    {
+        // main thread places each other threads on a specific core[cxy][lid]
+        // but the actual thread creation is sequencial
+        unsigned int x;
+        unsigned int y;
+        unsigned int l;
+        unsigned int cxy;                   // cluster identifier
+        unsigned int tid;                   // thread continuous index
+
+        for( x = 0 ; x < x_size ; x++ )
+        {
+            for( y = 0 ; y < y_size ; y++ )
+            {
+                cxy = HAL_CXY_FROM_XY( x , y );
+                for( l = 0 ; l < ncores ; l++ )
+                {
+                    // compute thread continuous index
+                    tid = (((x  * y_size) + y) * ncores) + l;
+
+                    // register tid value in exec_args[tid] array
+                    exec_args[tid].tid = tid;
+
+                    // no thread created on the core running the main
+                    if( (cxy != cxy_main) || (l != lid_main) )
+                    {
+                        // define thread attributes
+                        exec_attr[tid].attributes = PT_ATTR_CLUSTER_DEFINED |
+                                                    PT_ATTR_CORE_DEFINED;
+                        exec_attr[tid].cxy        = cxy;
+                        exec_attr[tid].lid        = l;
   
-                    // create thread on core[cxy,l]
-                    if (pthread_create( &trdid[cxy][l],    
-                                        &attr[cxy][l],    
-                                        &execute,
-                                        &tid[cxy][l] ) )       
+                        // create thread[tid] on core[cxy][l]
+                        if ( pthread_create( &exec_trdid[tid],    
+                                             &exec_attr[tid],    
+                                             &execute,
+                                             &exec_args[tid] ) )       
+                        {
+                            printf("\n[transpose error] cannot create thread %d\n", tid );
+                            exit( 0 );
+                        }
+#if VERBOSE_MAIN 
+printf("\n[transpose] main created thread[%d] on core[%x,%d]\n", tid, cxy, l );
+#endif
+                    }
+                    else
                     {
-                        printf("\n[convol error] created thread %x on core[%x][%d]\n",
-                        trdid[cxy][l] , cxy , l );
-                        exit( 0 );
+                        tid_main = tid;
                     }
-#if VERBOSE 
-printf("\n[transpose] main created thread[%x,%d]\n", cxy, l );
-#endif
                 }
             }
         }
-    }    
-
-    // main thread calls itself the execute() function
-    execute( &tid[cxy_main][lid_main] );
-
-    // main thread wait other threads completion
-    for( x = 0 ; x < x_size ; x++ )
-    {
-        for( y = 0 ; y < y_size ; y++ )
+
+        // main thread calls itself the execute() function
+        execute( &exec_args[tid_main] );
+
+        // main thread wait other threads completion
+        for( tid = 0 ; tid < nthreads ; tid++ )
         {
-            cxy = HAL_CXY_FROM_XY( x , y );
-            for( l = 0 ; l < ncores ; l++ )
+            // no other thread on the core running the main
+            if( tid != tid_main )
             {
-                // no other thread on the core running the main
-                if( (cxy != cxy_main) || (l != lid_main) )
+                unsigned int * status;
+
+                // wait thread[tid]
+                if( pthread_join( exec_trdid[tid] , (void*)(&status) ) )
                 {
-                    unsigned int * status;
-
-                    // wait thread[cxy][l]
-                    if( pthread_join( trdid[cxy][l] , (void*)(&status) ) )
-                    {
-                        printf("\n[transpose error] main cannot join thread[%x,%d]\n", cxy, l );
-                        exit( 0 );
-                    }
+                    printf("\n[transpose error] main cannot join thread %d\n", tid );
+                    exit( 0 );
+                }
        
-                    // check status
-                    if( *status != THREAD_EXIT_SUCCESS )
-                    {
-                        printf("\n[transpose error] thread[%x,%d] returned failure\n", cxy, l );
-                        exit( 0 );
-                    }
-#if VERBOSE 
-printf("\n[transpose] main joined thread[%x,%d]\n", cxy, l );
-#endif
+                // check status
+                if( *status != THREAD_EXIT_SUCCESS )
+                {
+                    printf("\n[transpose error] thread %d returned failure\n", tid );
+                    exit( 0 );
                 }
+#if VERBOSE_MAIN 
+printf("\n[transpose] main joined thread %d on core[%x,%d]\n", tid , cxy , l );
+#endif
             }
         }
-    }
-
-///////////////////////////////
-#else  // no explicit placement
-
-    // main thread launch other threads 
-    unsigned int n;
-    for ( n = 1 ; n < nthreads ; n++ )
-    {
-        tid[n] = n;
-        if ( pthread_create( &trdid[n], 
-                             NULL,                  // no attribute
-                             &execute,
-                             &tid[n] ) ) 
+    }  // end if explicit_placement
+
+    ////////////////////////
+    if( PARALLEL_PLACEMENT )
+    {
+        // compute covering DQT size an level
+        unsigned int z          = (x_size > y_size) ? x_size : y_size;
+        unsigned int root_level = ((z == 1) ? 0 : 
+                                  ((z == 2) ? 1 : 
+                                  ((z == 4) ? 2 : 
+                                  ((z == 8) ? 3 : 4))));
+
+        // create & execute the working threads
+        if( pthread_parallel_create( root_level , &execute ) )
         {
-            printf("\n[transpose error] cannot create thread %d\n", n );
+            printf("\n[transpose error] in %s\n", __FUNCTION__ );
             exit( 0 );
         }
-
-#if VERBOSE
-printf("\n[transpose] main created thread %d\n", tid[n] );
-#endif
-
-    }
-
-    // main thread calls itself the execute() function
-    execute( &tid[0] );
-
-    // main thread wait other threads completion
-    for ( n = 1 ; n < nthreads ; n++ )
-    {
-        unsigned int * status;
-
-        // main wait thread[n] status
-        if ( pthread_join( trdid[n], (void*)(&status)) )
-        {
-            printf("\n[transpose error] main cannot join thread %d\n", n );
-            exit( 0 );
-        }
-       
-        // check status
-        if( *status != THREAD_EXIT_SUCCESS )
-        {
-            printf("\n[transpose error] thread %x returned failure\n", n );
-            exit( 0 );
-        }
-
-#if VERBOSE 
-printf("\n[transpose] main successfully joined thread %x\n", tid[n] );
-#endif
-        
-    }
-
-#endif
-
-    // instrumentation
-    instrument();
-
-    // close input and output files 
+    }  // end if parallel_placement
+
+
+    /////////////////////////////////////////////////////////////////////////////
+    get_cycle( &end_parallel_cycle );
+    PARALLEL_TIME = (unsigned int)(end_parallel_cycle - end_sequencial_cycle);
+    /////////////////////////////////////////////////////////////////////////////
+
+    // main thread register instrumentation results
+    instrument( f , filename );
+
+    // main thread close input file 
     close( fd_in );
+
+#if SAVE_RESULT_IMAGE
+
+    // main thread close output file 
     close( fd_out );
 
-    // suicide
+#endif
+
+    // main close instrumentation file
+    fclose( f );
+
+    // main thread suicide
     exit( 0 );
     
@@ -390,174 +590,241 @@
 
 
-///////////////////////////////////
-void execute( unsigned int * ptid )
+
+///////////////////////////////////////////////////
+void execute( pthread_parallel_work_args_t * args )
 {
     unsigned long long   date;
  
-    unsigned int l;                         // line index for loops
-    unsigned int p;                         // pixel index for loops
-
-    // get thread continuous index 
-    unsigned int my_tid = *ptid;
+    unsigned int l;                         // line index for loop
+    unsigned int p;                         // pixel index for loop
+
+    // WARNING 
+    //A thread is identified by the tid index, defined in the "args" structure.
+    // This index being in range [0,nclusters*ncores-1] we can always write
+    //       tid == cid * ncores + lid 
+    // with cid in [0,nclusters-1] and lid in [0,ncores-1].
+    // if NO_PLACEMENT, there is no relation between these
+    // thread [cid][lid] indexes, and the core coordinates [cxy][lpid]
+
+    // get thread abstract identifiers 
+    unsigned int tid = args->tid;
+    unsigned int cid = tid / ncores;   
+    unsigned int lid = tid % ncores;
+
+#if VERBOSE_EXEC
+unsigned int cxy;
+unsigned int lpid;
+get_core_id( &cxy , &lpid );   // get core physical identifiers
+printf("\n[transpose] exec[%d] on core[%x,%d] enters parallel exec\n",
+tid , cxy , lpid );
+#endif
+
+    get_cycle( &date );
+    LOAD_START[cid][lid] = (unsigned int)date;
 
     // build total number of pixels per image
     unsigned int npixels = IMAGE_SIZE * IMAGE_SIZE;      
 
-    // nuild total number of threads and clusters
-    unsigned int nthreads  = x_size * y_size * ncores;
+    // build total number of threads and clusters
     unsigned int nclusters = x_size * y_size;
-
-    // get cluster continuous index and core index from tid
-    // we use (tid == cid * ncores + lid) 
-    unsigned int cid = my_tid / ncores;     // continuous index   
-    unsigned int lid = my_tid % ncores;     // core local index
-
-    // get cluster identifier from cid
-    // we use (cid == x * y_size + y)
-    unsigned int x   = cid / y_size;        // X cluster coordinate
-    unsigned int y   = cid % y_size;        // Y cluster coordinate
-    unsigned int cxy = HAL_CXY_FROM_XY(x,y);
-    
-#if VERBOSE
-printf("\n[transpose] thread[%d] start on core[%x,%d]\n", my_tid , cxy , lid );
-#endif
-
-    // In each cluster cxy,  thread[cxy,0] map input file
-    // to buf_in[cxy] and map output file to buf_in[cxy] 
-
-    get_cycle( &date );
-    MMAP_START[cxy][lid] = (unsigned int)date;
-
-    if ( lid == 0 ) 
-    {
-        unsigned int length = npixels / nclusters;
-        unsigned int offset = length * cid;
-        
-        // map buf_in
-        buf_in[cid] =  mmap( NULL,
-                             length,
-                             PROT_READ,
-                             MAP_SHARED,
-                             fd_in,
-                             offset );
-
-        if ( buf_in[cid] == NULL )
+    unsigned int nthreads  = nclusters * ncores;
+
+    unsigned int buf_size = npixels / nclusters;     // number of bytes in buf_in & buf_out
+    unsigned int offset   = cid * buf_size;       // offset in file (bytes)
+
+    unsigned char  * buf_in = NULL;        // private pointer on local input buffer
+    unsigned char  * buf_out = NULL;       // private pointer on local output buffer
+
+    // Each thread[cid,0] allocate a local buffer buf_in, and register
+    // the base adress in the global variable buf_in_ptr[cid]
+    // this local buffer is shared by all threads with the same cid
+    if( lid == 0 )
+    {
+        // allocate buf_in
+        buf_in = (unsigned char *)malloc( buf_size );
+
+        if( buf_in == NULL )
         {
-            printf("\n[transpose error] thread[%x,%d] cannot map input file\n", cxy, lid);
+            printf("\n[transpose error] thread[%d] cannot allocate buf_in\n", tid );
             pthread_exit( &THREAD_EXIT_FAILURE );
         }
-                 
-#if VERBOSE
-printf("\n[transpose] thread[%x,%d] map input file / length %x / offset %x / buf_in %x\n",
-cxy, lid, length, offset, buf_in[cid] );
-#endif
-
-        // map buf_out           
-        buf_out[cid] = mmap( NULL,
-                             length,
-                             PROT_WRITE,
-                             MAP_SHARED,
-                             fd_out,
-                             offset );
-
-        if ( buf_out[cid] == NULL )
+
+        // register buf_in buffer in global array of pointers
+        buf_in_ptr[cid] = buf_in;
+
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core[%x,%d] allocated buf_in = %x\n",
+tid , cxy , lpid , buf_in );
+#endif
+
+    }
+
+    // Each thread[cid,0] copy relevant part of the image_in to buf_in
+    if( lid == 0 )
+    {
+        memcpy( buf_in,
+                image_in + offset,
+                buf_size );
+    } 
+
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core[%x,%d] loaded buf_in[%d]\n",
+tid , cxy , lpid , cid );
+#endif
+
+    // Each thread[cid,0] allocate a local buffer buf_out, and register
+    // the base adress in the global variable buf_out_ptr[cid]
+    if( lid == 0 )
+    {
+        // allocate buf_out
+        buf_out = (unsigned char *)malloc( buf_size );
+
+        if( buf_out == NULL )
         {
-            printf("\n[transpose error] thread[%x,%d] cannot map output file\n", cxy, lid);
+            printf("\n[transpose error] thread[%d] cannot allocate buf_in\n", tid );
             pthread_exit( &THREAD_EXIT_FAILURE );
         }
-                   
-#if VERBOSE
-printf("\n[transpose] thread[%x,%d] map output file / length %x / offset %x / buf_out %x\n",
-cxy, lid, length, offset, buf_out[cid] );
-#endif
-
-    }
-
+
+        // register buf_in buffer in global array of pointers
+        buf_out_ptr[cid] = buf_out;
+
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core[%x,%d] allocated buf_out = %x\n",
+tid , cxy , lpid , buf_out );
+#endif
+
+    }
+    
     get_cycle( &date );
-    MMAP_END[cxy][lid] = (unsigned int)date;
+    LOAD_END[cid][lid] = (unsigned int)date;
 
     /////////////////////////////////
     pthread_barrier_wait( &barrier );
 
-    // parallel transpose from buf_in to buf_out
-    // each thread makes the transposition for nlt lines (nlt = IMAGE_SIZE/nthreads)
+    get_cycle( &date );
+    TRSP_START[cid][lid] = (unsigned int)date;
+
+    // All threads contribute to parallel transpose from buf_in to buf_out
+    // each thread makes the transposition for nlt lines (nlt = npixels/nthreads)
     // from line [tid*nlt] to line [(tid + 1)*nlt - 1]
     // (p,l) are the absolute pixel coordinates in the source image
+    // (l,p) are the absolute pixel coordinates in the source image
+    // (p,l) are the absolute pixel coordinates in the dest image
 
     get_cycle( &date );
-    TRSP_START[cxy][lid] = (unsigned int)date;
+    TRSP_START[cid][lid] = (unsigned int)date;
 
     unsigned int nlt   = IMAGE_SIZE / nthreads;    // number of lines per thread
     unsigned int nlc   = IMAGE_SIZE / nclusters;   // number of lines per cluster
 
-    unsigned int src_cluster;
+    unsigned int src_cid;
     unsigned int src_index;
-    unsigned int dst_cluster;
+    unsigned int dst_cid;
     unsigned int dst_index;
 
     unsigned char byte;
 
-    unsigned int first = my_tid * nlt;     // first line index for a given thread
+    unsigned int first = tid * nlt;     // first line index for a given thread
     unsigned int last  = first + nlt;      // last line index for a given thread
 
+    // loop on lines handled by this thread
     for ( l = first ; l < last ; l++ )
     {
-        // in each iteration we transfer one byte
+        // loop on pixels in one line (one pixel per iteration)
         for ( p = 0 ; p < IMAGE_SIZE ; p++ )
         {
             // read one byte from local buf_in
-            src_cluster = l / nlc;
-            src_index   = (l % nlc) * IMAGE_SIZE + p;
-            byte        = buf_in[src_cluster][src_index];
+            src_cid   = l / nlc;
+            src_index = (l % nlc) * IMAGE_SIZE + p;
+
+            byte        = buf_in_ptr[src_cid][src_index];
 
             // write one byte to remote buf_out
-            dst_cluster = p / nlc; 
-            dst_index   = (p % nlc) * IMAGE_SIZE + l;
-
-            buf_out[dst_cluster][dst_index] = byte;
+            dst_cid   = p / nlc; 
+            dst_index = (p % nlc) * IMAGE_SIZE + l;
+
+            buf_out_ptr[dst_cid][dst_index] = byte;
         }
     }
 
-#if VERBOSE
-printf("\n[transpose] thread[%x,%d] completes transposed\n", cxy, lid );
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core[%x,%d] completes transpose\n",
+tid , cxy , lpid );
 #endif
 
     get_cycle( &date );
-    TRSP_END[cxy][lid] = (unsigned int)date;
+    TRSP_END[cid][lid] = (unsigned int)date;
 
     /////////////////////////////////
     pthread_barrier_wait( &barrier );
 
-    // parallel display from local buf_out to frame buffer
-    // all threads contribute to display 
-
     get_cycle( &date );
-    DISP_START[cxy][lid] = (unsigned int)date;
-
+    DISP_START[cid][lid] = (unsigned int)date;
+
+    // All threads contribute to parallel display 
+    // from local buf_out to frame buffer
     unsigned int  npt   = npixels / nthreads;   // number of pixels per thread
 
-    if( fbf_write( &buf_out[cid][lid * npt], 
+    if( fbf_write( &buf_out_ptr[cid][lid * npt], 
                    npt,
-                   npt * my_tid ) )
-    {
-        printf("\n[transpose error] thread[%x,%d] cannot access FBF\n", cxy, lid );
+                   npt * tid ) )
+    {
+        printf("\n[transpose error] thread[%d] cannot access FBF\n", tid );
         pthread_exit( &THREAD_EXIT_FAILURE );
     }
 
-#if VERBOSE
-printf("\n[transpose] thread[%x,%d] completes display\n", cxy, lid );
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core [%x,%d] completes display\n",
+tid, cxy , lpid );
 #endif
 
     get_cycle( &date );
-    DISP_END[cxy][lid] = (unsigned int)date;
+    DISP_END[cid][lid] = (unsigned int)date;
 
     /////////////////////////////////
     pthread_barrier_wait( &barrier );
 
-    // all threads, but thread[0,0,0], suicide
-    if ( (cxy != cxy_main) || (lid !=  lid_main) )
-    { 
+#if SAVE_RESULT_IMAGE
+
+    // Each thread[cid,0] copy buf_out to relevant part of image_out
+    if( lid == 0 )
+    {
+        memcpy( image_out + offset,
+                buf_out,
+                buf_size );
+    } 
+
+#if VERBOSE_EXEC
+printf("\n[transpose] exec[%d] on core[%x,%d] saved buf_out[%d]\n",
+tid , cxy , lpid , cid );
+#endif
+
+#endif
+
+    // Each thread[cid,0] releases local buffer buf_out
+    if( lid == 0 )
+    {
+        // release buf_out
+        free( buf_in );
+        free( buf_out );
+    }
+    
+    // thread termination depends on the placement policy
+    if( PARALLEL_PLACEMENT )   
+    {
+        // <work> threads are runing in detached mode
+        // each thread must signal completion by calling barrier
+        // passed in arguments before exit
+
+        pthread_barrier_wait( args->barrier );
+
         pthread_exit( &THREAD_EXIT_SUCCESS );
     }
+    else
+    {
+        // <work> threads are running in attached mode
+        // each thread, but de main, simply exit
+        if ( tid != tid_main )  pthread_exit( &THREAD_EXIT_SUCCESS );
+    }
 
 } // end execute()
@@ -565,8 +832,13 @@
 
 
-///////////////////////
-void instrument( void )
+///////////////////////////
+void instrument( FILE * f,
+                 char * filename )
 {
     unsigned int x, y, l;
+
+#if VERBOSE_EXEC
+printf("\n[transpose] main enters instrument\n" );
+#endif
 
     unsigned int min_load_start = 0xFFFFFFFF;
@@ -583,92 +855,63 @@
     unsigned int max_disp_ended = 0;
  
-    char string[64];
-
-    snprintf( string , 64 , "/home/transpose_%d_%d_%d" , x_size , y_size , ncores );
-
-    // open instrumentation file
-    FILE * f = fopen( string , NULL );
-    if ( f == NULL ) 
-    { 
-        printf("\n[transpose error] cannot open instrumentation file %s\n", string );
-        exit( 0 );
-    }
-
     for (x = 0; x < x_size; x++)
     {
         for (y = 0; y < y_size; y++)
         {
-            unsigned int cxy = HAL_CXY_FROM_XY( x , y );
+            unsigned int cid = y_size * x + y;
 
             for ( l = 0 ; l < ncores ; l++ )
             {
-                if (MMAP_START[cxy][l] < min_load_start)  min_load_start = MMAP_START[cxy][l];
-                if (MMAP_START[cxy][l] > max_load_start)  max_load_start = MMAP_START[cxy][l];
-                if (MMAP_END[cxy][l]   < min_load_ended)  min_load_ended = MMAP_END[cxy][l]; 
-                if (MMAP_END[cxy][l]   > max_load_ended)  max_load_ended = MMAP_END[cxy][l];
-                if (TRSP_START[cxy][l] < min_trsp_start)  min_trsp_start = TRSP_START[cxy][l];
-                if (TRSP_START[cxy][l] > max_trsp_start)  max_trsp_start = TRSP_START[cxy][l];
-                if (TRSP_END[cxy][l]   < min_trsp_ended)  min_trsp_ended = TRSP_END[cxy][l];
-                if (TRSP_END[cxy][l]   > max_trsp_ended)  max_trsp_ended = TRSP_END[cxy][l];
-                if (DISP_START[cxy][l] < min_disp_start)  min_disp_start = DISP_START[cxy][l];
-                if (DISP_START[cxy][l] > max_disp_start)  max_disp_start = DISP_START[cxy][l];
-                if (DISP_END[cxy][l]   < min_disp_ended)  min_disp_ended = DISP_END[cxy][l];
-                if (DISP_END[cxy][l]   > max_disp_ended)  max_disp_ended = DISP_END[cxy][l];
+                if (LOAD_START[cid][l] < min_load_start)  min_load_start = LOAD_START[cid][l];
+                if (LOAD_START[cid][l] > max_load_start)  max_load_start = LOAD_START[cid][l];
+                if (LOAD_END[cid][l]   < min_load_ended)  min_load_ended = LOAD_END[cid][l]; 
+                if (LOAD_END[cid][l]   > max_load_ended)  max_load_ended = LOAD_END[cid][l];
+                if (TRSP_START[cid][l] < min_trsp_start)  min_trsp_start = TRSP_START[cid][l];
+                if (TRSP_START[cid][l] > max_trsp_start)  max_trsp_start = TRSP_START[cid][l];
+                if (TRSP_END[cid][l]   < min_trsp_ended)  min_trsp_ended = TRSP_END[cid][l];
+                if (TRSP_END[cid][l]   > max_trsp_ended)  max_trsp_ended = TRSP_END[cid][l];
+                if (DISP_START[cid][l] < min_disp_start)  min_disp_start = DISP_START[cid][l];
+                if (DISP_START[cid][l] > max_disp_start)  max_disp_start = DISP_START[cid][l];
+                if (DISP_END[cid][l]   < min_disp_ended)  min_disp_ended = DISP_END[cid][l];
+                if (DISP_END[cid][l]   > max_disp_ended)  max_disp_ended = DISP_END[cid][l];
             }
         }
     }
 
-    printf( "\n ------ %s ------\n" , string );
-    fprintf( f , "\n ------ %s ------\n" , string );
-
-    printf( " - MMAP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
-           max_load_start-min_load_start ); 
-
-    fprintf( f , " - MMAP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_load_start, max_load_start, (min_load_start+max_load_start)/2, 
-           max_load_start-min_load_start ); 
-
-    printf( " - MMAP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
-           max_load_ended-min_load_ended ); 
-
-    fprintf( f , " - MMAP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2, 
-           max_load_ended-min_load_ended ); 
-
-    printf( " - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
-           max_trsp_start-min_trsp_start ); 
-
-    fprintf( f , " - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2, 
-           max_trsp_start-min_trsp_start ); 
-
-    printf( " - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
-           max_trsp_ended-min_trsp_ended ); 
-
-    fprintf( f , " - TRSP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2, 
-           max_trsp_ended-min_trsp_ended ); 
-
-    printf( " - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
-           max_disp_start-min_disp_start ); 
-
-    fprintf( f , " - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
-           min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2, 
-           max_disp_start-min_disp_start ); 
-
-    printf( " - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
-           max_disp_ended-min_disp_ended ); 
-
-    fprintf( f , " - DISP_END   : min = %d / max = %d / med = %d / delta = %d\n",
-           min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2, 
-           max_disp_ended-min_disp_ended ); 
-
-    fclose( f );
+    printf( "\n ------ %s ------\n" , filename );
+    fprintf( f , "\n ------ %s ------\n" , filename );
+
+    printf( " - LOAD_START : min = %d / max = %d / delta = %d\n",
+           min_load_start, max_load_start, max_load_start-min_load_start ); 
+    fprintf( f , " - LOAD_START : min = %d / max = %d / delta = %d\n",
+           min_load_start, max_load_start, max_load_start-min_load_start ); 
+
+    printf( " - LOAD_END   : min = %d / max = %d / delta = %d\n",
+           min_load_ended, max_load_ended, max_load_ended-min_load_ended ); 
+    fprintf( f , " - LOAD_END   : min = %d / max = %d / delta = %d\n",
+           min_load_ended, max_load_ended, max_load_ended-min_load_ended ); 
+
+    printf( " - TRSP_START : min = %d / max = %d / delta = %d\n",
+           min_trsp_start, max_trsp_start, max_trsp_start-min_trsp_start ); 
+    fprintf( f , " - TRSP_START : min = %d / max = %d / delta = %d\n",
+           min_trsp_start, max_trsp_start, max_trsp_start-min_trsp_start ); 
+
+    printf( " - TRSP_END   : min = %d / max = %d / delta = %d\n",
+           min_trsp_ended, max_trsp_ended, max_trsp_ended-min_trsp_ended ); 
+    fprintf( f , " - TRSP_END   : min = %d / max = %d / delta = %d\n",
+           min_trsp_ended, max_trsp_ended, max_trsp_ended-min_trsp_ended ); 
+
+    printf( " - DISP_START : min = %d / max = %d / delta = %d\n",
+           min_disp_start, max_disp_start, max_disp_start-min_disp_start ); 
+    fprintf( f , " - DISP_START : min = %d / max = %d / delta = %d\n",
+           min_disp_start, max_disp_start, max_disp_start-min_disp_start ); 
+
+    printf( " - DISP_END   : min = %d / max = %d / delta = %d\n",
+           min_disp_ended, max_disp_ended, max_disp_ended-min_disp_ended ); 
+    fprintf( f , " - DISP_END   : min = %d / max = %d / delta = %d\n",
+           min_disp_ended, max_disp_ended, max_disp_ended-min_disp_ended ); 
+
+    printf( "\n   Sequencial = %d / Parallel = %d\n", SEQUENCIAL_TIME, PARALLEL_TIME );
+    fprintf( f , "\n   Sequencial = %d / Parallel = %d\n", SEQUENCIAL_TIME, PARALLEL_TIME );
 
 }  // end instrument()
