////////////////////////////////////////////////////////////////////////////////////////// // File : transpose.c // Date : september 2019 // author : Alain Greiner ////////////////////////////////////////////////////////////////////////////////////////// // This multi-threaded aplication read a raw image (one byte per pixel) // stored on disk, transposes it, displays the result on the frame buffer, // and stores the transposed image on disk. // // The image size and the pixel encoding type are defined by the IMAGE_SIZE and // IMAGE_TYPE global parameters. // // 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 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 threads cannot be larger than IMAGE_SIZE. // ////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #define X_MAX 16 // max number of clusters in row #define Y_MAX 16 // max number of clusters in column #define CORES_MAX 4 // max number of cores per cluster #define CLUSTERS_MAX (X_MAX * Y_MAX) // max number of clusters #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/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 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 /////////////////////////////////////////////////////// // global variables /////////////////////////////////////////////////////// // 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 }}; unsigned int DISP_START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }}; unsigned int DISP_END [CLUSTERS_MAX][CORES_MAX] = {{ 0 }}; // 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 cores per cluster // main thread continuous index unsigned int tid_main; //return values at thread exit unsigned int THREAD_EXIT_SUCCESS = 0; 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( pthread_parallel_work_args_t * args ); void instrument( FILE * f , char * filename ); ///////////////// void main( void ) { 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; ///////////////////////////////////////////////////////////////////////////////// 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 ); if((ncores != 1) && (ncores != 2) && (ncores != 4)) { printf("\n[transpose error] number of cores per cluster must be 1/2/4\n"); exit( 0 ); } if( (x_size != 1) && (x_size != 2) && (x_size != 4) && (x_size != 8) && (x_size != 16) ) { printf("\n[transpose error] x_size must be 1/2/4/8/16\n"); exit( 0 ); } if( (y_size != 1) && (y_size != 2) && (y_size != 4) && (y_size != 8) && (y_size != 16) ) { printf("\n[transpose error] y_size must be 1/2/4/8/16\n"); exit( 0 ); } // 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 unsigned int nclusters = x_size * y_size; unsigned int nthreads = nclusters * ncores; // main thread get FBF size and type unsigned int fbf_width; unsigned int fbf_height; unsigned int fbf_type; fbf_get_config( &fbf_width , &fbf_height , &fbf_type ); if( (fbf_width != IMAGE_SIZE) || (fbf_height != IMAGE_SIZE) || (fbf_type != IMAGE_TYPE) ) { printf("\n[transpose error] image does not fit FBF size or type\n"); exit( 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] 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 ) { pthread_barrierattr_t attr; attr.x_size = x_size; attr.y_size = y_size; attr.nthreads = ncores; error = pthread_barrier_init( &barrier, &attr , nthreads ); } else { error = pthread_barrier_init( &barrier, NULL , nthreads ); } if( error ) { printf("\n[transpose error] main cannot initialize barrier\n" ); exit( 0 ); } #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++ ) { // register tid value in exec_args[tid] array exec_args[tid].tid = tid; // create other threads if( tid > 0 ) { if ( pthread_create( &exec_trdid[tid], NULL, // no attribute &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\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[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 { tid_main = tid; } } } } // main thread calls itself the execute() function execute( &exec_args[tid_main] ); // main thread wait other threads completion for( tid = 0 ; tid < nthreads ; tid++ ) { // no other thread on the core running the main if( tid != tid_main ) { unsigned int * status; // wait thread[tid] 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 %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 } } } // 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] in %s\n", __FUNCTION__ ); exit( 0 ); } } // 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 ); #endif // main close instrumentation file fclose( f ); // main thread suicide exit( 0 ); } // end main() /////////////////////////////////////////////////// void execute( pthread_parallel_work_args_t * args ) { unsigned long long date; 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; // build total number of threads and clusters unsigned int nclusters = x_size * y_size; 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[%d] cannot allocate buf_in\n", tid ); pthread_exit( &THREAD_EXIT_FAILURE ); } // 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[%d] cannot allocate buf_in\n", tid ); pthread_exit( &THREAD_EXIT_FAILURE ); } // 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 ); LOAD_END[cid][lid] = (unsigned int)date; ///////////////////////////////// pthread_barrier_wait( &barrier ); 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[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_cid; unsigned int src_index; unsigned int dst_cid; unsigned int dst_index; unsigned char byte; 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++ ) { // 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_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_cid = p / nlc; dst_index = (p % nlc) * IMAGE_SIZE + l; buf_out_ptr[dst_cid][dst_index] = byte; } } #if VERBOSE_EXEC printf("\n[transpose] exec[%d] on core[%x,%d] completes transpose\n", tid , cxy , lpid ); #endif get_cycle( &date ); TRSP_END[cid][lid] = (unsigned int)date; ///////////////////////////////// pthread_barrier_wait( &barrier ); get_cycle( &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_ptr[cid][lid * npt], npt, npt * tid ) ) { printf("\n[transpose error] thread[%d] cannot access FBF\n", tid ); pthread_exit( &THREAD_EXIT_FAILURE ); } #if VERBOSE_EXEC printf("\n[transpose] exec[%d] on core [%x,%d] completes display\n", tid, cxy , lpid ); #endif get_cycle( &date ); DISP_END[cid][lid] = (unsigned int)date; ///////////////////////////////// pthread_barrier_wait( &barrier ); #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 ) { // 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 { // threads are running in attached mode // each thread, but de main, simply exit if ( tid != tid_main ) pthread_exit( &THREAD_EXIT_SUCCESS ); } } // end execute() /////////////////////////// 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; unsigned int max_load_start = 0; unsigned int min_load_ended = 0xFFFFFFFF; unsigned int max_load_ended = 0; unsigned int min_trsp_start = 0xFFFFFFFF; unsigned int max_trsp_start = 0; unsigned int min_trsp_ended = 0xFFFFFFFF; unsigned int max_trsp_ended = 0; unsigned int min_disp_start = 0xFFFFFFFF; unsigned int max_disp_start = 0; unsigned int min_disp_ended = 0xFFFFFFFF; unsigned int max_disp_ended = 0; for (x = 0; x < x_size; x++) { for (y = 0; y < y_size; y++) { unsigned int cid = y_size * x + y; for ( l = 0 ; l < ncores ; 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" , 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()