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

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

Introduce the non-standard pthread_parallel_create() system call
and re-write the <fft> and <sort> applications to improve the
intrinsic paralelism in applications.

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