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

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

Introduce the three placement modes in "transpose", "convol', "fft" applications.

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