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

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

Fix several bugs in the FATFS and in the VFS,
related to the creation of big files requiring
more than 4 Kbytes (one cluster) on device.

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