source: trunk/user/fft/fft.c @ 628

Last change on this file since 628 was 628, checked in by alain, 5 years ago

Introduce teh page_min / page_max mechanism in the fatfs_release_inode()
function, to avoid to scan all pages in FAT mapper.

File size: 44.9 KB
RevLine 
[469]1/*************************************************************************/
2/*                                                                       */
3/*  Copyright (c) 1994 Stanford University                               */
4/*                                                                       */
5/*  All rights reserved.                                                 */
6/*                                                                       */
7/*  Permission is given to use, copy, and modify this software for any   */
8/*  non-commercial purpose as long as this copyright notice is not       */
9/*  removed.  All other uses, including redistribution in whole or in    */
10/*  part, are forbidden without prior written permission.                */
11/*                                                                       */
12/*  This software is provided with absolutely no warranty and no         */
13/*  support.                                                             */
14/*                                                                       */
15/*************************************************************************/
16
17///////////////////////////////////////////////////////////////////////////
18// This port of the SPLASH FFT benchmark on the ALMOS-MKH OS has been
19// done by Alain Greiner (august 2018).
20//
21// This application performs the 1D fast Fourier transfom for an array
22// of N complex points, using the Cooley-Tuckey FFT method.
23// The N data points are seen as a 2D array (rootN rows * rootN columns).
24// Each thread handle (rootN / nthreads) rows. The N input data points
25// be initialised in three different modes:
26// - CONSTANT : all data points have the same [1,0] value
27// - COSIN    : data point n has [cos(n/N) , sin(n/N)] values
28// - RANDOM   : data points have pseudo random values
29//
[628]30// The main parameters for this generic application are the following:     
31//  - M : N = 2**M = number of data points / M must be an even number.
32//  - T : nthreads = ncores defined by the hardware / must be power of 2.
33//
34// This application uses 4 shared data arrays, that are dynamically
35// allocated an distributed, using the remote_malloc() function, with
36// one sub-buffer per cluster:
[469]37// - data[N] contains N input data points, with 2 double per point.
38// - trans[N] contains N intermediate data points, 2 double per point.
39// - umain[rootN] contains rootN coefs required for a rootN points FFT.
40// - twid[N] contains N coefs : exp(2*pi*i*j/N) / i and j in [0,rootN-1].
41// For data, trans, twid, each sub-buffer contains (N/nclusters) points.
42// For umain, each sub-buffer contains (rootN/nclusters) points.
43//
44// There is one thread per core.
45// The max number of clusters is defined by (X_MAX * Y_MAX).
46// The max number of cores per cluster is defined by CORES_MAX.
47//
48// Several configuration parameters can be defined below:
[574]49//  - PRINT_ARRAY : Print out complex data points arrays.
50//  - CHECK       : Perform both FFT and inverse FFT to check output/input.
51//  - DEBUG_MAIN  : Display intermediate results in main()
52//  - DEBUG_FFT1D : Display intermediate results in FFT1D()
[628]53//  - DEBUG_ROW   : Display intermedite results in FFTrow()
[469]54//
55// Regarding final instrumentation:
56// - the sequencial initialisation time (init_time) is computed
57//   by the main thread in the main() function.
58// - The parallel execution time (parallel_time[i]) is computed by each
59//   thread(i) in the slave() function.
60// - The synchronisation time related to the barriers (sync_time[i])
61//   is computed by each thread(i) in the slave() function.
62// The results are displayed on the TXT terminal, and registered on disk.
63///////////////////////////////////////////////////////////////////////////
64
65#include <math.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <fcntl.h>
69#include <unistd.h>
70#include <pthread.h>
71#include <almosmkh.h>
72#include <hal_macros.h>
73
74// constants
75
76#define PI                      3.14159265359
77#define PAGE_SIZE               4096
78#define X_MAX                   16              // max number of clusters in a row
79#define Y_MAX                   16              // max number of clusters in a column
80#define CORES_MAX               4               // max number of cores in a cluster
81#define CLUSTERS_MAX            X_MAX * Y_MAX
82#define THREADS_MAX             CLUSTERS_MAX * CORES_MAX
83#define RANDOM                  0
84#define COSIN                   1
85#define CONSTANT                2
86
87// parameters
88
[596]89#define DEFAULT_M               12              // 4096 data points
[628]90#define USE_DQT_BARRIER         0               // use DDT barrier if non zero
91#define MODE                    COSIN           // DATA array initialisation mode
92#define CHECK                   0               
93#define DEBUG_MAIN              1               // trace main() function (detailed if odd)
94#define DEBUG_SLAVE             0               // trace slave() function (detailed if odd)
95#define DEBUG_FFT1D             0               // trace FFT1D() function (detailed if odd)
[574]96#define DEBUG_ROW               0               // trace FFTRow() function (detailed if odd)
97#define PRINT_ARRAY             0
[469]98
99// macro to swap two variables
100#define SWAP(a,b) { double tmp; tmp = a; a = b; b = tmp; }
101
[588]102/////////////////////////////////////////////////////////////////////////////////////
103//             structure containing the arguments for the slave() function
104/////////////////////////////////////////////////////////////////////////////////////
105
106typedef struct args_s
107{
108    unsigned int   tid;                    // thread continuous index
109    unsigned int   main_tid;               // main thread continuous index
110}
111args_t;
112
113/////////////////////////////////////////////////////////////////////////////////////
[469]114//             global variables
[588]115/////////////////////////////////////////////////////////////////////////////////////
[469]116
117unsigned int   x_size;                     // number of clusters per row in the mesh
118unsigned int   y_size;                     // number of clusters per column in the mesh
119unsigned int   ncores;                     // number of cores per cluster
[473]120unsigned int   nthreads;                   // total number of threads (one thread per core)
121unsigned int   nclusters;                  // total number of clusters
122unsigned int   M = DEFAULT_M;              // log2(number of points)
123unsigned int   N;                          // number of points (N = 2^M)         
124unsigned int   rootN;                      // rootN = 2^M/2   
125unsigned int   rows_per_thread;            // number of data "rows" handled by a single thread
126unsigned int   points_per_cluster;         // number of data points per cluster
[469]127
128// arrays of pointers on distributed buffers (one sub-buffer per cluster)
129double *       data[CLUSTERS_MAX];         // original time-domain data
130double *       trans[CLUSTERS_MAX];        // used as auxiliary space for transpose
131double *       bloup[CLUSTERS_MAX];        // used as auxiliary space for DFT
132double *       umain[CLUSTERS_MAX];        // roots of unity used fo rootN points FFT   
133double *       twid[CLUSTERS_MAX];         // twiddle factor : exp(-2iPI*k*n/N)
134
135// instrumentation counters
[588]136unsigned int   parallel_time[THREADS_MAX]; // total computation time (per thread)
137unsigned int   sync_time[THREADS_MAX];     // cumulated waiting time in barriers (per thread)
138unsigned int   init_time;                  // initialisation time (in main)
[469]139
140// synchronisation barrier (all threads)
141pthread_barrier_t      barrier;
[628]142pthread_barrierattr_t  barrier_attr;
[469]143
144// threads identifiers, attributes, and arguments
145pthread_t       trdid[THREADS_MAX];        // kernel threads identifiers
146pthread_attr_t  attr[THREADS_MAX];         // POSIX thread attributes
[588]147args_t          args[THREADS_MAX];         // slave function arguments
[469]148
149/////////////////////////////////////////////////////////////////////////////////
150//           functions declaration
151/////////////////////////////////////////////////////////////////////////////////
152
[588]153void slave( args_t * args );
[469]154
[503]155double CheckSum( void );
[469]156
157void InitX(double ** x , unsigned int mode);
158
159void InitU(double ** u);
160
161void InitT(double ** u);
162
[473]163unsigned int BitReverse( unsigned int k );
[469]164
[473]165void FFT1D( int          direction,
166            double    ** x,
167            double    ** tmp,
168            double     * upriv, 
169            double    ** twid,
170            unsigned int MyNum,
171            unsigned int MyFirst,
172            unsigned int MyLast );
[469]173
[473]174void TwiddleOneCol( int          direction,
175                    unsigned int j,
176                    double    ** u,
177                    double    ** x,
178                    unsigned int offset_x );
[469]179
[473]180void Scale( double    ** x,
181            unsigned int offset_x );
[469]182
[473]183void Transpose( double    ** src, 
184                double    ** dest,
185                unsigned int MyFirst,
186                unsigned int MyLast );
[469]187
[473]188void Copy( double    ** src,
189           double    ** dest,
190           unsigned int MyFirst,
191           unsigned int MyLast );
[469]192
[473]193void Reverse( double    ** x, 
194              unsigned int offset_x );
[469]195
[574]196void FFTRow( int          direction,
[473]197                double     * u,
198                double    ** x,
199                unsigned int offset_x );
[469]200
[473]201void PrintArray( double ** x,
202                 unsigned int size );
[469]203
[473]204void SimpleDft( int          direction,
205                unsigned int size,
206                double    ** src,
207                unsigned int src_offset,
208                double    ** dst,
209                unsigned int dst_offset );
[469]210
211///////////////////////////////////////////////////////////////////
212// This main() function execute the sequencial initialisation
213// launch the parallel execution, and makes the instrumentation.
214///////////////////////////////////////////////////////////////////
[503]215void main ( void )
[469]216{
[628]217    int                 error;
218
[469]219    unsigned int        main_cxy;          // main thread cluster
220    unsigned int        main_x;            // main thread X coordinate
221    unsigned int        main_y;            // main thread y coordinate
222    unsigned int        main_lid;          // main thread local core index
223    unsigned int        main_tid;          // main thread continuous index
224
225    unsigned int        x;                 // current index for cluster X coordinate
226    unsigned int        y;                 // current index for cluster Y coordinate
227    unsigned int        lid;               // current index for core in a cluster
228    unsigned int        ci;                // continuous cluster index (from x,y)
229    unsigned int        cxy;               // hardware specific cluster identifier
230    unsigned int        tid;               // continuous thread index
231
232    unsigned long long  start_init_cycle; 
[588]233    unsigned long long  end_init_cycle;
[469]234
235#if CHECK
236double     ck1;           // for input/output checking
237double     ck3;           // for input/output checking
238#endif
239   
240    // get FFT application start cycle
[588]241    get_cycle( &start_init_cycle );
[469]242
243    // get platform parameters to compute nthreads & nclusters
244    if( get_config( &x_size , &y_size , &ncores ) )
245    {
[628]246        printf("\n[fft error] cannot get hardware configuration\n");
[469]247        exit( 0 );
248    }
249
250    // check ncores
251    if( (ncores != 1) && (ncores != 2) && (ncores != 4) )
252    {
[628]253        printf("\n[fft error] number of cores per cluster must be 1/2/4\n");
[469]254        exit( 0 );
255    }
256
257    // check x_size
258    if( (x_size != 1) && (x_size != 2) && (x_size != 4) && (x_size != 8) && (x_size != 16) )
259    {
[628]260        printf("\n[fft error] x_size must be 1/2/4/8/16\n");
[469]261        exit( 0 );
262    }
263
264    // check y_size
265    if( (y_size != 1) && (y_size != 2) && (y_size != 4) && (y_size != 8) && (y_size != 16) )
266    {
[628]267        printf("\n[fft error] y_size must be 1/2/4/8/16\n");
[469]268        exit( 0 );
269    }
270
271    nthreads  = x_size * y_size * ncores;
272    nclusters = x_size * y_size;
273
274    // compute various constants depending on N and T
275    N                  = 1 << M;
276    rootN              = 1 << (M / 2);
277    rows_per_thread    = rootN / nthreads;
278    points_per_cluster = N / nclusters;
279 
280    // check N versus T
281    if( rootN < nthreads )
282    {
[628]283        printf("\n[fft error] sqrt(N) must be larger than T\n");
[469]284        exit( 0 );
285    }
286
287    // get main thread coordinates (main_x, main_y, main_lid)
288    get_core( &main_cxy , &main_lid );
289    main_x   = HAL_X_FROM_CXY( main_cxy );
290    main_y   = HAL_Y_FROM_CXY( main_cxy );
291    main_tid = (((main_x * y_size) + main_y) * ncores) + main_lid; 
292
[628]293    printf("\n[fft] starts on core[%x,%d] / %d complex points / %d thread(s) / PID %x\n",
[588]294    main_cxy, main_lid, N, nthreads, getpid() );
[469]295
296    // allocate memory for the distributed data[i], trans[i], umain[i], twid[i] buffers
297    // the index (i) is a continuous cluster index
[473]298    unsigned int data_size   = (N / nclusters) * 2 * sizeof(double);
299    unsigned int coefs_size  = (rootN / nclusters) * 2 * sizeof(double);
[469]300    for (x = 0 ; x < x_size ; x++)
301    {
302        for (y = 0 ; y < y_size ; y++)
303        {
304            ci         = x * y_size + y;
305            cxy        = HAL_CXY_FROM_XY( x , y );
306            data[ci]   = (double *)remote_malloc( data_size  , cxy ); 
307            trans[ci]  = (double *)remote_malloc( data_size  , cxy ); 
308            bloup[ci]  = (double *)remote_malloc( data_size  , cxy ); 
309            umain[ci]  = (double *)remote_malloc( coefs_size , cxy ); 
310            twid[ci]   = (double *)remote_malloc( data_size  , cxy ); 
311        }
312    }
313
[628]314    printf("\n[fft] main completes remote_malloc\n");
[574]315
[469]316    // arrays initialisation
317    InitX( data , MODE ); 
318    InitU( umain ); 
319    InitT( twid );
320
[628]321    printf("\n[fft] main completes arrays init\n");
[574]322
[469]323#if CHECK
[473]324ck1 = CheckSum();
[469]325#endif
326
[574]327#if PRINT_ARRAY
[469]328printf("\nData values / base = %x\n", &data[0][0] );
329PrintArray( data , N );
330
331printf("\nTwiddle values / base = %x\n", &twid[0][0] );
332PrintArray( twid , N );
333
334SimpleDft( 1 , N , data , 0 , bloup , 0 );
335
336printf("\nExpected results / base = %x\n", &bloup[0][0] );
337PrintArray( bloup , N );
338#endif
339
[582]340    // initialise barrier
[628]341    if( USE_DQT_BARRIER )
[473]342    {
[628]343        barrier_attr.x_size   = x_size;
344        barrier_attr.y_size   = y_size;
345        barrier_attr.nthreads = ncores;
346        error = pthread_barrier_init( &barrier, &barrier_attr , nthreads );
347    }
348    else
349    {
350        error = pthread_barrier_init( &barrier, NULL , nthreads );
351    }
352
353    if( error )
354    {
355        printf("\n[fft error] cannot initialize barrier\n");
[473]356        exit( 0 );
357    }
[469]358
[628]359    printf("\n[fft] main completes barrier init\n");
[473]360
[469]361    // launch other threads to execute the slave() function
362    // on cores other than the core running the main thread
363    for (x = 0 ; x < x_size ; x++)
364    {
365        for (y = 0 ; y < y_size ; y++)
366        {
[588]367            // compute cluster identifier
368            cxy = HAL_CXY_FROM_XY( x , y );
369
[469]370            for ( lid = 0 ; lid < ncores ; lid++ )
371            {
[582]372                // compute thread user index (continuous index)
[469]373                tid = (((x * y_size) + y) * ncores) + lid;
374
375                // set thread attributes
376                attr[tid].attributes = PT_ATTR_CLUSTER_DEFINED | PT_ATTR_CORE_DEFINED;
[588]377                attr[tid].cxy        = cxy;
[469]378                attr[tid].lid        = lid;
379
380                // set slave function argument
[588]381                args[tid].tid      = tid;
382                args[tid].main_tid = main_tid;
[469]383
384                // create thread
385                if( tid != main_tid )
386                {
387                    if ( pthread_create( &trdid[tid],  // pointer on kernel identifier
388                                         &attr[tid],   // pointer on thread attributes
389                                         &slave,       // pointer on function
390                                         &args[tid]) ) // pointer on function arguments
391                    {
[628]392                        printf("\n[fft error] creating thread %x\n", tid );
[469]393                        exit( 0 );
394                    }
[628]395#if (DEBUG_MAIN & 1)
[588]396unsigned long long debug_cycle; 
397get_cycle( &debug_cycle ); 
[628]398printf("\n[fft] main created thread %d on core[%x,%d] / cycle %d\n",
[588]399tid, cxy, lid, (unsigned int)debug_cycle );
[469]400#endif
401                }
402            }
403        }
404    }
405
[628]406
[469]407    // register sequencial initalisation completion cycle
[588]408    get_cycle( &end_init_cycle );
409    init_time = (unsigned int)(end_init_cycle - start_init_cycle);
410
[628]411    printf("\n[fft] main completes threads creation\n");
[469]412   
[588]413    // main itself executes the slave() function
[469]414    slave( &args[main_tid] );
415
416    // wait other threads completion
417    for (x = 0 ; x < x_size ; x++)
418    {
419        for (y = 0 ; y < y_size ; y++)
420        {
421            for ( lid = 0 ; lid < ncores ; lid++ )
422            {
423                // compute thread continuous index
[473]424                tid = (((x * y_size) + y) * ncores) + lid;
[469]425
426                if( tid != main_tid )
427                {
428                    if( pthread_join( trdid[tid] , NULL ) )
429                    {
[628]430                        printf("\n[fft error] in main thread joining thread %x\n", tid );
[469]431                        exit( 0 );
432                    }
[588]433                   
[628]434#if (DEBUG_MAIN & 1)
435printf("\n[fft] main thread %d joined thread %d\n", main_tid, tid );
[588]436#endif
[469]437
438                }
439            }
440        }
441    }
442
[574]443#if PRINT_ARRAY
[469]444printf("\nData values after FFT:\n");
445PrintArray( data , N );
446#endif
447
448#if CHECK
[473]449ck3 = CheckSum();
[469]450printf("\n*** Results ***\n");
451printf("Checksum difference is %f (%f, %f)\n", ck1 - ck3, ck1, ck3);
452if (fabs(ck1 - ck3) < 0.001)  printf("Results OK\n");
453else                          printf("Results KO\n");
454#endif
455
456    // instrumentation
[628]457    char name[64];
458    char path[128];
[469]459    char string[256];
[628]460    int  ret;
[469]461
[628]462    // build file name
463    if( USE_DQT_BARRIER )
464    snprintf( name , 64 , "fft_dqt_%d_%d_%d_%d", x_size , y_size , ncores , N );
465    else
466    snprintf( name , 64 , "fft_smp_%d_%d_%d_%d", x_size , y_size , ncores , N );
[469]467
[628]468    // build pathname
469    snprintf( path , 128 , "/home/%s", name );
470
[469]471    // open instrumentation file
[628]472    FILE * f = fopen( path , NULL );
473    if ( f == NULL ) 
474    { 
475        printf("\n[fft error] cannot open instrumentation file <%s>\n", path );
476        exit( 0 );
477    }
478    printf("\n[fft] file <%s> open\n", path );
[469]479
[628]480    // display header on terminal, and save to file
481    printf("\n----- %s -----\n", name );
[469]482
[628]483    ret = fprintf( f , "\n----- %s -----\n", name );
484    if( ret < 0 )
485    {
486        printf("\n[fft error] cannot write header to file <%s>\n", path );
487        exit(0);
488    }
[469]489
[628]490    // display results for each thread on terminal, and save to file
[588]491    for (tid = 0 ; tid < nthreads ; tid++) 
492    {
[628]493        snprintf( string , 256 , "- tid %d : Sequencial %d / Parallel %d / Barrier %d\n",
[588]494        tid, init_time, parallel_time[tid], sync_time[tid] );
495
496        // display on terminal, and save to instrumentation file
497        printf("%s" , string );
[628]498        fprintf( f , "%s" , string );
499        if( ret < 0 )
500        {
501            printf("\n[fft error] cannot write thread %d to file <%s>\n", tid, path );
502            exit(0);
503        }
[588]504    }
505
[628]506    // display MIN/MAX values on terminal and save to file
507    unsigned int min_para = parallel_time[0];
508    unsigned int max_para = parallel_time[0];
509    unsigned int min_sync = sync_time[0];
510    unsigned int max_sync = sync_time[0];
[588]511
[469]512    for (tid = 1 ; tid < nthreads ; tid++) 
513    {
514        if (parallel_time[tid] > max_para)  max_para = parallel_time[tid];
515        if (parallel_time[tid] < min_para)  min_para = parallel_time[tid];
516        if (sync_time[tid]     > max_sync)  max_sync = sync_time[tid];
517        if (sync_time[tid]     < min_sync)  min_sync = sync_time[tid];
518    }
519
[628]520    snprintf( string , 256 , "\n      Sequencial  Parallel       Barrier\n"
[588]521                             "MIN : %d\t | %d\t | %d\t   (cycles)\n" 
522                             "MAX : %d\t | %d\t | %d\t   (cycles)\n",
[469]523                             (int)init_time, (int)min_para, (int)min_sync,
524                             (int)init_time, (int)max_para, (int)max_sync );
[628]525    printf("%s", string );
526    ret = fprintf( f , "%s", string );
527    if( ret < 0 )
528    {
529        printf("\n[fft error] cannot write MIN/MAX to file <%s>\n", path );
530        exit(0);
531    }
[469]532
[628]533    // close instrumentation file
534    ret = fclose( f );
535    if( ret )
536    {
537        printf("\n[fft error] cannot close file <%s>\n", path );
538        exit(0);
539    }
540    printf("\n[sort] file <%s> closed\n", path );
[469]541
[628]542    exit( 0 );
543
[469]544} // end main()
545
546///////////////////////////////////////////////////////////////
547// This function is executed in parallel by all threads.
548///////////////////////////////////////////////////////////////
[588]549void slave( args_t * args ) 
[469]550{
[473]551    unsigned int   i;
[588]552    unsigned int   MyNum;           // this thread index
553    unsigned int   MainNum;         // main thread index
[473]554    unsigned int   MyFirst;         // index first row allocated to thread
555    unsigned int   MyLast;          // index last row allocated to thread
556    double       * upriv;
557    unsigned int   c_id;
558    unsigned int   c_offset;
[469]559
560    unsigned long long  parallel_start;
561    unsigned long long  parallel_stop;
562    unsigned long long  barrier_start;
563    unsigned long long  barrier_stop;
564
[588]565    MyNum   = args->tid;
566    MainNum = args->main_tid;
[469]567
568    // initialise instrumentation
569    get_cycle( &parallel_start );
570
[588]571#if DEBUG_SLAVE
[628]572printf("\n[fft] %s : thread %x enter / cycle %d\n",
[588]573__FUNCTION__, MyNum, (unsigned int)parallel_start );
574#endif
575
[469]576    // allocate and initialise local array upriv[]
577    // that is a local copy of the rootN coefs defined in umain[]
578    upriv = (double *)malloc(2 * (rootN - 1) * sizeof(double)); 
579    for ( i = 0 ; i < (rootN - 1) ; i++) 
580    {
581        c_id     = i / (rootN / nclusters);
582        c_offset = i % (rootN / nclusters);
583        upriv[2*i]   = umain[c_id][2*c_offset];
584        upriv[2*i+1] = umain[c_id][2*c_offset+1];
585    }
586
587    // compute first and last rows handled by the thread
588    MyFirst = rootN * MyNum / nthreads;
589    MyLast  = rootN * (MyNum + 1) / nthreads;
590
591    // perform forward FFT
592    FFT1D( 1 , data , trans , upriv , twid , MyNum , MyFirst , MyLast );
593
594    // BARRIER
595    get_cycle( &barrier_start );
596    pthread_barrier_wait( &barrier );
597    get_cycle( &barrier_stop );
598
[588]599    sync_time[MyNum] += (barrier_stop - barrier_start);
[469]600
601#if CHECK
602get_cycle( &barrier_start );
603pthread_barrier_wait( &barrier );
604get_cycle( &barrier_stop );
605
606sync_time[MyNum] += (long)(barrier_stop - barrier_start);
607
608FFT1D( -1 , data , trans , upriv , twid , MyNum , MyFirst , MyLast );
609#endif
610
611    // register computation time
612    get_cycle( &parallel_stop );
[588]613    parallel_time[MyNum] = (parallel_stop - parallel_start);
[469]614
[588]615#if DEBUG_SLAVE
[628]616printf("\n[fft] %s : thread %x exit / cycle %d\n", __FUNCTION__, MyNum, parallel_stop );
[588]617#endif
[469]618
[588]619    // exit only if MyNum != MainNum
620    if( MyNum != MainNum ) pthread_exit( NULL );
621
[469]622}  // end slave()
623
624////////////////////////////////////////////////////////////////////////////////////////
625// This function makes the DFT from the src[nclusters][points_per_cluster] distributed
626// buffer, to the dst[nclusters][points_per_cluster] distributed buffer.
627////////////////////////////////////////////////////////////////////////////////////////
[473]628void SimpleDft( int             direction,      // 1 direct / -1 reverse
629                unsigned int    size,           // number of points
630                double       ** src,            // source distributed buffer
631                unsigned int    src_offset,     // offset in source array
632                double       ** dst,            // destination distributed buffer
633                unsigned int    dst_offset )    // offset in destination array
[469]634{
[473]635    unsigned int  n , k;
636    double        phi;            // 2*PI*n*k/N
637    double        u_r;            // cos( phi )
638    double        u_c;            // sin( phi )
639    double        d_r;            // Re(data[n])
640    double        d_c;            // Im(data[n])
641    double        accu_r;         // Re(accu)
642    double        accu_c;         // Im(accu)
643    unsigned int  c_id;           // distributed buffer cluster index
644    unsigned int  c_offset;       // offset in distributed buffer
[469]645
646    for ( k = 0 ; k < size ; k++ )       // loop on the output data points
647    {
648        // initialise accu
649        accu_r = 0;
650        accu_c = 0;
651
652        for ( n = 0 ; n < size ; n++ )   // loop on the input data points
653        {
654            // compute coef
655            phi = (double)(2*PI*n*k) / size;
656            u_r =  cos( phi );
657            u_c = -sin( phi ) * direction;
658
659            // get input data point
660            c_id     = (src_offset + n) / (points_per_cluster);
661            c_offset = (src_offset + n) % (points_per_cluster);
[473]662            d_r      = src[c_id][2*c_offset];
663            d_c      = src[c_id][2*c_offset+1];
[469]664
665            // increment accu
666            accu_r += ((u_r*d_r) - (u_c*d_c));
667            accu_c += ((u_r*d_c) + (u_c*d_r));
668        }
669
670        // scale for inverse DFT
671        if ( direction == -1 )
672        {
673            accu_r /= size;
674            accu_c /= size;
675        }
676
677        // set output data point
678        c_id     = (dst_offset + k) / (points_per_cluster);
679        c_offset = (dst_offset + k) % (points_per_cluster);
680        dst[c_id][2*c_offset]   = accu_r;
681        dst[c_id][2*c_offset+1] = accu_c;
682    }
683
684}  // end SimpleDft()
685
[582]686///////////////////////
[503]687double CheckSum( void )
[469]688{
[473]689    unsigned int         i , j;
[469]690    double       cks;
[473]691    unsigned int         c_id;
692    unsigned int         c_offset;
[469]693
694    cks = 0.0;
695    for (j = 0; j < rootN ; j++) 
696    {
697        for (i = 0; i < rootN ; i++) 
698        {
699            c_id      = (rootN * j + i) / (points_per_cluster);
700            c_offset  = (rootN * j + i) % (points_per_cluster);
701
702            cks += data[c_id][2*c_offset] + data[c_id][2*c_offset+1];
703        }
704    }
705    return(cks);
706}
707
708
709////////////////////////////
710void InitX(double      ** x,
711           unsigned int   mode ) 
712{
[473]713    unsigned int    i , j;
714    unsigned int    c_id;
715    unsigned int    c_offset;
716    unsigned int    index;
[469]717
718    for ( j = 0 ; j < rootN ; j++ )      // loop on row index
719    { 
720        for ( i = 0 ; i < rootN ; i++ )  // loop on point in a row
721        { 
722            index     = j * rootN + i;
723            c_id      = index / (points_per_cluster);
724            c_offset  = index % (points_per_cluster);
725
726            // complex input signal is random
727            if ( mode == RANDOM )               
728            {
[473]729                x[c_id][2*c_offset]   = ( (double)rand() ) / 65536;
730                x[c_id][2*c_offset+1] = ( (double)rand() ) / 65536;
[469]731            }
732           
733
734            // complex input signal is cos(n/N) / sin(n/N)
735            if ( mode == COSIN )               
736            {
737                double phi = (double)( 2 * PI * index) / N;
[473]738                x[c_id][2*c_offset]   = cos( phi );
739                x[c_id][2*c_offset+1] = sin( phi );
[469]740            }
741
742            // complex input signal is constant
743            if ( mode == CONSTANT )               
744            {
[473]745                x[c_id][2*c_offset]   = 1.0;
746                x[c_id][2*c_offset+1] = 0.0;
[469]747            }
748        }
749    }
750}
751
752/////////////////////////
753void InitU( double ** u ) 
754{
[473]755    unsigned int    q; 
756    unsigned int    j; 
757    unsigned int    base; 
758    unsigned int    n1;
759    unsigned int    c_id;
760    unsigned int    c_offset;
[469]761    double  phi;
[473]762    unsigned int    stop = 0;
[469]763
[473]764    for (q = 0 ; ((unsigned int)(1 << q) < N) && (stop == 0) ; q++) 
[469]765    { 
766        n1 = 1 << q;
767        base = n1 - 1;
768        for (j = 0; (j < n1) && (stop == 0) ; j++) 
769        {
770            if (base + j > rootN - 1) return;
771
772            c_id      = (base + j) / (rootN / nclusters);
773            c_offset  = (base + j) % (rootN / nclusters);
774            phi = (double)(2.0 * PI * j) / (2 * n1);
775            u[c_id][2*c_offset]   = cos( phi );
776            u[c_id][2*c_offset+1] = -sin( phi );
777        }
778    }
779}
780
781//////////////////////////
782void InitT( double ** u )
783{
[473]784    unsigned int    i, j;
785    unsigned int    index;
786    unsigned int    c_id;
787    unsigned int    c_offset;
[469]788    double  phi;
789
790    for ( j = 0 ; j < rootN ; j++ )      // loop on row index
791    { 
792        for ( i = 0 ; i < rootN ; i++ )  // loop on points in a row
793        { 
794            index     = j * rootN + i;
795            c_id      = index / (points_per_cluster);
796            c_offset  = index % (points_per_cluster);
797
798            phi = (double)(2.0 * PI * i * j) / N;
799            u[c_id][2*c_offset]   = cos( phi );
800            u[c_id][2*c_offset+1] = -sin( phi );
801        }
802    }
803}
804
805////////////////////////////////////////////////////////////////////////////////////////
806// This function returns an index value that is the bit reverse of the input value.
807////////////////////////////////////////////////////////////////////////////////////////
[473]808unsigned int BitReverse( unsigned int k ) 
[469]809{
[473]810    unsigned int i; 
811    unsigned int j; 
812    unsigned int tmp;
[469]813
814    j = 0;
815    tmp = k;
816    for (i = 0; i < M/2 ; i++) 
817    {
818        j = 2 * j + (tmp & 0x1);
819        tmp = tmp >> 1;
820    }
821    return j;
822}
823
824////////////////////////////////////////////////////////////////////////////////////////
825// This function perform the in place (direct or inverse) FFT on the N data points
826// contained in the distributed buffers x[nclusters][points_per_cluster].
827// It handles the (N) points 1D array as a (rootN*rootN) points 2D array.
828// 1) it transpose (rootN/nthreads ) rows from x to tmp.
829// 2) it make (rootN/nthreads) FFT on the tmp rows and apply the twiddle factor.
830// 3) it transpose (rootN/nthreads) columns from tmp to x.
831// 4) it make (rootN/nthreads) FFT on the x rows.
[574]832// It calls the FFTRow() 2*(rootN/nthreads) times to perform the in place FFT
[469]833// on the rootN points contained in a row.
834////////////////////////////////////////////////////////////////////////////////////////
[473]835void FFT1D( int              direction,       // direct 1 / inverse -1
836            double       **  x,               // input & output distributed data points array
837            double       **  tmp,             // auxiliary distributed data points array
838            double        *  upriv,           // local array containing coefs for rootN FFT
839            double       **  twid,            // distributed arrays containing N twiddle factors
840            unsigned int     MyNum,           // thread continuous index
841            unsigned int     MyFirst, 
842            unsigned int     MyLast )
[469]843{
[473]844    unsigned int j;
[469]845    unsigned long long barrier_start;
846    unsigned long long barrier_stop;
847
[574]848#if DEBUG_FFT1D
[588]849unsigned long long cycle;
850get_cycle( &cycle );
[628]851printf("\n[fft] %s : thread %x enter / first %d / last %d / cycle %d\n",
[588]852__FUNCTION__, MyNum, MyFirst, MyLast, (unsigned int)cycle );
[574]853#endif
854
[469]855    // transpose (rootN/nthreads) rows from x to tmp
856    Transpose( x , tmp , MyFirst , MyLast );
857
[574]858#if( DEBUG_FFT1D & 1 )
859get_cycle( &cycle );
[628]860printf("\n[fft] %s : thread %x after first transpose / cycle %d\n",
[574]861__FUNCTION__, MyNum, (unsigned int)cycle );
862if( PRINT_ARRAY ) PrintArray( tmp , N );
[469]863#endif
864
865    // BARRIER
866    get_cycle( &barrier_start );
867    pthread_barrier_wait( &barrier );
868    get_cycle( &barrier_stop );
869    sync_time[MyNum] = (long)(barrier_stop - barrier_start);
870
[574]871#if( DEBUG_FFT1D & 1 )
872get_cycle( &cycle );
[628]873printf("\n[fft] %s : thread %x exit barrier after first transpose / cycle %d\n",
[574]874__FUNCTION__, MyNum, (unsigned int)cycle );
875#endif
876
[469]877    // do FFTs on rows of tmp (i.e. columns of x) and apply twiddle factor
878    for (j = MyFirst; j < MyLast; j++) 
879    {
[574]880        FFTRow( direction , upriv , tmp , j * rootN );
881
[469]882        TwiddleOneCol( direction , j , twid , tmp , j * rootN );
883    } 
884
[574]885#if( DEBUG_FFT1D & 1 )
[628]886printf("\n[fft] %s : thread %x after first twiddle\n", __FUNCTION__, MyNum);
[574]887if( PRINT_ARRAY ) PrintArray( tmp , N );
[469]888#endif
889
890    // BARRIER
891    get_cycle( &barrier_start );
892    pthread_barrier_wait( &barrier );
893    get_cycle( &barrier_stop );
894
[574]895#if( DEBUG_FFT1D & 1 )
[628]896printf("\n[fft] %s : thread %x exit barrier after first twiddle\n", __FUNCTION__, MyNum);
[574]897#endif
898
[469]899    sync_time[MyNum] += (long)(barrier_stop - barrier_start);
900
901    // transpose tmp to x
902    Transpose( tmp , x , MyFirst , MyLast );
903
[574]904#if( DEBUG_FFT1D & 1 )
[628]905printf("\n[fft] %s : thread %x after second transpose\n", __FUNCTION__, MyNum);
[574]906if( PRINT_ARRAY ) PrintArray( x , N );
[469]907#endif
908
909    // BARRIER
910    get_cycle( &barrier_start );
911    pthread_barrier_wait( &barrier );
912    get_cycle( &barrier_stop );
913
[574]914#if( DEBUG_FFT1D & 1 )
[628]915printf("\n[fft] %s : thread %x exit barrier after second transpose\n", __FUNCTION__, MyNum);
[574]916#endif
917
[469]918    sync_time[MyNum] += (long)(barrier_stop - barrier_start);
919
920    // do FFTs on rows of x and apply the scaling factor
921    for (j = MyFirst; j < MyLast; j++) 
922    {
[574]923        FFTRow( direction , upriv , x , j * rootN );
[469]924        if (direction == -1) Scale( x , j * rootN );
925    }
926
[574]927#if( DEBUG_FFT1D & 1 )
[628]928printf("\n[fft] %s : thread %x after FFT on rows\n", __FUNCTION__, MyNum);
[574]929if( PRINT_ARRAY ) PrintArray( x , N );
[469]930#endif
931
932    // BARRIER
933    get_cycle( &barrier_start );
934    pthread_barrier_wait( &barrier );
935    get_cycle( &barrier_stop );
936
[574]937#if( DEBUG_FFT1D & 1 )
[628]938printf("\n[fft] %s : thread %x exit barrier after FFT on rows\n", __FUNCTION__, MyNum);
[574]939#endif
[469]940    sync_time[MyNum] += (long)(barrier_stop - barrier_start);
941
942    // transpose x to tmp
943    Transpose( x , tmp , MyFirst , MyLast );
944
[574]945#if( DEBUG_FFT1D & 1 )
[628]946printf("\n[fft] %s : thread %x after third transpose\n", __FUNCTION__, MyNum);
[574]947if( PRINT_ARRAY ) PrintArray( x , N );
[469]948#endif
949
950    // BARRIER
951    get_cycle( &barrier_start );
952    pthread_barrier_wait( &barrier );
953    get_cycle( &barrier_stop );
954
[574]955#if( DEBUG_FFT1D & 1 )
[628]956printf("\n[fft] %s : thread %x exit barrier after third transpose\n", __FUNCTION__, MyNum);
[574]957#endif
958
[469]959    sync_time[MyNum] += (long)(barrier_stop - barrier_start);
[574]960    sync_time[MyNum] += (long)(barrier_stop - barrier_start);
[469]961
962    // copy tmp to x
963    Copy( tmp , x , MyFirst , MyLast );
964
965#if DEBUG_FFT1D
[628]966printf("\n[fft] %s : thread %x completed\n", __FUNCTION__, MyNum);
[574]967if( PRINT_ARRAY ) PrintArray( x , N );
[469]968#endif
969
970}  // end FFT1D()
971
972/////////////////////////////////////////////////////////////////////////////////////
973// This function multiply all points contained in a row (rootN points) of the
974// x[] array by the corresponding twiddle factor, contained in the u[] array.
975/////////////////////////////////////////////////////////////////////////////////////
[473]976void TwiddleOneCol( int             direction, 
977                    unsigned int    j,              // y coordinate in 2D view of coef array
978                    double       ** u,              // coef array base address
979                    double       ** x,              // data array base address
980                    unsigned int    offset_x )      // first point in N points data array
[469]981{
[473]982    unsigned int i;
[469]983    double       omega_r; 
984    double       omega_c; 
985    double       x_r; 
986    double       x_c;
[473]987    unsigned int c_id;
988    unsigned int c_offset;
[469]989
990    for (i = 0; i < rootN ; i++)  // loop on the rootN points
991    {
992        // get coef
993        c_id      = (j * rootN + i) / (points_per_cluster);
994        c_offset  = (j * rootN + i) % (points_per_cluster);
995        omega_r = u[c_id][2*c_offset];
996        omega_c = direction * u[c_id][2*c_offset+1];
997
998        // access data
999        c_id      = (offset_x + i) / (points_per_cluster);
1000        c_offset  = (offset_x + i) % (points_per_cluster);   
1001        x_r = x[c_id][2*c_offset]; 
1002        x_c = x[c_id][2*c_offset+1];
1003
1004        x[c_id][2*c_offset]   = omega_r*x_r - omega_c * x_c;
1005        x[c_id][2*c_offset+1] = omega_r*x_c + omega_c * x_r;
1006    }
1007}  // end TwiddleOneCol()
1008
[473]1009////////////////////////////
1010void Scale( double      ** x,           // data array base address
1011            unsigned int   offset_x )   // first point of the row to be scaled
[469]1012{
[473]1013    unsigned int i;
1014    unsigned int c_id;
1015    unsigned int c_offset;
[469]1016
1017    for (i = 0; i < rootN ; i++) 
1018    {
1019        c_id      = (offset_x + i) / (points_per_cluster);
1020        c_offset  = (offset_x + i) % (points_per_cluster);
[473]1021        x[c_id][2*c_offset]     /= N;
1022        x[c_id][2*c_offset + 1] /= N;
[469]1023    }
1024}
1025
[473]1026///////////////////////////////////
1027void Transpose( double      ** src,      // source buffer (array of pointers)
1028                double      ** dest,     // destination buffer (array of pointers)
1029                unsigned int   MyFirst,  // first row allocated to the thread
1030                unsigned int   MyLast )  // last row allocated to the thread
[469]1031{
[473]1032    unsigned int row;               // row index
1033    unsigned int point;             // data point index in a row
[469]1034
[473]1035    unsigned int index_src;         // absolute index in the source N points array
1036    unsigned int c_id_src;          // cluster for the source buffer
1037    unsigned int c_offset_src;      // offset in the source buffer
[469]1038
[473]1039    unsigned int index_dst;         // absolute index in the dest N points array
1040    unsigned int c_id_dst;          // cluster for the dest buffer
1041    unsigned int c_offset_dst;      // offset in the dest buffer
[469]1042
1043   
1044    // scan all data points allocated to the thread
1045    // (between MyFirst row and MyLast row) from the source buffer
1046    // and write these points to the destination buffer
1047    for ( row = MyFirst ; row < MyLast ; row++ )       // loop on the rows
1048    {
1049        for ( point = 0 ; point < rootN ; point++ )    // loop on points in row
1050        {
1051            index_src    = row * rootN + point;
1052            c_id_src     = index_src / (points_per_cluster);
1053            c_offset_src = index_src % (points_per_cluster);
1054
1055            index_dst    = point * rootN + row;
1056            c_id_dst     = index_dst / (points_per_cluster);
1057            c_offset_dst = index_dst % (points_per_cluster);
1058
1059            dest[c_id_dst][2*c_offset_dst]   = src[c_id_src][2*c_offset_src];
1060            dest[c_id_dst][2*c_offset_dst+1] = src[c_id_src][2*c_offset_src+1];
1061        }
1062    }
1063}  // end Transpose()
1064
[473]1065//////////////////////////////
1066void Copy( double      ** src,      // source buffer (array of pointers)
1067           double      ** dest,     // destination buffer (array of pointers)
1068           unsigned int   MyFirst,  // first row allocated to the thread
1069           unsigned int   MyLast )  // last row allocated to the thread
[469]1070{
[473]1071    unsigned int row;                  // row index
1072    unsigned int point;                // data point index in a row
[469]1073
[473]1074    unsigned int index;                // absolute index in the N points array
1075    unsigned int c_id;                 // cluster index
1076    unsigned int c_offset;             // offset in local buffer
[469]1077
1078    // scan all data points allocated to the thread
1079    for ( row = MyFirst ; row < MyLast ; row++ )       // loop on the rows
1080    {
1081        for ( point = 0 ; point < rootN ; point++ )    // loop on points in row
1082        {
1083            index    = row * rootN + point;
1084            c_id     = index / (points_per_cluster);
1085            c_offset = index % (points_per_cluster);
1086
1087            dest[c_id][2*c_offset]   = src[c_id][2*c_offset];
1088            dest[c_id][2*c_offset+1] = src[c_id][2*c_offset+1];
1089        }
1090    }
1091}  // end Copy()
1092
[473]1093///////////////////////////////
1094void Reverse( double      ** x, 
1095              unsigned int   offset_x )
[469]1096{
[473]1097    unsigned int j, k;
1098    unsigned int c_id_j;
1099    unsigned int c_offset_j;
1100    unsigned int c_id_k;
1101    unsigned int c_offset_k;
[469]1102
1103    for (k = 0 ; k < rootN ; k++) 
1104    {
1105        j = BitReverse( k );
1106        if (j > k) 
1107        {
1108            c_id_j      = (offset_x + j) / (points_per_cluster);
1109            c_offset_j  = (offset_x + j) % (points_per_cluster);
1110            c_id_k      = (offset_x + k) / (points_per_cluster);
1111            c_offset_k  = (offset_x + k) % (points_per_cluster);
1112
1113            SWAP(x[c_id_j][2*c_offset_j]  , x[c_id_k][2*c_offset_k]);
1114            SWAP(x[c_id_j][2*c_offset_j+1], x[c_id_k][2*c_offset_k+1]);
1115        }
1116    }
1117}
1118
1119/////////////////////////////////////////////////////////////////////////////
1120// This function makes the in-place FFT on all points contained in a row
1121// (i.e. rootN points) of the x[nclusters][points_per_cluster] array.
1122/////////////////////////////////////////////////////////////////////////////
[574]1123void FFTRow( int            direction,  // 1 direct / -1 inverse
[473]1124                double       * u,          // private coefs array
1125                double      ** x,          // array of pointers on distributed buffers
1126                unsigned int   offset_x )  // absolute offset in the x array
[469]1127{
[473]1128    unsigned int     j;
1129    unsigned int     k;
1130    unsigned int     q;
1131    unsigned int     L;
1132    unsigned int     r;
1133    unsigned int     Lstar;
[469]1134    double * u1; 
1135
[473]1136    unsigned int     offset_x1;     // index first butterfly input
1137    unsigned int     offset_x2;     // index second butterfly output
[469]1138
[473]1139    double           omega_r;       // real part butterfy coef
1140    double           omega_c;       // complex part butterfly coef
[469]1141
[473]1142    double           tau_r;
1143    double           tau_c;
[469]1144
[473]1145    double           d1_r;          // real part first butterfly input
1146    double           d1_c;          // imag part first butterfly input
1147    double           d2_r;          // real part second butterfly input
1148    double           d2_c;          // imag part second butterfly input
[469]1149
[473]1150    unsigned int     c_id_1;        // cluster index for first butterfly input
1151    unsigned int     c_offset_1;    // offset for first butterfly input
1152    unsigned int     c_id_2;        // cluster index for second butterfly input
1153    unsigned int     c_offset_2;    // offset for second butterfly input
[469]1154
[574]1155#if DEBUG_ROW
[469]1156unsigned int p;
[628]1157printf("\n[fft] ROW data in / %d points / offset = %d\n", rootN , offset_x );
[574]1158
[469]1159for ( p = 0 ; p < rootN ; p++ )
1160{
[473]1161    unsigned int index    = offset_x + p;
1162    unsigned int c_id     = index / (points_per_cluster);
1163    unsigned int c_offset = index % (points_per_cluster);
[469]1164    printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1165}
1166printf("\n");
1167#endif
1168
1169    // This makes the rootN input points reordering
1170    Reverse( x , offset_x ); 
1171
[574]1172#if DEBUG_ROW
[628]1173printf("\n[fft] ROW data after reverse / %d points / offset = %d\n", rootN , offset_x );
[574]1174
[469]1175for ( p = 0 ; p < rootN ; p++ )
1176{
[473]1177    unsigned int index    = offset_x + p;
1178    unsigned int c_id     = index / (points_per_cluster);
1179    unsigned int c_offset = index % (points_per_cluster);
[469]1180    printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1181}
1182printf("\n");
1183#endif
1184
1185    // This implements the multi-stages, in place Butterfly network
1186    for (q = 1; q <= M/2 ; q++)     // loop on stages
1187    {
1188        L = 1 << q;       // number of points per subset for current stage
1189        r = rootN / L;    // number of subsets
1190        Lstar = L / 2;
1191        u1 = &u[2 * (Lstar - 1)];
1192        for (k = 0; k < r; k++)     // loop on the subsets
1193        {
1194            offset_x1  = offset_x + (k * L);            // index first point
1195            offset_x2  = offset_x + (k * L + Lstar);    // index second point
1196
[574]1197#if (DEBUG_ROW & 1)
1198printf("\n ### q = %d / k = %d / x1 = %d / x2 = %d\n", q , k , offset_x1 , offset_x2 );
[469]1199#endif
1200            // makes all in-place butterfly(s) for subset
1201            for (j = 0; j < Lstar; j++) 
1202            {
1203                // get coef
1204                omega_r = u1[2*j];
1205                omega_c = direction * u1[2*j+1];
1206
1207                // get d[x1] address and value
1208                c_id_1      = (offset_x1 + j) / (points_per_cluster);
1209                c_offset_1  = (offset_x1 + j) % (points_per_cluster);
1210                d1_r        = x[c_id_1][2*c_offset_1];
1211                d1_c        = x[c_id_1][2*c_offset_1+1];
1212
1213                // get d[x2] address and value
1214                c_id_2      = (offset_x2 + j) / (points_per_cluster);
1215                c_offset_2  = (offset_x2 + j) % (points_per_cluster);
1216                d2_r        = x[c_id_2][2*c_offset_2];
1217                d2_c        = x[c_id_2][2*c_offset_2+1];
1218
[574]1219#if (DEBUG_ROW & 1)
[469]1220printf("\n ### d1_in = (%f , %f) / d2_in = (%f , %f) / coef = (%f , %f)\n", 
1221                d1_r , d1_c , d2_r , d2_c , omega_r , omega_c);
1222#endif
1223                // tau = omega * d[x2]
1224                tau_r = omega_r * d2_r - omega_c * d2_c;
1225                tau_c = omega_r * d2_c + omega_c * d2_r;
1226
1227                // set new value for d[x1] = d[x1] + omega * d[x2]
1228                x[c_id_1][2*c_offset_1]   = d1_r + tau_r;
1229                x[c_id_1][2*c_offset_1+1] = d1_c + tau_c;
1230
1231                // set new value for d[x2] = d[x1] - omega * d[x2]
1232                x[c_id_2][2*c_offset_2]   = d1_r - tau_r;
1233                x[c_id_2][2*c_offset_2+1] = d1_c - tau_c;
1234
[574]1235#if (DEBUG_ROW & 1)
[469]1236printf("\n ### d1_out = (%f , %f) / d2_out = (%f , %f)\n", 
1237                d1_r + tau_r , d1_c + tau_c , d2_r - tau_r , d2_c - tau_c );
1238#endif
1239            }
1240        }
1241    }
1242
[574]1243#if DEBUG_ROW
[628]1244printf("\n[fft] ROW data out / %d points / offset = %d\n", rootN , offset_x );
[469]1245for ( p = 0 ; p < rootN ; p++ )
1246{
[473]1247    unsigned int index    = offset_x + p;
1248    unsigned int c_id     = index / (points_per_cluster);
1249    unsigned int c_offset = index % (points_per_cluster);
[469]1250    printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1251}
1252printf("\n");
1253#endif
1254
[574]1255}  // end FFTRow()
[469]1256
[473]1257///////////////////////////////////////
1258void PrintArray( double       ** array,
1259                 unsigned int    size ) 
[469]1260{
[473]1261    unsigned int  i;
1262    unsigned int  c_id;
1263    unsigned int  c_offset;
[469]1264
1265    // float display
1266    for (i = 0; i < size ; i++) 
1267    {
1268        c_id      = i / (points_per_cluster);
1269        c_offset  = i % (points_per_cluster);
1270
1271        printf(" %f  %f |", array[c_id][2*c_offset], array[c_id][2*c_offset+1]);
1272
1273        if ( (i+1) % 4 == 0)  printf("\n");
1274    }
1275    printf("\n");
1276}
1277
1278
1279// Local Variables:
1280// tab-width: 4
1281// c-basic-offset: 4
1282// c-file-offsets:((innamespace . 0)(inline-open . 0))
1283// indent-tabs-mode: nil
1284// End:
1285
1286// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1287
Note: See TracBrowser for help on using the repository browser.