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

Last change on this file since 645 was 645, checked in by alain, 3 years ago

Introducing application "convol".

File size: 31.0 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-processors, multi-clusters architecture, with one thread
8// per processor, 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 [201]*[35] pixels, but it can be factored in two
17// independant line and column convolution products.
18// The five buffers containing the image are distributed in clusters.
19//
20// The (1024 * 1024) pixels image is read from a file (2 bytes per pixel).
21//
22// - number of clusters containing processors must be power of 2 no larger than 256.
23// - number of processors per cluster must be power of 2 no larger than 8.
24///////////////////////////////////////////////////////////////////////////////////////
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <pthread.h>
31#include <almosmkh.h>
32#include <hal_macros.h>
33
34#define IMAGE_IN_PATH              "misc/philips_1024.raw"
35
36#define USE_SQT_BARRIER            1
37#define VERBOSE                    1
38#define SUPER_VERBOSE              0
39
40#define USE_DQT_BARRIER            1
41
42#define X_MAX                      16
43#define Y_MAX                      16
44#define PROCS_MAX                  4
45#define CLUSTERS_MAX               (X_MAX * Y_MAX)
46#define THREADS_MAX                (X_MAX * Y_MAX * PROCS_MAX]
47
48#define INITIAL_DISPLAY_ENABLE     1
49#define FINAL_DISPLAY_ENABLE       1
50
51#define PIXEL_SIZE                 2       // input image has 2 bytes per pixel
52#define FBF_TYPE                   420     // output image has 1 byte per pixel
53
54#define NL                         1024
55#define NP                         1024
56#define NB_PIXELS                  (NP * NL)
57#define FRAME_SIZE                 (NB_PIXELS * PIXEL_SIZE)
58
59
60#define TA(c,l,p)  (A[c][((NP) * (l)) + (p)])
61#define TB(c,p,l)  (B[c][((NL) * (p)) + (l)])
62#define TC(c,l,p)  (C[c][((NP) * (l)) + (p)])
63#define TD(c,l,p)  (D[c][((NP) * (l)) + (p)])
64#define TZ(c,l,p)  (Z[c][((NP) * (l)) + (p)])
65
66#define max(x,y) ((x) > (y) ? (x) : (y))
67#define min(x,y) ((x) < (y) ? (x) : (y))
68
69//////////////////////////////////////////////////////////
70//   global variables stored in seg_data in cluster[0,0]
71//////////////////////////////////////////////////////////
72
73// Instrumentation counters (cluster_id, lpid]
74unsigned int START[CLUSTERS_MAX][PROCS_MAX];
75unsigned int H_BEG[CLUSTERS_MAX][PROCS_MAX];
76unsigned int H_END[CLUSTERS_MAX][PROCS_MAX];
77unsigned int V_BEG[CLUSTERS_MAX][PROCS_MAX];
78unsigned int V_END[CLUSTERS_MAX][PROCS_MAX];
79unsigned int D_BEG[CLUSTERS_MAX][PROCS_MAX];
80unsigned int D_END[CLUSTERS_MAX][PROCS_MAX];
81
82// file pointers on input image
83FILE * f_image_in;
84FILE * f_instrum;
85
86// return values at thread exit
87unsigned int THREAD_EXIT_SUCCESS = 0;
88unsigned int THREAD_EXIT_FAILURE = 1;
89
90// synchronization barrier
91pthread_barrier_t     barrier;
92
93// coordinates of core executing the main thread
94unsigned int cxy_main;
95unsigned int lid_main;
96
97// arrays of pointers on distributed buffers in all clusters
98unsigned short * GA[CLUSTERS_MAX];
99int *            GB[CLUSTERS_MAX];
100int *            GC[CLUSTERS_MAX];
101int *            GD[CLUSTERS_MAX];
102unsigned char *  GZ[CLUSTERS_MAX];
103
104// trdid[] array for execution threads
105// 1D array if no explicit threads placement / 2D array if explicit placement
106pthread_t        trdid[CLUSTERS_MAX][PROCS_MAX];
107//pthread_t        trdid[THREADS_MAX];
108
109// attr[] array for execution threads
110// unused if no explicit threads placement
111pthread_attr_t   attr[CLUSTERS_MAX][PROCS_MAX]; 
112
113/////////////////////////////////////////////////////////////////////////////////////
114//           functions declaration
115/////////////////////////////////////////////////////////////////////////////////////
116
117void execute( void );
118
119void instrument( unsigned int nclusters,
120                 unsigned int ncores );
121
122/////////////////
123void main( void )
124{
125    unsigned int x_size;                 // number of clusters in a row
126    unsigned int y_size;                 // number of clusters in a column
127    unsigned int ncores;                 // number of processors per cluster
128
129    unsigned long long  date;
130
131    char         name[64];               // instrumentation file name
132    char         path[128];              // instrumentation path name
133
134    int          error;
135
136    // get platform parameters
137    if ( get_config( &x_size , &y_size , &ncores ) )
138    {
139        printf("\n[convol error] cannot get hardware configuration\n");
140        exit( 0 );
141    }
142
143    // get core executing this main thread
144    // and register these coordinates in global variables
145    get_core_id( &cxy_main , &lid_main );
146   
147    // check ncores
148    if( (ncores != 1) && (ncores != 2) && (ncores != 4) )
149    {
150        printf("\n[convol error] number of cores per cluster must be 1/2/4\n");
151        exit( 0 );
152    }
153
154    // check x_size
155    if( (x_size != 1) && (x_size != 2) && (x_size != 4) && (x_size != 8) && (x_size != 16) )
156    {
157        printf("\n[convol error] x_size must be 1/2/4/8/16\n");
158        exit( 0 );
159    }
160
161    // check y_size
162    if( (y_size != 1) && (y_size != 2) && (y_size != 4) && (y_size != 8) && (y_size != 16) )
163    {
164        printf("\n[convol error] y_size must be 1/2/4/8/16\n");
165        exit( 0 );
166    }
167
168    // compute nthreads and nclusters
169    unsigned int nthreads  = x_size * y_size * ncores;
170    unsigned int nclusters = x_size * y_size;
171
172    get_cycle( &date );
173    printf("\n[convol] starts on core[%x,%d] / %d thread(s) / cycle %d\n",
174    cxy_main, lid_main, nthreads, (unsigned int)date );
175
176    // build instrumentation file name
177    if( USE_DQT_BARRIER )
178    snprintf( name , 64 , "p_convol_dqt_%d_%d", x_size * y_size , ncores );
179    else
180    snprintf( name , 64 , "p_convol_smp_%d_%d", x_size * y_size , ncores );
181
182    // build pathname
183    snprintf( path , 128 , "/home/%s", name );
184
185    // open instrumentation file
186    f_instrum = fopen( path , NULL );
187    if ( f_instrum == NULL ) 
188    { 
189        printf("\n[convol error] cannot open instrumentation file <%s>\n", path );
190        exit( 0 );
191    }
192
193#if DEBUG_MAIN
194get_cycle( &date );
195printf("\n[convol] main on core[%x,%d] open file <%s> at cycle %d\n",
196cxy_main, lid_main, path, (unsigned int)date );
197#endif
198
199    // open input file
200    f_image_in = fopen( IMAGE_IN_PATH , NULL );
201    if ( f_image_in == NULL ) 
202    { 
203        printf("\n[convol error] cannot open input file <%s>\n", IMAGE_IN_PATH );
204        exit( 0 );
205    }
206
207#if DEBUG_MAIN
208get_cycle( &date );
209printf("\n[convol] main on core[%x,%d] open file <%s> at cycle %d\n",
210cxy_main, lid_main, path, (unsigned int)date );
211#endif
212   
213    // get FBF config
214    unsigned int  fbf_width;
215    unsigned int  fbf_height;
216    unsigned int  fbf_type;
217    fbf_get_config( &fbf_width , &fbf_height , &fbf_type );
218
219    // check FBF size
220    if ( (fbf_width != NP) || (fbf_height != NL) )
221    {
222        printf("\n[convol error] bad FBF size\n");
223        exit( 0 );
224    }
225
226    // check FBF subsampling
227    if ( fbf_type != FBF_TYPE )
228    {
229        printf("\n[convol error] bad FBF subsampling\n");
230        exit( 0 );
231    }
232
233    // initialise barrier
234    if( USE_DQT_BARRIER )
235    {
236        pthread_barrierattr_t attr;
237        attr.x_size   = x_size;
238        attr.y_size   = y_size;
239        attr.nthreads = ncores;
240        error = pthread_barrier_init( &barrier, &attr , nthreads );
241    }
242    else
243    {
244        error = pthread_barrier_init( &barrier, NULL , nthreads );
245    }
246
247    if( error )
248    {
249        printf("\n[convol error] cannot initialize barrier\n");
250        exit( 0 );
251    }
252
253    get_cycle( &date );
254    printf("\n[convol] main on core[%x,%d] completes initialisation at cycle %d\n" 
255           "- CLUSTERS     = %d\n"
256           "- PROCS        = %d\n" 
257           "- THREADS      = %d\n",
258           cxy_main, lid_main, (unsigned int)date, nclusters, ncores, nthreads );
259
260    // launch exec threads with explicit placement
261    unsigned int x;
262    unsigned int y;
263    unsigned int l;
264    unsigned int cxy;
265 
266    for( x = 0 ; x < x_size ; x++ )
267    {
268        for( y = 0 ; y < y_size ; y++ )
269        {
270           cxy = HAL_CXY_FROM_XY(x,y);
271           for( l = 0 ; l < ncores ; l++ )
272           {
273               // no other thread on the core running the main
274               if( (cxy != cxy_main) || (l != lid_main) )
275               {
276                   // define thread attributes
277                   attr[cxy][l].attributes = PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
278                   attr[cxy][l].cxy        = cxy;
279                   attr[cxy][l].lid        = l;
280 
281                   // create thread on core[x,y,l]
282                   if (pthread_create( &trdid[cxy][l],
283                                       &attr[cxy][l],   
284                                       &execute,
285                                       NULL ) )     // execute has no argument
286                   {
287                       printf("\n[convol error] created thread %x on core[%x][%d]\n",
288                       trdid[cxy][l] , cxy , l );
289                       exit( 0 );
290                   }
291                }
292            }
293        }
294    }   
295
296/*
297    // launch other threads without explicit placement
298    for ( n = 1 ; n < nthreads ; n++ )
299    {
300        if ( giet_pthread_create( &trdid[n],
301                                  NULL,                  // no attribute
302                                  &execute,
303                                  NULL ) )               // no argument
304        {
305            printf("\n[convol error] creating thread %x\n", trdid[n] );
306            exit( 0 );
307        }
308    }
309*/
310
311    // the main thread run itself the execute() function
312    execute();
313
314    // wait other threads completions if explicit threads placement
315    for( x = 0 ; x < x_size ; x++ )
316    {
317        for( y = 0 ; y < y_size ; y++ )
318        {
319            unsigned int cxy = HAL_CXY_FROM_XY(x,y);
320            for( l = 0 ; l < ncores ; l++ )
321            {
322                // no other thread on the core running the main
323                if( (cxy != cxy_main) || (l != lid_main) )
324                {
325                    unsigned int * exit_status;
326
327                    // wait thread running on core[x,y,l]
328                    if (pthread_join( trdid[cxy][l] , (void*)(&exit_status) ) )
329                    {
330                        printf("\n[convol error] main cannot join thread[%x,%d]\n", cxy, l );
331                        exit( 0 );
332                    }
333
334                    // check exit_status
335                    if( *exit_status != 0 )
336                    {
337                        printf("\n[convol error] thread[%x,%d]return failure\n", cxy, l );
338                        exit( 0 );
339                    }
340                }
341            }
342        }
343    }
344/*   
345    // wait other threads completion when no explicit threads placement
346    for ( n = 1 ; n < nthreads ; n++ )
347    {
348        if ( pthread_join( trdid[n], NULL ) )
349        {
350            printf("\n[convol error] joining thread %x\n", trdid[n] );
351            exit( 0 );
352        }
353    }
354*/
355    // call the instrument() function
356    instrument( nclusters , ncores );
357
358    exit( 0 );
359   
360} // end main()
361
362
363
364//////////////
365void execute()
366{
367    unsigned long long date;
368
369    // Each thread[x,y,p] initialises the convolution kernel parameters in local stack.
370    // The values defined in the next 12 lines are Philips proprietary information.
371
372    int   vnorm  = 115;
373    int   vf[35] = { 1, 1, 2, 2, 2,
374                     2, 3, 3, 3, 4,
375                     4, 4, 4, 5, 5,
376                     5, 5, 5, 5, 5,
377                     5, 5, 4, 4, 4,
378                     4, 3, 3, 3, 2,
379                     2, 2, 2, 1, 1 };
380
381    unsigned int hrange = 100;
382    unsigned int hnorm  = 201;
383
384    // get plat-form config
385    unsigned int x_size;            // number of clusters in a row
386    unsigned int y_size;            // number of clusters in a column
387    unsigned int ncores;            // number of processors per cluster
388    get_config( &x_size , &y_size , &ncores );
389
390    // get cluster indentifier and core local index
391    unsigned int cxy; 
392    unsigned int lid; 
393    get_core_id( &cxy , &lid );
394    unsigned int x = HAL_X_FROM_CXY( cxy );
395    unsigned int y = HAL_Y_FROM_CXY( cxy );
396
397    // indexes for loops
398    unsigned int c;                 // cluster index
399    unsigned int l;                 // line index
400    unsigned int p;                 // pixel index
401    unsigned int z;                 // vertical filter index
402
403    unsigned int nclusters  = x_size * y_size;              // number of clusters
404    unsigned int cluster_id = (x * y_size) + y;             // continuous cluster index
405    unsigned int thread_id  = (cluster_id * ncores) + lid;  // continuous thread index
406    unsigned int nthreads   = nclusters * ncores;           // number of threads
407    unsigned int frame_size = FRAME_SIZE;                   // total size (bytes)
408    unsigned int lines_per_thread   = NL / nthreads;        // lines per thread
409    unsigned int lines_per_cluster  = NL / nclusters;       // lines per cluster
410    unsigned int pixels_per_thread  = NP / nthreads;        // columns per thread
411    unsigned int pixels_per_cluster = NP / nclusters;       // columns per cluster
412
413    unsigned int first, last;
414
415    get_cycle( &date );
416    START[cluster_id][lid] = (unsigned int)date;
417
418    // Each thread[cxy][0] allocate the global buffers in cluster cxy
419    if ( lid == 0 )
420    {
421
422#if VERBOSE
423printf( "\n[convol] thread[%x,%d] enters malloc at cycle %d\n", 
424cxy , lid , (unsigned int)date );
425#endif
426
427        GA[cluster_id] = remote_malloc( (FRAME_SIZE/nclusters)   , cxy );
428        GB[cluster_id] = remote_malloc( (FRAME_SIZE/nclusters)*2 , cxy );
429        GC[cluster_id] = remote_malloc( (FRAME_SIZE/nclusters)*2 , cxy );
430        GD[cluster_id] = remote_malloc( (FRAME_SIZE/nclusters)*2 , cxy );
431        GZ[cluster_id] = remote_malloc( (FRAME_SIZE/nclusters)/2 , cxy );
432       
433#if VERBOSE
434printf( "\n[convol]  Shared Buffer Virtual Addresses in cluster %x\n"
435        "### GA = %x\n"
436        "### GB = %x\n"               
437        "### GC = %x\n"               
438        "### GD = %x\n"               
439        "### GZ = %x\n",
440        cxy,
441        GA[cluster_id],
442        GB[cluster_id],
443        GC[cluster_id],
444        GD[cluster_id],
445        GZ[cluster_id] );
446#endif
447   
448    }
449
450    ////////////////////////////////
451    pthread_barrier_wait( &barrier );
452
453    // Each thread[cxy,p] initialise in its private stack a copy of the
454    // arrays of pointers on the shared, distributed buffers.
455    unsigned short * A[CLUSTERS_MAX];
456    int            * B[CLUSTERS_MAX];
457    int            * C[CLUSTERS_MAX];
458    int            * D[CLUSTERS_MAX];
459    unsigned char  * Z[CLUSTERS_MAX];
460
461    for( c = 0 ; c < nclusters ; c++ )
462    {
463        A[c] = GA[c];
464        B[c] = GB[c];
465        C[c] = GC[c];
466        D[c] = GD[c];
467        Z[c] = GZ[c];
468    }
469
470    // Each thread[x,y,0] access the file containing the input image, to load
471    // the local A[c] buffer (frame_size / nclusters loaded in each cluster).
472    // Other threads are waiting on the barrier.
473    if ( lid==0 )
474    {
475        unsigned int offset = (frame_size/nclusters)*cluster_id;
476        unsigned int size   = frame_size/nclusters;
477
478        // seek the pointer in file
479        if ( fseek( f_image_in,
480                    offset,
481                    SEEK_SET ) )
482        {
483            printf("\n[convol error] in %s : thread[%x,%d] cannot seek input file\n",
484            __FUNCTION__ , cxy , lid );
485            pthread_exit( &THREAD_EXIT_FAILURE );
486        } 
487
488        if ( fread( A[cluster_id],
489                    1, 
490                    size,
491                    f_image_in ) != size )
492        {
493            printf("\n[convol error] in %s : thread[%x,%d] cannot read input file\n",
494            __FUNCTION__ , cxy , lid );
495            pthread_exit( &THREAD_EXIT_FAILURE );
496        }
497 
498#if VERBOSE
499get_cycle( &date );
500printf( "\n[convol] thread[%x,%d] load input file at cycle %d\n", 
501cxy , lid , (unsigned int)date );
502#endif
503
504    }
505
506    // Optionnal parallel display of the initial image stored in A[c] buffers.
507    // Eah thread[x,y,p] displays (NL/nthreads) lines. (one byte per pixel).
508
509    if ( INITIAL_DISPLAY_ENABLE )
510    {
511        unsigned int line;
512        unsigned int offset = lines_per_thread * lid;
513
514        for ( l = 0 ; l < lines_per_thread ; l++ )
515        {
516            line = offset + l;
517
518            for ( p = 0 ; p < NP ; p++ )
519            {
520                TZ(cluster_id, line, p) = (unsigned char)(TA(cluster_id, line, p) >> 8);
521            }
522
523            if (fbf_write( &TZ(cluster_id, line, 0),                  // first pixel in TZ
524                           NP,                                        // number of bytes
525                           NP*(l + (thread_id * lines_per_thread))))  // offset in FBF
526            {
527                printf("\n[convol error] in %s : thread[%x,%d] cannot access FBF\n",
528                __FUNCTION__ , cxy , lid );
529                pthread_exit( &THREAD_EXIT_FAILURE );
530            }
531        }
532
533#if VERBOSE
534get_cycle( &date );
535printf( "\n[convol] thread[%x,%d] completes initial display at cycle %d\n",
536cxy , lid , (unsigned int)date );
537#endif
538
539        ////////////////////////////////
540        pthread_barrier_wait( &barrier );
541    }
542
543    ////////////////////////////////////////////////////////////
544    // parallel horizontal filter :
545    // B <= transpose(FH(A))
546    // D <= A - FH(A)
547    // Each thread computes (NL/nthreads) lines
548    // The image must be extended :
549    // if (z<0)    TA(cluster_id,l,z) == TA(cluster_id,l,0)
550    // if (z>NP-1) TA(cluster_id,l,z) == TA(cluster_id,l,NP-1)
551    ////////////////////////////////////////////////////////////
552
553    get_cycle( &date );
554    H_BEG[cluster_id][lid] = (unsigned int)date;
555
556#if VERBOSE
557printf( "\n[convol] thread[%x,%d] starts horizontal filter at cycle %d\n",
558cxy , lid , (unsigned int)date );
559#else
560if ( (cxy == cxy_main) && (lid == lid_main) ) 
561printf( "\n[convol] thread[%x,%d] starts horizontal filter at cycle %d\n",
562cxy , lid , (unsigned int)date );
563#endif
564
565    // l = absolute line index / p = absolute pixel index 
566    // first & last define which lines are handled by a given thread
567
568    first = thread_id * lines_per_thread;
569    last  = first + lines_per_thread;
570
571    for (l = first; l < last; l++)
572    {
573        // src_c and src_l are the cluster index and the line index for A & D
574        int src_c = l / lines_per_cluster;
575        int src_l = l % lines_per_cluster;
576
577        // We use the specific values of the horizontal ep-filter for optimisation:
578        // sum(p) = sum(p-1) + TA[p+hrange] - TA[p-hrange-1]
579        // To minimize the number of tests, the loop on pixels is split in three domains
580
581        int sum_p = (hrange + 2) * TA(src_c, src_l, 0);
582        for (z = 1; z < hrange; z++)
583        {
584            sum_p = sum_p + TA(src_c, src_l, z);
585        }
586
587        // first domain : from 0 to hrange
588        for (p = 0; p < hrange + 1; p++)
589        {
590            // dst_c and dst_p are the cluster index and the pixel index for B
591            int dst_c = p / pixels_per_cluster;
592            int dst_p = p % pixels_per_cluster;
593            sum_p = sum_p + (int) TA(src_c, src_l, p + hrange) - (int) TA(src_c, src_l, 0);
594            TB(dst_c, dst_p, l) = sum_p / hnorm;
595            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
596        }
597        // second domain : from (hrange+1) to (NP-hrange-1)
598        for (p = hrange + 1; p < NP - hrange; p++)
599        {
600            // dst_c and dst_p are the cluster index and the pixel index for B
601            int dst_c = p / pixels_per_cluster;
602            int dst_p = p % pixels_per_cluster;
603            sum_p = sum_p + (int) TA(src_c, src_l, p + hrange) 
604                          - (int) TA(src_c, src_l, p - hrange - 1);
605            TB(dst_c, dst_p, l) = sum_p / hnorm;
606            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
607        }
608        // third domain : from (NP-hrange) to (NP-1)
609        for (p = NP - hrange; p < NP; p++)
610        {
611            // dst_c and dst_p are the cluster index and the pixel index for B
612            int dst_c = p / pixels_per_cluster;
613            int dst_p = p % pixels_per_cluster;
614            sum_p = sum_p + (int) TA(src_c, src_l, NP - 1) 
615                          - (int) TA(src_c, src_l, p - hrange - 1);
616            TB(dst_c, dst_p, l) = sum_p / hnorm;
617            TD(src_c, src_l, p) = (int) TA(src_c, src_l, p) - sum_p / hnorm;
618        }
619
620#if SUPER_VERBOSE
621get_cycle( &date );
622printf(" - line %d computed at cycle %d\n", l, (unsigned int)date );
623#endif   
624
625    }
626
627    get_cycle( &date );
628    H_END[cluster_id][lid] = (unsigned int)date;
629
630#if VERBOSE
631printf( "\n[convol] thread[%x,%d] completes horizontal filter at cycle %d\n",
632cxy , lid, (unsigned int)date );
633#else
634if ( (cxy == cxy_main) && (lid == lid_main) ) 
635printf( "\n[convol] thread[%x,%d] completes horizontal filter at cycle %d\n",
636cxy , lid, (unsigned int)date );
637#endif
638
639    ////////////////////////////////
640    pthread_barrier_wait( &barrier );
641
642    ///////////////////////////////////////////////////////////////
643    // parallel vertical filter :
644    // C <= transpose(FV(B))
645    // Each thread computes (NP/nthreads) columns
646    // The image must be extended :
647    // if (l<0)    TB(cluster_id,p,l) == TB(cluster_id,p,0)
648    // if (l>NL-1)   TB(cluster_id,p,l) == TB(cluster_id,p,NL-1)
649    ///////////////////////////////////////////////////////////////
650
651    get_cycle( &date );
652    V_BEG[cluster_id][lid] = (unsigned int)date;
653
654#if VERBOSE
655printf( "\n[convol] thread[%x,%d] starts vertical filter at cycle %d\n",
656cxy , lid , (unsigned int)date );
657#else
658if ( (cxy == cxy_main) && (lid == lid_main) ) 
659printf( "\n[convol] thread[%x,%d] starts vertical filter at cycle %d\n",
660cxy , lid, (unsigned int)date );
661#endif
662
663    // l = absolute line index / p = absolute pixel index
664    // first & last define which pixels are handled by a given thread
665
666    first = thread_id * pixels_per_thread;
667    last  = first + pixels_per_thread;
668
669    for (p = first; p < last; p++)
670    {
671        // src_c and src_p are the cluster index and the pixel index for B
672        int src_c = p / pixels_per_cluster;
673        int src_p = p % pixels_per_cluster;
674
675        int sum_l;
676
677        // We use the specific values of the vertical ep-filter
678        // To minimize the number of tests, the NL lines are split in three domains
679
680        // first domain : explicit computation for the first 18 values
681        for (l = 0; l < 18; l++)
682        {
683            // dst_c and dst_l are the cluster index and the line index for C
684            int dst_c = l / lines_per_cluster;
685            int dst_l = l % lines_per_cluster;
686
687            for (z = 0, sum_l = 0; z < 35; z++)
688            {
689                sum_l = sum_l + vf[z] * TB(src_c, src_p, max(l - 17 + z,0) );
690            }
691            TC(dst_c, dst_l, p) = sum_l / vnorm;
692        }
693        // second domain
694        for (l = 18; l < NL - 17; l++)
695        {
696            // dst_c and dst_l are the cluster index and the line index for C
697            int dst_c = l / lines_per_cluster;
698            int dst_l = l % lines_per_cluster;
699
700            sum_l = sum_l + TB(src_c, src_p, l + 4)
701                  + TB(src_c, src_p, l + 8)
702                  + TB(src_c, src_p, l + 11)
703                  + TB(src_c, src_p, l + 15)
704                  + TB(src_c, src_p, l + 17)
705                  - TB(src_c, src_p, l - 5)
706                  - TB(src_c, src_p, l - 9)
707                  - TB(src_c, src_p, l - 12)
708                  - TB(src_c, src_p, l - 16)
709                  - TB(src_c, src_p, l - 18);
710
711            TC(dst_c, dst_l, p) = sum_l / vnorm;
712        }
713        // third domain
714        for (l = NL - 17; l < NL; l++)
715        {
716            // dst_c and dst_l are the cluster index and the line index for C
717            int dst_c = l / lines_per_cluster;
718            int dst_l = l % lines_per_cluster;
719
720            sum_l = sum_l + TB(src_c, src_p, min(l + 4, NL - 1))
721                  + TB(src_c, src_p, min(l + 8, NL - 1))
722                  + TB(src_c, src_p, min(l + 11, NL - 1))
723                  + TB(src_c, src_p, min(l + 15, NL - 1))
724                  + TB(src_c, src_p, min(l + 17, NL - 1))
725                  - TB(src_c, src_p, l - 5)
726                  - TB(src_c, src_p, l - 9)
727                  - TB(src_c, src_p, l - 12)
728                  - TB(src_c, src_p, l - 16)
729                  - TB(src_c, src_p, l - 18);
730
731            TC(dst_c, dst_l, p) = sum_l / vnorm;
732        }
733
734#if SUPER_VERBOSE
735get_cycle( &date );
736printf(" - column %d computed at cycle %d\n", p, (unsigned int)date );
737#endif
738
739    }
740
741    get_cycle( &date );
742    V_END[cluster_id][lid] = (unsigned int)date;
743
744#if VERBOSE
745printf( "\n[convol] thread[%x,%d] completes vertical filter at cycle %d\n",
746cxy , lid , (unsigned int)date );
747#else
748if ( (cxy == cxy_main) && (lid == lid_main) ) 
749printf( "\n[convol] thread[%x,%d] completes vertical filter at cycle %d\n",
750cxy , lid, (unsigned int)date );
751#endif
752
753    ////////////////////////////////
754    pthread_barrier_wait( &barrier );
755
756    // Optional parallel display of the final image Z <= D + C
757    // Eah thread[x,y,p] displays (NL/nthreads) lines. (one byte per pixel).
758
759    if ( FINAL_DISPLAY_ENABLE )
760    {
761        get_cycle( &date );
762        D_BEG[cluster_id][lid] = (unsigned int)date;
763
764#if VERBOSE
765printf( "\n[convol] thread[%x,%d] starts final display at cycle %d\n",
766cxy , lid , (unsigned int)date );
767#else
768if ( (cxy == cxy_main) && (lid == lid_main) ) 
769printf( "\n[convol] thread[%x,%d] starts final display at cycle %d\n",
770cxy , lid, (unsigned int)date );
771#endif
772
773        unsigned int line;
774        unsigned int offset = lines_per_thread * lid;
775
776        for ( l = 0 ; l < lines_per_thread ; l++ )
777        {
778            line = offset + l;
779
780            for ( p = 0 ; p < NP ; p++ )
781            {
782                TZ(cluster_id, line, p) = 
783                   (unsigned char)( (TD(cluster_id, line, p) + 
784                                     TC(cluster_id, line, p) ) >> 8 );
785            }
786
787            if (fbf_write( &TZ(cluster_id, line, 0),                  // first pixel in TZ
788                           NP,                                        // number of bytes
789                           NP*(l + (thread_id * lines_per_thread))))  // offset in FBF
790            {
791                printf("\n[convol error] in %s : thread[%d,%d,%d] cannot access FBF\n",
792                __FUNCTION__ , x , y , lid );
793                pthread_exit( &THREAD_EXIT_FAILURE );
794            }
795        }
796
797        get_cycle( &date );
798        D_END[cluster_id][lid] = (unsigned int)date;
799
800#if VERBOSE
801printf( "\n[convol] thread[%x,%d] completes final display at cycle %d\n",
802cxy , lid , (unsigned int)date );
803#else
804if ( (cxy == cxy_main) && (lid == lid_main) ) 
805printf( "\n[convol] thread[%x,%d] completes final display at cycle %d\n",
806cxy , lid , (unsigned int)date );
807#endif
808     
809        ////////////////////////////////
810        pthread_barrier_wait( &barrier );
811    }
812
813    // all threads (but the one executing main) exit
814    if ( (cxy != cxy_main) || (lid != lid_main) )
815    {
816        pthread_exit( &THREAD_EXIT_SUCCESS );
817    }
818
819} // end execute()
820
821
822
823/////////////////////////////////////////
824void instrument( unsigned int nclusters,
825                 unsigned int ncores )
826{
827        unsigned int cc, pp;
828
829        unsigned int min_start = 0xFFFFFFFF;
830        unsigned int max_start = 0;
831
832        unsigned int min_h_beg = 0xFFFFFFFF;
833        unsigned int max_h_beg = 0;
834
835        unsigned int min_h_end = 0xFFFFFFFF;
836        unsigned int max_h_end = 0;
837
838        unsigned int min_v_beg = 0xFFFFFFFF;
839        unsigned int max_v_beg = 0;
840
841        unsigned int min_v_end = 0xFFFFFFFF;
842        unsigned int max_v_end = 0;
843
844        unsigned int min_d_beg = 0xFFFFFFFF;
845        unsigned int max_d_beg = 0;
846
847        unsigned int min_d_end = 0xFFFFFFFF;
848        unsigned int max_d_end = 0;
849
850        for (cc = 0; cc < nclusters; cc++)
851        {
852            for (pp = 0; pp < ncores; pp++ )
853            {
854                if (START[cc][pp] < min_start) min_start = START[cc][pp];
855                if (START[cc][pp] > max_start) max_start = START[cc][pp];
856
857                if (H_BEG[cc][pp] < min_h_beg) min_h_beg = H_BEG[cc][pp];
858                if (H_BEG[cc][pp] > max_h_beg) max_h_beg = H_BEG[cc][pp];
859
860                if (H_END[cc][pp] < min_h_end) min_h_end = H_END[cc][pp];
861                if (H_END[cc][pp] > max_h_end) max_h_end = H_END[cc][pp];
862
863                if (V_BEG[cc][pp] < min_v_beg) min_v_beg = V_BEG[cc][pp];
864                if (V_BEG[cc][pp] > max_v_beg) max_v_beg = V_BEG[cc][pp];
865
866                if (V_END[cc][pp] < min_v_end) min_v_end = V_END[cc][pp];
867                if (V_END[cc][pp] > max_v_end) max_v_end = V_END[cc][pp];
868
869                if (D_BEG[cc][pp] < min_d_beg) min_d_beg = D_BEG[cc][pp];
870                if (D_BEG[cc][pp] > max_d_beg) max_d_beg = D_BEG[cc][pp];
871
872                if (D_END[cc][pp] < min_d_end) min_d_end = D_END[cc][pp];
873                if (D_END[cc][pp] > max_d_end) max_d_end = D_END[cc][pp];
874            }
875        }
876
877        printf(" - START : min = %d / max = %d / med = %d / delta = %d\n",
878               min_start, max_start, (min_start+max_start)/2, max_start-min_start);
879
880        printf(" - H_BEG : min = %d / max = %d / med = %d / delta = %d\n",
881               min_h_beg, max_h_beg, (min_h_beg+max_h_beg)/2, max_h_beg-min_h_beg);
882
883        printf(" - H_END : min = %d / max = %d / med = %d / delta = %d\n",
884               min_h_end, max_h_end, (min_h_end+max_h_end)/2, max_h_end-min_h_end);
885
886        printf(" - V_BEG : min = %d / max = %d / med = %d / delta = %d\n",
887               min_v_beg, max_v_beg, (min_v_beg+max_v_beg)/2, max_v_beg-min_v_beg);
888
889        printf(" - V_END : min = %d / max = %d / med = %d / delta = %d\n",
890               min_v_end, max_v_end, (min_v_end+max_v_end)/2, max_v_end-min_v_end);
891
892        printf(" - D_BEG : min = %d / max = %d / med = %d / delta = %d\n",
893               min_d_beg, max_d_beg, (min_d_beg+max_d_beg)/2, max_d_beg-min_d_beg);
894
895        printf(" - D_END : min = %d / max = %d / med = %d / delta = %d\n",
896               min_d_end, max_d_end, (min_d_end+max_d_end)/2, max_d_end-min_d_end);
897
898        printf( "\n General Scenario (Kcycles for each step)\n" );
899        printf( " - BOOT OS           = %d\n", (min_start            )/1000 );
900        printf( " - LOAD IMAGE        = %d\n", (min_h_beg - min_start)/1000 );
901        printf( " - H_FILTER          = %d\n", (max_h_end - min_h_beg)/1000 );
902        printf( " - BARRIER HORI/VERT = %d\n", (min_v_beg - max_h_end)/1000 );
903        printf( " - V_FILTER          = %d\n", (max_v_end - min_v_beg)/1000 );
904        printf( " - BARRIER VERT/DISP = %d\n", (min_d_beg - max_v_end)/1000 );
905        printf( " - DISPLAY           = %d\n", (max_d_end - min_d_beg)/1000 );
906
907        // TODO save these results on f_instrum
908
909} // end instrument()
910
911
912
913
914
915// Local Variables:
916// tab-width: 3
917// c-basic-offset: 3
918// c-file-offsets:((innamespace . 0)(inline-open . 0))
919// indent-tabs-mode: nil
920// End:
921
922// vim: filetype=cpp:expandtab:shiftwidth=3:tabstop=3:softtabstop=3
923
924
Note: See TracBrowser for help on using the repository browser.