source: trunk/user/convol/convol.c @ 665

Last change on this file since 665 was 659, checked in by alain, 4 years ago

euh...

File size: 39.9 KB
RevLine 
[645]1///////////////////////////////////////////////////////////////////////////////////////
2// File   : convol.c 
3// Date   : june 2014
4// author : Alain Greiner
5///////////////////////////////////////////////////////////////////////////////////////
6// This multi-threaded application implements a 2D convolution product. 
[652]7// It can run on a multi-cores, multi-clusters architecture, with one thread
8// per core, and uses the POSIX threads API.
[645]9//
10// The main() function can be launched on any processor P[x,y,l].
11// It makes the initialisations, launch (N-1) threads to run the execute() function
12// on the (N-1) other processors than P[x,y,l], call himself the execute() function,
13// and finally call the instrument() function to display instrumentation results
14// when the parallel execution is completed.
15//
[652]16// The convolution kernel is defined in the execute() function.
17// It can be factored in two independant line and column convolution products.
[645]18// The five buffers containing the image are distributed in clusters.
[652]19// For the philips image, it is a [201]*[35] pixels rectangle, and the.
[645]20//
21// The (1024 * 1024) pixels image is read from a file (2 bytes per pixel).
22//
23// - number of clusters containing processors must be power of 2 no larger than 256.
[652]24// - number of processors per cluster must be power of 2 no larger than 4.
25//
26// The number N of working threads is always defined by the number of cores availables
27// in the architecture, but this application supports three placement modes.
28// In all modes, the working threads are identified by the [tid] continuous index
29// in range [0, NTHREADS-1], and defines how the lines are shared amongst the threads.
30// This continuous index can always be decomposed in two continuous sub-indexes:
31// tid == cid * ncores + lid,  where cid is in [0,NCLUSTERS-1] and lid in [0,NCORES-1].
32//
33// - NO_PLACEMENT: the main thread is itsef a working thread. The (N_1) other working
34//   threads are created by the main thread, but the placement is done by the OS, using
35//   the DQDT for load balancing, and two working threads can be placed on the same core.
36//   The [cid,lid] are only abstract identifiers, and cannot be associated to a physical
37//   cluster or a physical core. In this mode, the main thread run on any cluster,
38//   but has tid = 0 (i.e. cid = 0 & tid = 0).
39//
40// - EXPLICIT_PLACEMENT: the main thread is again a working thread, but the placement of
41//   of the threads on the cores is explicitely controled by the main thread to have
42//   exactly one working thread per core, and the [cxy][lpid] core coordinates for a given
43//   thread[tid] can be directly derived from the [tid] value: [cid] is an alias for the
44//   physical cluster identifier, and [lid] is the local core index.
45//
46// - PARALLEL_PLACEMENT: the main thread is not anymore a working thread, and uses the
47//   non standard pthread_parallel_create() function to avoid the costly sequencial
48//   loops for pthread_create() and pthread_join(). It garanty one working thread
49//   per core, and the same relation between the thread[tid] and the core[cxy][lpid].
50//
51// The [tid] continuous index defines how the work is shared amongst the threads:
52// - each thread handles NL/nthreads lines for the horizontal filter.
53// - each thread handles NP/nthreads columns for the vertical filter.
[645]54///////////////////////////////////////////////////////////////////////////////////////
55
[652]56#include <sys/mman.h>
[645]57#include <stdio.h>
58#include <stdlib.h>
59#include <fcntl.h>
60#include <unistd.h>
61#include <pthread.h>
[652]62#include <string.h>
[645]63#include <almosmkh.h>
64#include <hal_macros.h>
65
[652]66#define VERBOSE_MAIN               1
[656]67#define VERBOSE_EXEC               0
68#define SUPER_VERBOSE              0
[645]69
70#define X_MAX                      16
71#define Y_MAX                      16
[652]72#define CORES_MAX                  4
[645]73#define CLUSTERS_MAX               (X_MAX * Y_MAX)
[652]74#define THREADS_MAX                (X_MAX * Y_MAX * CORES_MAX)
[645]75
[652]76#define IMAGE_IN_PATH              "misc/philips_1024_2.raw"
77#define IMAGE_IN_PIXEL_SIZE        2                               // 2 bytes per pixel
[645]78
[652]79#define IMAGE_OUT_PATH             "misc/philips_after_1O24.raw"
80#define IMAGE_OUT_PIXEL_SIZE       1                               // 1 bytes per pixel
[645]81
[652]82#define FBF_TYPE                   420
[645]83#define NL                         1024
84#define NP                         1024
85#define NB_PIXELS                  (NP * NL)
86
[652]87#define NO_PLACEMENT               0
88#define EXPLICIT_PLACEMENT         0
89#define PARALLEL_PLACEMENT         1
[645]90
[652]91#define USE_DQT_BARRIER            1
92#define INITIAL_DISPLAY_ENABLE     1
93#define FINAL_DISPLAY_ENABLE       1
94
[645]95#define TA(c,l,p)  (A[c][((NP) * (l)) + (p)])
96#define TB(c,p,l)  (B[c][((NL) * (p)) + (l)])
97#define TC(c,l,p)  (C[c][((NP) * (l)) + (p)])
98#define TD(c,l,p)  (D[c][((NP) * (l)) + (p)])
99#define TZ(c,l,p)  (Z[c][((NP) * (l)) + (p)])
100
101#define max(x,y) ((x) > (y) ? (x) : (y))
102#define min(x,y) ((x) < (y) ? (x) : (y))
103
104//////////////////////////////////////////////////////////
[652]105//            global variables
[645]106//////////////////////////////////////////////////////////
107
[652]108// global instrumentation counters for the main thread
109unsigned int SEQUENCIAL_TIME = 0;
110unsigned int PARALLEL_TIME   = 0;
[645]111
[652]112// instrumentation counters for thread[tid] in cluster[cid]
113unsigned int START[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
114unsigned int H_BEG[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
115unsigned int H_END[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
116unsigned int V_BEG[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
117unsigned int V_END[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
118unsigned int D_BEG[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
119unsigned int D_END[CLUSTERS_MAX][CORES_MAX] = {{ 0 }};
[645]120
[652]121// pointer on buffer containing the input image, maped by the main to the input file
122unsigned char *  image_in;
123
124// pointer on buffer containing the output image, maped by the main to the output file
125unsigned char *  image_out;
126
[645]127// return values at thread exit
128unsigned int THREAD_EXIT_SUCCESS = 0;
129unsigned int THREAD_EXIT_FAILURE = 1;
130
131// synchronization barrier
132pthread_barrier_t     barrier;
133
[652]134// platform parameters
135unsigned int  x_size;              // number of clusters in a row
136unsigned int  y_size;              // number of clusters in a column
137unsigned int  ncores;              // number of processors per cluster
[645]138
139// arrays of pointers on distributed buffers in all clusters
140unsigned short * GA[CLUSTERS_MAX];
[652]141int            * GB[CLUSTERS_MAX];
142int            * GC[CLUSTERS_MAX];
143int            * GD[CLUSTERS_MAX];
144unsigned char  * GZ[CLUSTERS_MAX];
[645]145
[652]146// array of threads kernel identifiers / indexed by [tid]
147pthread_t        exec_trdid[THREADS_MAX];
[645]148
[652]149// array of threads attributes / indexed bi [tid]
150pthread_attr_t   exec_attr[THREADS_MAX]; 
[645]151
[652]152// array of execute() function arguments / indexed by [tid]
153pthread_parallel_work_args_t exec_args[THREADS_MAX];
154
155// main thread continuous index
156unsigned int     tid_main;
157
[645]158/////////////////////////////////////////////////////////////////////////////////////
159//           functions declaration
160/////////////////////////////////////////////////////////////////////////////////////
161
[656]162void * execute( void * args );
[645]163
[652]164void instrument( FILE * f , char * filename );
[645]165
166/////////////////
167void main( void )
168{
[652]169    unsigned long long start_cycle;
170    unsigned long long end_sequencial_cycle;
171    unsigned long long end_parallel_cycle;
[645]172
[652]173    int          error;
[645]174
[652]175    char         instru_name[32];               // instrumentation file name
[656]176    char         instru_path[64];               // instrumentation path name
[645]177
[652]178    /////////////////////////////////////////////////////////////////////////////////
179    get_cycle( &start_cycle );
180    /////////////////////////////////////////////////////////////////////////////////
[645]181
[652]182    if( (NO_PLACEMENT + EXPLICIT_PLACEMENT + PARALLEL_PLACEMENT) != 1 )
[645]183    {
[652]184        printf("\n[convol error] illegal placement\n");
[645]185        exit( 0 );
186    }
187
[652]188    // get & check platform parameters
[659]189    hard_config_t  config;
190    get_config( &config );
191    x_size = config.x_size;
192    y_size = config.y_size;
193    ncores = config.ncores;
[652]194
195    if((ncores != 1) && (ncores != 2) && (ncores != 4))
[645]196    {
197        printf("\n[convol error] number of cores per cluster must be 1/2/4\n");
198        exit( 0 );
199    }
200
[652]201    if( (x_size != 1) && (x_size != 2) && (x_size != 4) && 
202        (x_size != 8) && (x_size != 16) )
[645]203    {
204        printf("\n[convol error] x_size must be 1/2/4/8/16\n");
205        exit( 0 );
206    }
[652]207       
208    if( (y_size != 1) && (y_size != 2) && (y_size != 4) && 
209        (y_size != 8) && (y_size != 16) )
[645]210    {
211        printf("\n[convol error] y_size must be 1/2/4/8/16\n");
212        exit( 0 );
213    }
[652]214       
215    // main thread get identifiers for core executing main
216    unsigned int  cxy_main;
217    unsigned int  lid_main;
218    get_core_id( &cxy_main , &lid_main );
[645]219
220    // compute nthreads and nclusters
221    unsigned int nclusters = x_size * y_size;
[652]222    unsigned int nthreads  = nclusters * ncores;
[645]223
[652]224    // main thread get FBF size and type
225    unsigned int   fbf_width;
226    unsigned int   fbf_height;
227    unsigned int   fbf_type;
228    fbf_get_config( &fbf_width , &fbf_height , &fbf_type );
[645]229
[652]230    if( (fbf_width != NP) || (fbf_height != NL) || (fbf_type != FBF_TYPE) )
231    {
232        printf("\n[convol error] image does not fit FBF size or type\n");
233        exit( 0 );
234    }
[645]235
[652]236    if( nthreads > NL )
237    {
238        printf("\n[convol error] number of threads larger than number of lines\n");
[645]239        exit( 0 );
240    }
241
[652]242    // define instrumentation file name
243    if( NO_PLACEMENT )
244    {
245        printf("\n[convol] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / NO_PLACE\n",
246        nclusters, ncores, fbf_width, fbf_height, getpid() );
[645]247
[652]248        // build instrumentation file name
249        if( USE_DQT_BARRIER )
250        snprintf( instru_name , 32 , "conv_dqt_no_place_%d_%d", x_size * y_size , ncores );
251        else
252        snprintf( instru_name , 32 , "conv_smp_no_place_%d_%d", x_size * y_size , ncores );
[645]253    }
254
[652]255    if( EXPLICIT_PLACEMENT )
256    {
257        printf("\n[convol] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / EXPLICIT\n",
258        nclusters, ncores, fbf_width, fbf_height, getpid() );
[645]259
[652]260        // build instrumentation file name
261        if( USE_DQT_BARRIER )
[656]262        snprintf( instru_name , 32 , "conv_dqt_explicit_%d_%d", x_size * y_size , ncores );
[652]263        else
[656]264        snprintf( instru_name , 32 , "conv_smp_explicit_%d_%d", x_size * y_size , ncores );
[652]265    }
266
267    if( PARALLEL_PLACEMENT )
[645]268    {
[652]269        printf("\n[convol] %d cluster(s) / %d core(s) / FBF[%d*%d] / PID %x / PARALLEL\n",
270        nclusters, ncores, fbf_width, fbf_height, getpid() );
271
272        // build instrumentation file name
273        if( USE_DQT_BARRIER )
[656]274        snprintf( instru_name , 32 , "conv_dqt_parallel_%d_%d", x_size * y_size , ncores );
[652]275        else
[656]276        snprintf( instru_name , 32 , "conv_smp_parallel_%d_%d", x_size * y_size , ncores );
[645]277    }
278
[652]279    // open instrumentation file
280    snprintf( instru_path , 64 , "/home/%s", instru_name );
281    FILE * f_instru = fopen( instru_path , NULL );
282    if ( f_instru == NULL ) 
283    { 
284        printf("\n[convol error] cannot open instrumentation file %s\n", instru_path );
[645]285        exit( 0 );
286    }
287
[652]288#if  VERBOSE_MAIN
289printf("\n[convol] main on core[%x,%d] open instrumentation file %s\n",
290cxy_main, lid_main, instru_path );
291#endif
292
293    // main initialise barrier
[645]294    if( USE_DQT_BARRIER )
295    {
296        pthread_barrierattr_t attr;
297        attr.x_size   = x_size;
298        attr.y_size   = y_size;
299        attr.nthreads = ncores;
300        error = pthread_barrier_init( &barrier, &attr , nthreads );
301    }
302    else
303    {
304        error = pthread_barrier_init( &barrier, NULL , nthreads );
305    }
306
307    if( error )
308    {
309        printf("\n[convol error] cannot initialize barrier\n");
310        exit( 0 );
311    }
312
[652]313#if VERBOSE_MAIN
314printf("\n[convol] main on core[%x,%d] completes barrier init\n", 
315cxy_main, lid_main );
316#endif
[645]317
[652]318    // main open input file
319    int fd_in = open( IMAGE_IN_PATH , O_RDONLY , 0 );
320
321    if ( fd_in < 0 ) 
322    { 
323        printf("\n[convol error] cannot open input file <%s>\n", IMAGE_IN_PATH );
324        exit( 0 );
325    }
326
327#if VERBOSE_MAIN
328printf("\n[convol] main on core[%x,%d] open file <%s>\n",
329cxy_main, lid_main, IMAGE_IN_PATH );
330#endif
331   
332    // main thread map image_in buffer to input file
333    image_in = (unsigned char *)mmap( NULL,
334                                      NB_PIXELS * IMAGE_IN_PIXEL_SIZE,
335                                      PROT_READ,
336                                      MAP_FILE | MAP_SHARED,
337                                      fd_in,
338                                      0 );           // offset
339    if ( image_in == NULL ) 
340    { 
341        printf("\n[convol error] main cannot map buffer to file %s\n", IMAGE_IN_PATH );
342        exit( 0 );
343    }
344
345#if  VERBOSE_MAIN
346printf("\n[convol] main on core[%x,%x] map buffer to file <%s>\n",
347cxy_main, lid_main, IMAGE_IN_PATH );
348#endif
349
350    // main thread open output file
351    int fd_out = open( IMAGE_OUT_PATH , O_CREAT , 0 ); 
352
353    if ( fd_out < 0 ) 
354    { 
355        printf("\n[convol error] main cannot open file %s\n", IMAGE_OUT_PATH );
356        exit( 0 );
357    }
358
359#if  VERBOSE_MAIN
360printf("\n[convol] main on core[%x,%d] open file <%s>\n",
361cxy_main, lid_main, IMAGE_OUT_PATH );
362#endif
363
364    // main thread map image_out buffer to output file
365    image_out = (unsigned char *)mmap( NULL,
366                                       NB_PIXELS + IMAGE_OUT_PIXEL_SIZE,
367                                       PROT_WRITE,
368                                       MAP_FILE | MAP_SHARED,
369                                       fd_out,
370                                       0 );     // offset
371    if ( image_out == NULL ) 
372    { 
373        printf("\n[convol error] main cannot map buffer to file %s\n", IMAGE_OUT_PATH );
374        exit( 0 );
375    }
376
377#if  VERBOSE_MAIN
378printf("\n[convol] main on core[%x,%x] map buffer to file <%s>\n",
379cxy_main, lid_main, IMAGE_OUT_PATH );
380#endif
381
382    /////////////////////////////////////////////////////////////////////////////////////
383    get_cycle( &end_sequencial_cycle );
384    SEQUENCIAL_TIME = (unsigned int)(end_sequencial_cycle - start_cycle);
385    /////////////////////////////////////////////////////////////////////////////////////
386
[656]387//////////////////
388#if NO_PLACEMENT
389{
390    // the tid value for the main thread is always 0
391    // main thread creates new threads with tid in [1,nthreads-1] 
392    unsigned int tid;
393    for ( tid = 0 ; tid < nthreads ; tid++ )
[645]394    {
[656]395        // register tid value in exec_args[tid] array
396        exec_args[tid].tid = tid;
397         
398        // create other threads
399        if( tid > 0 )
[645]400        {
[656]401            if ( pthread_create( &exec_trdid[tid], 
402                                 NULL,                  // no attribute
403                                 &execute,
404                                 &exec_args[tid] ) ) 
[652]405            {
[656]406                printf("\n[convol error] cannot create thread %d\n", tid );
407                exit( 0 );
408            }
[652]409
410#if VERBOSE_MAIN
411printf("\n[convol] main created thread %d\n", tid );
412#endif
413
[656]414        }
415        else
416        {
417            tid_main = 0;
418        }
419    }  // end for tid
[645]420
[656]421    // main thread calls itself the execute() function
422    execute( &exec_args[0] );
[652]423
[656]424    // main thread wait other threads completion
425    for ( tid = 1 ; tid < nthreads ; tid++ )
426    {
427        unsigned int * status;
428
429        // main wait thread[tid] status
430        if ( pthread_join( exec_trdid[tid], (void*)(&status)) )
[645]431        {
[656]432            printf("\n[convol error] main cannot join thread %d\n", tid );
433            exit( 0 );
434        }
[652]435       
[656]436        // check status
437        if( *status != THREAD_EXIT_SUCCESS )
438        {
439            printf("\n[convol error] thread %x returned failure\n", tid );
440            exit( 0 );
441        }
[645]442
[652]443#if VERBOSE_MAIN
444printf("\n[convol] main successfully joined thread %x\n", tid );
445#endif
446       
[656]447    }  // end for tid
448} 
449#endif // end no_placement
[652]450
[656]451//////////////////////
452#if EXPLICIT_PLACEMENT
453{
454    // main thread places each other threads on a specific core[cxy][lid]
455    // but the actual thread creation is sequencial
456    unsigned int x;
457    unsigned int y;
458    unsigned int l;
459    unsigned int cxy;                   // cluster identifier
460    unsigned int tid;                   // thread continuous index
[652]461
[656]462    for( x = 0 ; x < x_size ; x++ )
[645]463    {
[656]464        for( y = 0 ; y < y_size ; y++ )
[645]465        {
[656]466            cxy = HAL_CXY_FROM_XY( x , y );
467            for( l = 0 ; l < ncores ; l++ )
[645]468            {
[656]469                // compute thread continuous index
470                tid = (((* y_size) + y) * ncores) + l;
[645]471
[656]472                // register tid value in exec_args[tid] array
473                exec_args[tid].tid = tid;
[652]474
[656]475                // no thread created on the core running the main
476                if( (cxy != cxy_main) || (l != lid_main) )
477                {
478                    // define thread attributes
479                    exec_attr[tid].attributes = PT_ATTR_CLUSTER_DEFINED |
480                                                PT_ATTR_CORE_DEFINED;
481                    exec_attr[tid].cxy        = cxy;
482                    exec_attr[tid].lid        = l;
483 
484                    // create thread[tid] on core[cxy][l]
485                    if ( pthread_create( &exec_trdid[tid],   
486                                         &exec_attr[tid],   
487                                         &execute,
488                                         &exec_args[tid] ) )       
[645]489                    {
[656]490                        printf("\n[convol error] cannot create thread %d\n", tid );
491                        exit( 0 );
492                    }
[652]493#if VERBOSE_MAIN
494printf("\n[convol] main created thread[%d] on core[%x,%d]\n", tid, cxy, l );
495#endif
[645]496                }
[656]497                else
498                {
499                    tid_main = tid;
500                }
[645]501            }
502        }
[656]503    }
[652]504
[656]505    // main thread calls itself the execute() function
506    execute( &exec_args[tid_main] );
[652]507
[656]508    // main thread wait other threads completion
509    for( tid = 0 ; tid < nthreads ; tid++ )
510    {
511        // no other thread on the core running the main
512        if( tid != tid_main )
[652]513        {
[656]514            unsigned int * status;
515
516            // wait thread[tid]
517            if( pthread_join( exec_trdid[tid] , (void*)(&status) ) )
[652]518            {
[656]519                printf("\n[convol error] main cannot join thread %d\n", tid );
520                exit( 0 );
521            }
522     
523            // check status
524            if( *status != THREAD_EXIT_SUCCESS )
525            {
526                printf("\n[convol error] thread %d returned failure\n", tid );
527                exit( 0 );
528            }
[652]529#if VERBOSE_MAIN
530printf("\n[convol] main joined thread %d on core[%x,%d]\n", tid , cxy , l );
531#endif
532        }
[656]533    }
534} 
535#endif   // end explicit_placement
[652]536
[656]537//////////////////////
538#if PARALLEL_PLACEMENT
539{
540    // compute covering DQT size an level
541    unsigned int z          = (x_size > y_size) ? x_size : y_size;
542    unsigned int root_level = ((z == 1) ? 0 : 
543                              ((z == 2) ? 1 : 
544                              ((z == 4) ? 2 : 
545                              ((z == 8) ? 3 : 4))));
546
547    // create & execute the working threads
548    if( pthread_parallel_create( root_level , &execute ) )
[645]549    {
[656]550        printf("\n[convol error] in %s\n", __FUNCTION__ );
551        exit( 0 );
552    }
553}
554#endif  // end parallel_placement
[652]555
556    /////////////////////////////////////////////////////////////////////////////
557    get_cycle( &end_parallel_cycle );
558    PARALLEL_TIME = (unsigned int)(end_parallel_cycle - end_sequencial_cycle);
559    /////////////////////////////////////////////////////////////////////////////
560
561    // main thread register instrumentation results
562    instrument( f_instru , instru_name );
563
[656]564#if VERBOSE_MAIN
565printf("\n[convol] main registered instrumentation info\n" );
566#endif
567
[652]568    // main thread close input file
569    close( fd_in );
570
[656]571#if VERBOSE_MAIN
572printf("\n[convol] main closed input file\n" );
573#endif
574
[652]575    // main thread close output file
576    close( fd_out );
577
[656]578#if VERBOSE_MAIN
579printf("\n[convol] main closed output file\n" );
580#endif
581
[652]582    // main thread close instrumentation file
583    fclose( f_instru );
584
[656]585#if VERBOSE_MAIN
586printf("\n[convol] main closed instrumentation file\n" );
587#endif
588
[652]589    // main thread suicide
[645]590    exit( 0 );
591   
592} // end main()
593
594
595
[652]596
597
598
[656]599//////////////////////////////////
600void * execute( void * arguments )
601
[645]602{
603    unsigned long long date;
604
[656]605    pthread_parallel_work_args_t * args = (pthread_parallel_work_args_t *)arguments;
606
[652]607    // Each thread initialises the convolution kernel parameters in local stack.
[645]608    // The values defined in the next 12 lines are Philips proprietary information.
609
610    int   vnorm  = 115;
611    int   vf[35] = { 1, 1, 2, 2, 2,
612                     2, 3, 3, 3, 4,
613                     4, 4, 4, 5, 5,
614                     5, 5, 5, 5, 5,
615                     5, 5, 4, 4, 4,
616                     4, 3, 3, 3, 2,
617                     2, 2, 2, 1, 1 };
618
619    unsigned int hrange = 100;
620    unsigned int hnorm  = 201;
621
[652]622    // WARNING
623    //A thread is identified by the tid index, defined in the "args" structure.
624    // This index being in range [0,nclusters*ncores-1] we can always write
625    //       tid == cid * ncores + lid
626    // with cid in [0,nclusters-1] and lid in [0,ncores-1].
627    // if NO_PLACEMENT, there is no relation between these
628    // thread [cid][lid] indexes, and the core coordinates [cxy][lpid]
[645]629
[652]630    // get thread abstract identifiers
631    unsigned int tid = args->tid;
632    unsigned int cid = tid / ncores;   
633    unsigned int lid = tid % ncores;
[645]634
[652]635#if VERBOSE_EXEC
636unsigned int cxy;              // core cluster identifier
637unsigned int lpid;             // core local identifier
[656]638get_cycle( &date );
[652]639get_core_id( &cxy , &lpid );
[656]640printf("\n[convol] exec[%d] on core[%x,%d] enters parallel exec / cycle %d\n",
641tid , cxy , lpid , (unsigned int)date );
[652]642#endif
643
644    // build total number of threads and clusters from global variables
645    unsigned int nclusters = x_size * y_size;
646    unsigned int nthreads  = nclusters * ncores;
647
[645]648    // indexes for loops
649    unsigned int c;                 // cluster index
650    unsigned int l;                 // line index
651    unsigned int p;                 // pixel index
652    unsigned int z;                 // vertical filter index
653
[652]654    unsigned int lines_per_thread   = NL / nthreads;
655    unsigned int lines_per_cluster  = NL / nclusters;
656    unsigned int pixels_per_thread  = NP / nthreads;
657    unsigned int pixels_per_cluster = NP / nclusters;
[645]658
[652]659    // compute number of pixels stored in one abstract cluster cid
660    unsigned int local_pixels = NL * NP / nclusters;       
661
[645]662    unsigned int first, last;
663
664    get_cycle( &date );
[652]665    START[cid][lid] = (unsigned int)date;
[645]666
[652]667    // Each thread[cid][0] allocates 5 local buffers,
[656]668    // and registers these 5 pointers in the global arrays
[645]669    if ( lid == 0 )
670    {
[652]671        GA[cid] = malloc( local_pixels * sizeof( unsigned short ) );
672        GB[cid] = malloc( local_pixels * sizeof( int ) );
673        GC[cid] = malloc( local_pixels * sizeof( int ) );
674        GD[cid] = malloc( local_pixels * sizeof( int ) );
675        GZ[cid] = malloc( local_pixels * sizeof( unsigned char ) );
[645]676
[652]677        if( (GA[cid] == NULL) || (GB[cid] == NULL) || (GC[cid] == NULL) || 
678            (GD[cid] == NULL) || (GZ[cid] == NULL) )
679        {
680            printf("\n[convol error] thread[%d] cannot allocate buf_in\n", tid );
681            pthread_exit( &THREAD_EXIT_FAILURE );
682        }
[645]683
[652]684#if VERBOSE_EXEC
[656]685get_cycle( &date );
686printf( "\n[convol] exec[%d] on core[%x,%d] allocated shared buffers / cycle %d\n"
687" GA %x / GB %x / GC %x / GD %x / GZ %x\n",
688tid, cxy , lpid, (unsigned int)date, GA[cid], GB[cid], GC[cid], GD[cid], GZ[cid] );
[645]689#endif
690   
691    }
692
693    ////////////////////////////////
694    pthread_barrier_wait( &barrier );
695
[652]696    // Each thread[cid,lid] allocate and initialise in its private stack
697    // a copy of the arrays of pointers on the distributed buffers.
[645]698    unsigned short * A[CLUSTERS_MAX];
699    int            * B[CLUSTERS_MAX];
700    int            * C[CLUSTERS_MAX];
701    int            * D[CLUSTERS_MAX];
702    unsigned char  * Z[CLUSTERS_MAX];
703
704    for( c = 0 ; c < nclusters ; c++ )
705    {
706        A[c] = GA[c];
707        B[c] = GB[c];
708        C[c] = GC[c];
709        D[c] = GD[c];
710        Z[c] = GZ[c];
711    }
712
[652]713    // Each thread[cid,0] access the file containing the input image, to load
714    // the local A[cid] buffer. Other threads are waiting on the barrier.
[645]715    if ( lid==0 )
716    {
[652]717        unsigned int size   = local_pixels * sizeof( unsigned short );
718        unsigned int offset = size * cid;
[645]719
[652]720        memcpy( A[cid],
721                image_in + offset,
722                size );
[645]723 
[652]724#if VERBOSE_EXEC
[645]725get_cycle( &date );
[656]726printf( "\n[convol] exec[%d] on core[%x,%d] loaded input file in A[%d] / cycle %d\n", 
727tid , cxy , lpid , cid , (unsigned int)date);
[645]728#endif
729
730    }
731
732    // Optionnal parallel display of the initial image stored in A[c] buffers.
[652]733    // Eah thread[cid,lid] displays (NL/nthreads) lines.
[645]734
735    if ( INITIAL_DISPLAY_ENABLE )
736    {
737        unsigned int line;
738        unsigned int offset = lines_per_thread * lid;
739
740        for ( l = 0 ; l < lines_per_thread ; l++ )
741        {
742            line = offset + l;
743
[652]744            // copy TA[cid] to TZ[cid]
[645]745            for ( p = 0 ; p < NP ; p++ )
746            {
[652]747                TZ(cid, line, p) = (unsigned char)(TA(cid, line, p) >> 8);
[645]748            }
749
[652]750            // display one line to frame buffer
751            if (fbf_write( &TZ(cid, line, 0),                     // first pixel in TZ
752                           NP,                                    // number of bytes
753                           NP*(l + (tid * lines_per_thread))))    // offset in FBF
[645]754            {
[656]755                printf("\n[convol error] in %s : thread[%d] cannot access FBF\n",
756                __FUNCTION__ , tid );
[645]757                pthread_exit( &THREAD_EXIT_FAILURE );
758            }
759        }
760
[652]761#if VERBOSE_EXEC
[645]762get_cycle( &date );
[656]763printf( "\n[convol] exec[%d] on core[%x,%d] completed initial display / cycle %d\n",
764tid , cxy , lpid , (unsigned int)date );
[645]765#endif
766
767        ////////////////////////////////
768        pthread_barrier_wait( &barrier );
769    }
770
771    ////////////////////////////////////////////////////////////
772    // parallel horizontal filter :
[652]773    // B <= convol(FH(A))
[645]774    // D <= A - FH(A)
[652]775    // Each thread computes (NL/nthreads) lines.
[645]776    // The image must be extended :
[652]777    // if (z<0)    TA(cid,l,z) == TA(cid,l,0)
778    // if (z>NP-1) TA(cid,l,z) == TA(cid,l,NP-1)
[645]779    ////////////////////////////////////////////////////////////
780
781    get_cycle( &date );
[652]782    H_BEG[cid][lid] = (unsigned int)date;
[645]783
784    // l = absolute line index / p = absolute pixel index 
785    // first & last define which lines are handled by a given thread
786
[652]787    first = tid * lines_per_thread;
[645]788    last  = first + lines_per_thread;
789
790    for (l = first; l < last; l++)
791    {
792        // src_c and src_l are the cluster index and the line index for A & D
793        int src_c = l / lines_per_cluster;
794        int src_l = l % lines_per_cluster;
795
796        // We use the specific values of the horizontal ep-filter for optimisation:
797        // sum(p) = sum(p-1) + TA[p+hrange] - TA[p-hrange-1]
798        // To minimize the number of tests, the loop on pixels is split in three domains
799
800        int sum_p = (hrange + 2) * TA(src_c, src_l, 0);
801        for (z = 1; z < hrange; z++)
802        {
803            sum_p = sum_p + TA(src_c, src_l, z);
804        }
805
806        // first domain : from 0 to hrange
807        for (p = 0; p < hrange + 1; p++)
808        {
809            // dst_c and dst_p are the cluster index and the pixel index for B
810            int dst_c = p / pixels_per_cluster;
811            int dst_p = p % pixels_per_cluster;
812            sum_p = sum_p + (int) TA(src_c, src_l, p + hrange) - (int) TA(src_c, src_l, 0);
813            TB(dst_c, dst_p, l) = sum_p / hnorm;
814            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
815        }
816        // second domain : from (hrange+1) to (NP-hrange-1)
817        for (p = hrange + 1; p < NP - hrange; p++)
818        {
819            // dst_c and dst_p are the cluster index and the pixel index for B
820            int dst_c = p / pixels_per_cluster;
821            int dst_p = p % pixels_per_cluster;
822            sum_p = sum_p + (int) TA(src_c, src_l, p + hrange) 
823                          - (int) TA(src_c, src_l, p - hrange - 1);
824            TB(dst_c, dst_p, l) = sum_p / hnorm;
825            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
826        }
827        // third domain : from (NP-hrange) to (NP-1)
828        for (p = NP - hrange; p < NP; p++)
829        {
830            // dst_c and dst_p are the cluster index and the pixel index for B
831            int dst_c = p / pixels_per_cluster;
832            int dst_p = p % pixels_per_cluster;
833            sum_p = sum_p + (int) TA(src_c, src_l, NP - 1) 
834                          - (int) TA(src_c, src_l, p - hrange - 1);
835            TB(dst_c, dst_p, l) = sum_p / hnorm;
836            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
837        }
838
839#if SUPER_VERBOSE
840get_cycle( &date );
841printf(" - line %d computed at cycle %d\n", l, (unsigned int)date );
842#endif   
843
844    }
845
846    get_cycle( &date );
[652]847    H_END[cid][lid] = (unsigned int)date;
[645]848
[652]849#if VERBOSE_EXEC
[656]850get_cycle( &date );
851printf( "\n[convol] exec[%d] on core[%x,%d] completed horizontal filter / cycle %d\n",
852tid , cxy , lpid , (unsigned int)date );
[645]853#endif
854
855    ////////////////////////////////
856    pthread_barrier_wait( &barrier );
857
858    ///////////////////////////////////////////////////////////////
859    // parallel vertical filter :
860    // C <= transpose(FV(B))
861    // Each thread computes (NP/nthreads) columns
862    // The image must be extended :
[652]863    // if (l<0)    TB(cid,p,l) == TB(cid,p,0)
864    // if (l>NL-1)   TB(cid,p,l) == TB(cid,p,NL-1)
[645]865    ///////////////////////////////////////////////////////////////
866
867    get_cycle( &date );
[652]868    V_BEG[cid][lid] = (unsigned int)date;
[645]869
870    // l = absolute line index / p = absolute pixel index
871    // first & last define which pixels are handled by a given thread
872
[652]873    first = tid * pixels_per_thread;
[645]874    last  = first + pixels_per_thread;
875
876    for (p = first; p < last; p++)
877    {
878        // src_c and src_p are the cluster index and the pixel index for B
879        int src_c = p / pixels_per_cluster;
880        int src_p = p % pixels_per_cluster;
881
882        int sum_l;
883
884        // We use the specific values of the vertical ep-filter
885        // To minimize the number of tests, the NL lines are split in three domains
886
887        // first domain : explicit computation for the first 18 values
888        for (l = 0; l < 18; l++)
889        {
890            // dst_c and dst_l are the cluster index and the line index for C
891            int dst_c = l / lines_per_cluster;
892            int dst_l = l % lines_per_cluster;
893
894            for (z = 0, sum_l = 0; z < 35; z++)
895            {
896                sum_l = sum_l + vf[z] * TB(src_c, src_p, max(l - 17 + z,0) );
897            }
898            TC(dst_c, dst_l, p) = sum_l / vnorm;
899        }
900        // second domain
901        for (l = 18; l < NL - 17; l++)
902        {
903            // dst_c and dst_l are the cluster index and the line index for C
904            int dst_c = l / lines_per_cluster;
905            int dst_l = l % lines_per_cluster;
906
907            sum_l = sum_l + TB(src_c, src_p, l + 4)
908                  + TB(src_c, src_p, l + 8)
909                  + TB(src_c, src_p, l + 11)
910                  + TB(src_c, src_p, l + 15)
911                  + TB(src_c, src_p, l + 17)
912                  - TB(src_c, src_p, l - 5)
913                  - TB(src_c, src_p, l - 9)
914                  - TB(src_c, src_p, l - 12)
915                  - TB(src_c, src_p, l - 16)
916                  - TB(src_c, src_p, l - 18);
917
918            TC(dst_c, dst_l, p) = sum_l / vnorm;
919        }
920        // third domain
921        for (l = NL - 17; l < NL; l++)
922        {
923            // dst_c and dst_l are the cluster index and the line index for C
924            int dst_c = l / lines_per_cluster;
925            int dst_l = l % lines_per_cluster;
926
927            sum_l = sum_l + TB(src_c, src_p, min(l + 4, NL - 1))
928                  + TB(src_c, src_p, min(l + 8, NL - 1))
929                  + TB(src_c, src_p, min(l + 11, NL - 1))
930                  + TB(src_c, src_p, min(l + 15, NL - 1))
931                  + TB(src_c, src_p, min(l + 17, NL - 1))
932                  - TB(src_c, src_p, l - 5)
933                  - TB(src_c, src_p, l - 9)
934                  - TB(src_c, src_p, l - 12)
935                  - TB(src_c, src_p, l - 16)
936                  - TB(src_c, src_p, l - 18);
937
938            TC(dst_c, dst_l, p) = sum_l / vnorm;
939        }
940
941#if SUPER_VERBOSE
942get_cycle( &date );
943printf(" - column %d computed at cycle %d\n", p, (unsigned int)date );
944#endif
945
946    }
947
948    get_cycle( &date );
[652]949    V_END[cid][lid] = (unsigned int)date;
[645]950
[652]951#if VERBOSE_EXEC
[656]952get_cycle( &date );
953printf( "\n[convol] exec[%d] on core[%x,%d] completed vertical filter / cycle %d\n",
954tid , cxy , lid , (unsigned int)date );
[645]955#endif
956
957    ////////////////////////////////
958    pthread_barrier_wait( &barrier );
959
960    // Optional parallel display of the final image Z <= D + C
[652]961    // Eah thread[x,y,p] displays (NL/nthreads) lines.
[645]962
963    if ( FINAL_DISPLAY_ENABLE )
964    {
965        get_cycle( &date );
[652]966        D_BEG[cid][lid] = (unsigned int)date;
[645]967
968        unsigned int line;
969        unsigned int offset = lines_per_thread * lid;
970
971        for ( l = 0 ; l < lines_per_thread ; l++ )
972        {
973            line = offset + l;
974
975            for ( p = 0 ; p < NP ; p++ )
976            {
[652]977                TZ(cid, line, p) = 
978                   (unsigned char)( (TD(cid, line, p) + 
979                                     TC(cid, line, p) ) >> 8 );
[645]980            }
981
[652]982            if (fbf_write( &TZ(cid, line, 0),                   // first pixel in TZ
983                           NP,                                  // number of bytes
984                           NP*(l + (tid * lines_per_thread))))  // offset in FBF
[645]985            {
[652]986                printf("\n[convol error] thread[%d] cannot access FBF\n", tid );
[645]987                pthread_exit( &THREAD_EXIT_FAILURE );
988            }
989        }
990
991        get_cycle( &date );
[652]992        D_END[cid][lid] = (unsigned int)date;
[645]993
[652]994#if VERBOSE_EXEC
[656]995get_cycle( &date );
996printf( "\n[convol] exec[%d] on core[%x,%d] completed final display / cycle %d\n",
997tid , cxy , lid , (unsigned int)date );
[645]998#endif
[652]999
[645]1000    }
1001
[656]1002    // Each thread[cid,0] releases the 5 local buffers
1003    if( lid == 0 )
[645]1004    {
[656]1005        free( A[cid] );
1006        free( B[cid] );
1007        free( C[cid] );
1008        free( D[cid] );
1009        free( Z[cid] );
1010    }
1011
1012    // thread termination depends on the placement policy
1013    if( PARALLEL_PLACEMENT )   
1014    {
1015        // <exec> threads are runing in detached mode, and
1016        // each thread must signal completion by calling barrier
1017        // passed in arguments before exit
1018
1019        pthread_barrier_wait( args->barrier );
1020
[645]1021        pthread_exit( &THREAD_EXIT_SUCCESS );
1022    }
[656]1023    else
1024    {
1025        // <exec> threads are running in attached mode
1026        // all threads (but the one executing main) exit
1027        if ( tid != tid_main ) pthread_exit( &THREAD_EXIT_SUCCESS );
1028    }
[645]1029
[656]1030    return NULL;
1031
[645]1032} // end execute()
1033
1034
1035
[652]1036//////////////////////////
1037void instrument( FILE * f,
1038                 char * filename )
[645]1039{
[652]1040    unsigned int nclusters = x_size * y_size;
[645]1041
[652]1042    unsigned int cc, pp;
[645]1043
[652]1044    unsigned int min_start = 0xFFFFFFFF;
1045    unsigned int max_start = 0;
[645]1046
[652]1047    unsigned int min_h_beg = 0xFFFFFFFF;
1048    unsigned int max_h_beg = 0;
[645]1049
[652]1050    unsigned int min_h_end = 0xFFFFFFFF;
1051    unsigned int max_h_end = 0;
[645]1052
[652]1053    unsigned int min_v_beg = 0xFFFFFFFF;
1054    unsigned int max_v_beg = 0;
[645]1055
[652]1056    unsigned int min_v_end = 0xFFFFFFFF;
1057    unsigned int max_v_end = 0;
[645]1058
[652]1059    unsigned int min_d_beg = 0xFFFFFFFF;
1060    unsigned int max_d_beg = 0;
[645]1061
[652]1062    unsigned int min_d_end = 0xFFFFFFFF;
1063    unsigned int max_d_end = 0;
1064
1065    for (cc = 0; cc < nclusters; cc++)
1066    {
1067        for (pp = 0; pp < ncores; pp++ )
[645]1068        {
[652]1069            if (START[cc][pp] < min_start) min_start = START[cc][pp];
1070            if (START[cc][pp] > max_start) max_start = START[cc][pp];
[645]1071
[652]1072            if (H_BEG[cc][pp] < min_h_beg) min_h_beg = H_BEG[cc][pp];
1073            if (H_BEG[cc][pp] > max_h_beg) max_h_beg = H_BEG[cc][pp];
[645]1074
[652]1075            if (H_END[cc][pp] < min_h_end) min_h_end = H_END[cc][pp];
1076            if (H_END[cc][pp] > max_h_end) max_h_end = H_END[cc][pp];
[645]1077
[652]1078            if (V_BEG[cc][pp] < min_v_beg) min_v_beg = V_BEG[cc][pp];
1079            if (V_BEG[cc][pp] > max_v_beg) max_v_beg = V_BEG[cc][pp];
[645]1080
[652]1081            if (V_END[cc][pp] < min_v_end) min_v_end = V_END[cc][pp];
1082            if (V_END[cc][pp] > max_v_end) max_v_end = V_END[cc][pp];
[645]1083
[652]1084            if (D_BEG[cc][pp] < min_d_beg) min_d_beg = D_BEG[cc][pp];
1085            if (D_BEG[cc][pp] > max_d_beg) max_d_beg = D_BEG[cc][pp];
[645]1086
[652]1087            if (D_END[cc][pp] < min_d_end) min_d_end = D_END[cc][pp];
1088            if (D_END[cc][pp] > max_d_end) max_d_end = D_END[cc][pp];
[645]1089        }
[652]1090    }
[645]1091
[652]1092    // display on terminal
1093    printf( "\n ------ %s ------\n" , filename );
[645]1094
[652]1095    printf(" - START : min = %d / max = %d / med = %d / delta = %d\n",
1096           min_start, max_start, (min_start+max_start)/2, max_start-min_start);
[645]1097
[652]1098    printf(" - H_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1099           min_h_beg, max_h_beg, (min_h_beg+max_h_beg)/2, max_h_beg-min_h_beg);
[645]1100
[652]1101    printf(" - H_END : min = %d / max = %d / med = %d / delta = %d\n",
1102           min_h_end, max_h_end, (min_h_end+max_h_end)/2, max_h_end-min_h_end);
[645]1103
[652]1104    printf(" - V_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1105           min_v_beg, max_v_beg, (min_v_beg+max_v_beg)/2, max_v_beg-min_v_beg);
[645]1106
[652]1107    printf(" - V_END : min = %d / max = %d / med = %d / delta = %d\n",
1108           min_v_end, max_v_end, (min_v_end+max_v_end)/2, max_v_end-min_v_end);
[645]1109
[652]1110    printf(" - D_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1111           min_d_beg, max_d_beg, (min_d_beg+max_d_beg)/2, max_d_beg-min_d_beg);
[645]1112
[652]1113    printf(" - D_END : min = %d / max = %d / med = %d / delta = %d\n",
1114           min_d_end, max_d_end, (min_d_end+max_d_end)/2, max_d_end-min_d_end);
[645]1115
[656]1116    printf( "\n General Scenario   (Kcycles)\n" );
[652]1117    printf( " - LOAD IMAGE        = %d\n", (min_h_beg - min_start)/1000 );
1118    printf( " - H_FILTER          = %d\n", (max_h_end - min_h_beg)/1000 );
1119    printf( " - BARRIER HORI/VERT = %d\n", (min_v_beg - max_h_end)/1000 );
1120    printf( " - V_FILTER          = %d\n", (max_v_end - min_v_beg)/1000 );
1121    printf( " - BARRIER VERT/DISP = %d\n", (min_d_beg - max_v_end)/1000 );
1122    printf( " - DISPLAY           = %d\n", (max_d_end - min_d_beg)/1000 );
[656]1123    printf( " \nSEQUENCIAL = %d / PARALLEL = %d\n",
1124            SEQUENCIAL_TIME/1000, PARALLEL_TIME/1000 );
[645]1125
[652]1126    // save on disk
1127    fprintf( f ,  "\n ------ %s ------\n" , filename );
1128
1129    fprintf( f , " - START : min = %d / max = %d / med = %d / delta = %d\n",
1130           min_start, max_start, (min_start+max_start)/2, max_start-min_start);
1131
1132    fprintf( f , " - H_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1133           min_h_beg, max_h_beg, (min_h_beg+max_h_beg)/2, max_h_beg-min_h_beg);
1134
1135    fprintf( f , " - H_END : min = %d / max = %d / med = %d / delta = %d\n",
1136           min_h_end, max_h_end, (min_h_end+max_h_end)/2, max_h_end-min_h_end);
1137
1138    fprintf( f , " - V_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1139           min_v_beg, max_v_beg, (min_v_beg+max_v_beg)/2, max_v_beg-min_v_beg);
1140
1141    fprintf( f , " - V_END : min = %d / max = %d / med = %d / delta = %d\n",
1142           min_v_end, max_v_end, (min_v_end+max_v_end)/2, max_v_end-min_v_end);
1143
1144    fprintf( f , " - D_BEG : min = %d / max = %d / med = %d / delta = %d\n",
1145           min_d_beg, max_d_beg, (min_d_beg+max_d_beg)/2, max_d_beg-min_d_beg);
1146
1147    fprintf( f , " - D_END : min = %d / max = %d / med = %d / delta = %d\n",
1148           min_d_end, max_d_end, (min_d_end+max_d_end)/2, max_d_end-min_d_end);
1149
1150    fprintf( f ,  "\n General Scenario (Kcycles)\n" );
1151    fprintf( f ,  " - LOAD IMAGE        = %d\n", (min_h_beg - min_start)/1000 );
1152    fprintf( f ,  " - H_FILTER          = %d\n", (max_h_end - min_h_beg)/1000 );
1153    fprintf( f ,  " - BARRIER HORI/VERT = %d\n", (min_v_beg - max_h_end)/1000 );
1154    fprintf( f ,  " - V_FILTER          = %d\n", (max_v_end - min_v_beg)/1000 );
1155    fprintf( f ,  " - BARRIER VERT/DISP = %d\n", (min_d_beg - max_v_end)/1000 );
1156    fprintf( f ,  " - DISPLAY           = %d\n", (max_d_end - min_d_beg)/1000 );
[656]1157    fprintf( f ,  " \nSEQUENCIAL = %d / PARALLEL = %d\n",
1158    SEQUENCIAL_TIME/1000, PARALLEL_TIME/1000 );
[652]1159
[645]1160} // end instrument()
1161
1162
1163
1164
1165
1166// Local Variables:
1167// tab-width: 3
1168// c-basic-offset: 3
1169// c-file-offsets:((innamespace . 0)(inline-open . 0))
1170// indent-tabs-mode: nil
1171// End:
1172
1173// vim: filetype=cpp:expandtab:shiftwidth=3:tabstop=3:softtabstop=3
1174
1175
Note: See TracBrowser for help on using the repository browser.