source: trunk/user/fft/fft.c

Last change on this file was 659, checked in by alain, 6 years ago

euh...

File size: 54.3 KB
Line 
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.
25// The N input data points can 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//
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// The number of threads cannot be larger than the number of rows.
34//
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.
43//
44// Each working thread allocates also a private coefs[rootN-1] buffer,
45// that contains all coefs required for a rootN points FFT.
46//
47// The actual number of cores and cluster in a given hardware architecture
48// is obtained by the get_config() syscall (x_size, y_size, ncores).
49// The max number of clusters is bounded by (X_MAX * Y_MAX).
50// The max number of cores per cluster is bounded by CORES_MAX.
51//
52// The number N of working threads is always defined by the number of cores availables
53// in the architecture, but this application supports three placement modes.
54// In all modes, the working threads are identified by the [tid] continuous index
55// in range [0, NTHREADS-1], and defines how the lines are shared amongst the threads.
56// This continuous index can always be decomposed in two continuous sub-indexes:
57// tid == cid * ncores + lid, where cid is in [0,NCLUSTERS-1] and lid in [0,NCORES-1].
58//
59// - NO_PLACEMENT: the main thread is itsef a working thread. The (N_1) other working
60// threads are created by the main thread, but the placement is done by the OS, using
61// the DQDT for load balancing, and two working threads can be placed on the same core.
62// The [cid,lid] are only abstract identifiers, and cannot be associated to a physical
63// cluster or a physical core. In this mode, the main thread run on any cluster,
64// but has tid = 0 (i.e. cid = 0 & tid = 0).
65//
66// - EXPLICIT_PLACEMENT: the main thread is again a working thread, but the placement of
67// of the threads on the cores is explicitely controled by the main thread to have
68// exactly one working thread per core, and the [cxy][lpid] core coordinates for a given
69// thread[tid] can be directly derived from the [tid] value: [cid] is an alias for the
70// physical cluster identifier, and [lid] is the local core index.
71//
72// - PARALLEL_PLACEMENT: the main thread is not anymore a working thread, and uses the
73// non standard pthread_parallel_create() function to avoid the costly sequencial
74// loops for pthread_create() and pthread_join(). It garanty one working thread
75// per core, and the same relation between the thread[tid] and the core[cxy][lpid].
76//
77// Several others configuration parameters can be defined below:
78// - USE_DQT_BARRIER : use a hierarchical barrier for working threads synchro
79// - PRINT_ARRAY : Print out complex data points arrays.
80// - CHECK : Perform both FFT and inverse FFT to check output/input.
81// - DEBUG_MAIN : Display intermediate results in main()
82// - DEBUG_FFT1D : Display intermediate results in FFT1D()
83// - DEBUG_ROW : Display intermedite results in FFTrow()
84//
85// Regarding final instrumentation:
86// - the sequencial initialisation time (init_time) is computed
87// by the main thread in the main() function.
88// - The parallel execution time (parallel_time[i]) is computed by each
89// working thread(i) in the work() function.
90// - The synchronisation time related to the barriers (sync_time[i])
91// is computed by each thread(i) in the work() function.
92// The results are displayed on the TXT terminal, and registered on disk.
93///////////////////////////////////////////////////////////////////////////////////////
94
95#include <math.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include <fcntl.h>
99#include <unistd.h>
100#include <pthread.h>
101#include <almosmkh.h>
102#include <hal_macros.h>
103
104// constants
105
106#define PI 3.14159265359
107#define PAGE_SIZE 4096
108#define X_MAX 16 // max number of clusters in a row
109#define Y_MAX 16 // max number of clusters in a column
110#define CORES_MAX 4 // max number of cores in a cluster
111#define CLUSTERS_MAX X_MAX * Y_MAX
112#define THREADS_MAX CLUSTERS_MAX * CORES_MAX
113#define RANDOM 0
114#define COSIN 1
115#define CONSTANT 2
116
117// parameters
118
119#define NO_PLACEMENT 1
120#define EXPLICIT_PLACEMENT 0
121#define PARALLEL_PLACEMENT 0
122
123#define DEFAULT_M 18 // 256 K complex points
124#define USE_DQT_BARRIER 1 // use DDT barrier if non zero
125#define MODE COSIN // DATA array initialisation mode
126#define CHECK 0
127#define DEBUG_MAIN 1 // trace main() function (detailed if odd)
128#define DEBUG_WORK 0 // trace work() function (detailed if odd)
129#define DEBUG_FFT1D 0 // trace FFT1D() function (detailed if odd)
130#define DEBUG_ROW 0 // trace FFTRow() function (detailed if odd)
131#define PRINT_ARRAY 0
132#define DISPLAY_SCHED_AND_VMM 0 // display final VMM state in all clusters
133
134// macro to swap two variables
135#define SWAP(a,b) { double tmp; tmp = a; a = b; b = tmp; }
136
137/////////////////////////////////////////////////////////////////////////////////////
138// FFT global variables
139/////////////////////////////////////////////////////////////////////////////////////
140
141unsigned int x_size; // platform global parameter
142unsigned int y_size; // platform global parameter
143unsigned int ncores; // platform global parameter
144
145unsigned int nthreads; // total number of threads (one thread per core)
146unsigned int nclusters; // total number of clusters
147unsigned int M = DEFAULT_M; // log2(number of points)
148unsigned int N; // number of points (N = 2^M)
149unsigned int rootN; // rootN = 2^M/2
150unsigned int rows_per_thread; // number of data "rows" handled by a single thread
151unsigned int points_per_cluster; // number of data points per cluster
152
153// arrays of pointers on distributed buffers (one sub-buffer per cluster)
154double * data[CLUSTERS_MAX]; // original time-domain data
155double * trans[CLUSTERS_MAX]; // used as auxiliary space for fft
156double * twid[CLUSTERS_MAX]; // twiddle factor : exp(-2iPI*k*n/N)
157double * bloup[CLUSTERS_MAX]; // used as auxiliary space for DFT
158
159// instrumentation counters
160unsigned int pgfault_nr[THREADS_MAX]; // total number of page faults (per thread)
161unsigned int pgfault_cost[THREADS_MAX]; // total page faults cost (per thread)
162unsigned int pgfault_max[THREADS_MAX]; // max page faults cost (per thread)
163unsigned int parallel_time[THREADS_MAX]; // total computation time (per thread)
164unsigned int sync_time[THREADS_MAX]; // cumulated waiting time in barriers (per thread)
165unsigned int init_time; // initialisation time (in main)
166
167// synchronisation barrier (all threads)
168pthread_barrier_t barrier;
169pthread_barrierattr_t barrier_attr;
170
171//return values at thread exit
172unsigned int THREAD_EXIT_SUCCESS = 0;
173unsigned int THREAD_EXIT_FAILURE = 1;
174
175// main thread continuous index
176unsigned int tid_main;
177
178// array of kernel thread identifiers / indexed by [tid]
179pthread_t work_trdid[CLUSTERS_MAX * CORES_MAX];
180
181// array of thread attributes / indexed by [tid]
182pthread_attr_t work_attr[CLUSTERS_MAX * CORES_MAX];
183
184// array of work function arguments / indexed by [tid]
185pthread_parallel_work_args_t work_args[CLUSTERS_MAX * CORES_MAX];
186
187/////////////////////////////////////////////////////////////////////////////////////
188// functions declaration
189/////////////////////////////////////////////////////////////////////////////////////
190
191void * work( void * args );
192
193double CheckSum( void );
194
195void InitD( double ** data ,
196 unsigned int mode,
197 unsigned int tid );
198
199void InitT( double ** twid,
200 unsigned int tid );
201
202void InitU( double * coefs );
203
204unsigned int BitReverse( unsigned int k );
205
206void FFT1D( int direction,
207 double ** x,
208 double ** tmp,
209 double * upriv,
210 double ** twid,
211 unsigned int tid,
212 unsigned int MyFirst,
213 unsigned int MyLast );
214
215void TwiddleOneCol( int direction,
216 unsigned int j,
217 double ** u,
218 double ** x,
219 unsigned int offset_x );
220
221void Scale( double ** x,
222 unsigned int offset_x );
223
224void Transpose( double ** src,
225 double ** dest,
226 unsigned int MyFirst,
227 unsigned int MyLast );
228
229void Copy( double ** src,
230 double ** dest,
231 unsigned int MyFirst,
232 unsigned int MyLast );
233
234void Reverse( double ** x,
235 unsigned int offset_x );
236
237void FFTRow( int direction,
238 double * u,
239 double ** x,
240 unsigned int offset_x );
241
242void PrintArray( double ** x,
243 unsigned int size );
244
245void SimpleDft( int direction,
246 unsigned int size,
247 double ** src,
248 unsigned int src_offset,
249 double ** dst,
250 unsigned int dst_offset );
251
252///////////////////////////////////////////////////////////////////
253// This main() function execute the sequencial initialisation
254// launch the parallel execution, and makes the instrumentation.
255///////////////////////////////////////////////////////////////////
256int main ( void )
257{
258 int error;
259
260 unsigned int tid; // continuous thread index
261
262 char name[64]; // instrumentation file name
263 char path[128]; // instrumentation path name
264 char string[256];
265 int ret;
266
267 unsigned long long start_init_cycle;
268 unsigned long long end_init_cycle;
269
270#if DEBUG_MAIN
271 unsigned long long debug_cycle;
272#endif
273
274#if CHECK
275 double ck1; // for input/output checking
276 double ck3; // for input/output checking
277#endif
278
279 int pid = getpid();
280
281 // check placement mode
282 if( (NO_PLACEMENT + EXPLICIT_PLACEMENT + PARALLEL_PLACEMENT) != 1 )
283 {
284 printf("\n[fft error] illegal placement mode\n");
285 exit( 0 );
286 }
287
288 // get FFT application start cycle
289 get_cycle( &start_init_cycle );
290
291 // get platform parameters
292 hard_config_t config;
293 if( get_config( &config ) )
294 {
295 printf("\n[fft error] cannot get hardware configuration\n");
296 exit( 0 );
297 }
298
299 x_size = config.x_size;
300 y_size = config.y_size;
301 ncores = config.ncores;
302
303 // check ncores
304 if( (ncores != 1) && (ncores != 2) && (ncores != 4) )
305 {
306 printf("\n[fft error] number of cores per cluster must be 1/2/4\n");
307 exit( 0 );
308 }
309
310 // check x_size
311 if( (x_size != 1) && (x_size != 2) && (x_size != 4) && (x_size != 8) && (x_size != 16) )
312 {
313 printf("\n[fft error] x_size must be 1/2/4/8/16\n");
314 exit( 0 );
315 }
316
317 // check y_size
318 if( (y_size != 1) && (y_size != 2) && (y_size != 4) && (y_size != 8) && (y_size != 16) )
319 {
320 printf("\n[fft error] y_size must be 1/2/4/8/16\n");
321 exit( 0 );
322 }
323
324 // get identifiers for core executing main
325 unsigned int cxy_main;
326 unsigned int lid_main;
327 get_core_id( &cxy_main , &lid_main );
328
329 // compute nthreads and nclusters
330 nthreads = x_size * y_size * ncores;
331 nclusters = x_size * y_size;
332
333 // compute covering DQT size an level
334 unsigned int z = (x_size > y_size) ? x_size : y_size;
335 unsigned int root_level = (z == 1) ? 0 : (z == 2) ? 1 : (z == 4) ? 2 : (z == 8) ? 3 : 4;
336
337 // compute various constants depending on N and T
338 N = 1 << M;
339 rootN = 1 << (M / 2);
340 rows_per_thread = rootN / nthreads;
341 points_per_cluster = N / nclusters;
342
343 // check N versus T
344 if( rootN < nthreads )
345 {
346 printf("\n[fft error] sqrt(N) must be larger than T\n");
347 exit( 0 );
348 }
349
350 // define instrumentation file name
351 if( NO_PLACEMENT )
352 {
353 printf("\n[fft] starts / %d points / %d thread(s) / PID %x / NO_PLACE\n",
354 N, nthreads, pid );
355
356 // build instrumentation file name
357 if( USE_DQT_BARRIER )
358 snprintf( name , 64 , "fft_dqt_no_place_%d_%d_%d", M , x_size * y_size , ncores );
359 else
360 snprintf( name , 64 , "fft_smp_no_place_%d_%d_%d", M , x_size * y_size , ncores );
361 }
362
363 if( EXPLICIT_PLACEMENT )
364 {
365 printf("\n[fft] starts / %d points / %d thread(s) / PID %x / EXPLICIT\n",
366 N, nthreads, pid );
367
368 // build instrumentation file name
369 if( USE_DQT_BARRIER )
370 snprintf( name , 64 , "fft_dqt_explicit_%d_%d_%d", M , x_size * y_size , ncores );
371 else
372 snprintf( name , 64 , "fft_smp_explicit_%d_%d_%d", M , x_size * y_size , ncores );
373 }
374
375 if( PARALLEL_PLACEMENT )
376 {
377 printf("\n[fft] starts / %d points / %d thread(s) / PID %x / PARALLEL\n",
378 N, nthreads, pid );
379
380 // build instrumentation file name
381 if( USE_DQT_BARRIER )
382 snprintf( name , 64 , "fft_dqt_parallel_%d_%d_%d", M , x_size * y_size , ncores );
383 else
384 snprintf( name , 64 , "fft_smp_parallel_%d_%d_%d", M , x_size * y_size , ncores );
385 }
386
387 // build instrumentation file pathname
388 snprintf( path , 128 , "/home/%s", name );
389
390 // open instrumentation file
391 FILE * f = fopen( path , NULL );
392 if ( f == NULL )
393 {
394 printf("\n[fft error] cannot open instrumentation file <%s>\n", path );
395 exit( 0 );
396 }
397
398#if DEBUG_MAIN
399get_cycle( &debug_cycle );
400printf("\n[fft] main open instrumentation file <%s> at cycle %d\n",
401path, (unsigned int)debug_cycle );
402#endif
403
404#if CHECK
405ck1 = CheckSum();
406#endif
407
408#if PRINT_ARRAY
409printf("\nData values / base = %x\n", &data[0][0] );
410PrintArray( data , N );
411
412printf("\nTwiddle values / base = %x\n", &twid[0][0] );
413PrintArray( twid , N );
414
415SimpleDft( 1 , N , data , 0 , bloup , 0 );
416
417printf("\nExpected results / base = %x\n", &bloup[0][0] );
418PrintArray( bloup , N );
419#endif
420
421 // initialise barrier synchronizing all <work> threads
422 if( USE_DQT_BARRIER )
423 {
424 barrier_attr.x_size = x_size;
425 barrier_attr.y_size = y_size;
426 barrier_attr.nthreads = ncores;
427 error = pthread_barrier_init( &barrier, &barrier_attr , nthreads );
428 }
429 else
430 {
431 error = pthread_barrier_init( &barrier, NULL , nthreads );
432 }
433
434 if( error )
435 {
436 printf("\n[fft error] cannot initialize barrier\n");
437 exit( 0 );
438 }
439
440#if DEBUG_MAIN
441get_cycle( &debug_cycle );
442printf("\n[fft] main completes sequencial initialisation at cycle %d\n",
443(unsigned int)debug_cycle );
444#endif
445
446 // register sequencial time
447 get_cycle( &end_init_cycle );
448 init_time = (unsigned int)(end_init_cycle - start_init_cycle);
449
450 //////////////////
451 if( NO_PLACEMENT )
452 {
453 // the tid value for the main thread is always 0
454 // main thread creates new threads with tid in [1,nthreads-1]
455 unsigned int tid;
456 for ( tid = 0 ; tid < nthreads ; tid++ )
457 {
458 // register tid value in work_args[tid] array
459 work_args[tid].tid = tid;
460
461 // create other threads
462 if( tid > 0 )
463 {
464 if ( pthread_create( &work_trdid[tid],
465 NULL, // no attribute
466 &work,
467 &work_args[tid] ) )
468 {
469 printf("\n[fft error] cannot create thread %d\n", tid );
470 exit( 0 );
471 }
472
473#if DEBUG_MAIN
474printf("\n[fft] main created thread %d\n", tid );
475#endif
476
477 }
478 else
479 {
480 tid_main = 0;
481 }
482 } // end for tid
483
484 // main thread calls itself the execute() function
485 work( &work_args[0] );
486
487 // main thread wait other threads completion
488 for ( tid = 1 ; tid < nthreads ; tid++ )
489 {
490 unsigned int * status;
491
492 // main wait thread[tid] status
493 if ( pthread_join( work_trdid[tid], (void*)(&status)) )
494 {
495 printf("\n[fft error] main cannot join thread %d\n", tid );
496 exit( 0 );
497 }
498
499 // check status
500 if( *status != THREAD_EXIT_SUCCESS )
501 {
502 printf("\n[fft error] thread %x returned failure\n", tid );
503 exit( 0 );
504 }
505
506#if DEBUG_MAIN
507printf("\n[fft] main successfully joined thread %x\n", tid );
508#endif
509
510 } // end for tid
511
512 } // end if no_placement
513
514 ////////////////////////
515 if( EXPLICIT_PLACEMENT )
516 {
517 // main thread places each thread[tid] on a specific core[cxy][lid]
518 // but the actual thread creation is sequencial
519 unsigned int x;
520 unsigned int y;
521 unsigned int l;
522 unsigned int cxy; // cluster identifier
523 unsigned int tid; // thread continuous index
524
525 for( x = 0 ; x < x_size ; x++ )
526 {
527 for( y = 0 ; y < y_size ; y++ )
528 {
529 cxy = HAL_CXY_FROM_XY( x , y );
530 for( l = 0 ; l < ncores ; l++ )
531 {
532 // compute thread continuous index
533 tid = (((x * y_size) + y) * ncores) + l;
534
535 // register tid value in work_args[tid] array
536 work_args[tid].tid = tid;
537
538 // no thread created on the core running the main
539 if( (cxy != cxy_main) || (l != lid_main) )
540 {
541 // define thread attributes
542 work_attr[tid].attributes = PT_ATTR_CLUSTER_DEFINED |
543 PT_ATTR_CORE_DEFINED;
544 work_attr[tid].cxy = cxy;
545 work_attr[tid].lid = l;
546
547 // create thread[tid] on core[cxy][l]
548 if ( pthread_create( &work_trdid[tid],
549 &work_attr[tid],
550 &work,
551 &work_args[tid] ) )
552 {
553 printf("\n[fft error] cannot create thread %d\n", tid );
554 exit( 0 );
555 }
556#if DEBUG_MAIN
557printf("\n[fft] main created thread[%d] on core[%x,%d]\n", tid, cxy, l );
558#endif
559 }
560 else
561 {
562 tid_main = tid;
563 }
564 }
565 }
566 }
567
568 // main thread calls itself the execute() function
569 work( &work_args[tid_main] );
570
571 // main thread wait other threads completion
572 for( tid = 0 ; tid < nthreads ; tid++ )
573 {
574 // no other thread on the core running the main
575 if( tid != tid_main )
576 {
577 unsigned int * status;
578
579 // wait thread[tid]
580 if( pthread_join( work_trdid[tid] , (void*)(&status) ) )
581 {
582 printf("\n[fft error] main cannot join thread %d\n", tid );
583 exit( 0 );
584 }
585
586 // check status
587 if( *status != THREAD_EXIT_SUCCESS )
588 {
589 printf("\n[fft error] thread %d returned failure\n", tid );
590 exit( 0 );
591 }
592#if DEBUG_MAIN
593printf("\n[fft] main joined thread %d on core[%x,%d]\n", tid , cxy , l );
594#endif
595 }
596 }
597 } // end if explicit_placement
598
599 ////////////////////////
600 if( PARALLEL_PLACEMENT )
601 {
602 // create and execute the working threads
603 if( pthread_parallel_create( root_level , &work ) )
604 {
605 printf("\n[fft error] cannot create threads\n");
606 exit( 0 );
607 }
608 }
609
610#if DEBUG_MAIN
611get_cycle( &debug_cycle );
612printf("\n[fft] main resume for instrumentation at cycle %d\n",
613(unsigned int)debug_cycle) ;
614#endif
615
616#if PRINT_ARRAY
617printf("\nData values after FFT:\n");
618PrintArray( data , N );
619#endif
620
621#if CHECK
622ck3 = CheckSum();
623printf("\n*** Results ***\n");
624printf("Checksum difference is %f (%f, %f)\n", ck1 - ck3, ck1, ck3);
625if (fabs(ck1 - ck3) < 0.001) printf("Results OK\n");
626else printf("Results KO\n");
627#endif
628
629 // display header on terminal, and save to file
630 printf("\n----- %s -----\n", name );
631
632 ret = fprintf( f , "\n----- %s -----\n", name );
633 if( ret < 0 )
634 {
635 printf("\n[fft error] cannot write header to file <%s>\n", path );
636 exit(0);
637 }
638
639 // initializes global (all threads) instrumentation values
640 unsigned int time_para = parallel_time[0];
641 unsigned int time_sync = sync_time[0];
642 unsigned int pgfaults_nr = 0;
643 unsigned int pgfaults_cost = 0;
644 unsigned int pgfaults_max = pgfault_max[0];
645
646 // loop on threads to compute global instrumentation results
647 for (tid = 0 ; tid < nthreads ; tid++)
648 {
649 snprintf( string , 256 ,
650 "- tid %d : Seq %d / Para %d / Sync %d / Pgfaults %d ( cost %d / max %d )\n",
651 tid, init_time, parallel_time[tid], sync_time[tid],
652 pgfault_nr[tid], (pgfault_cost[tid] / pgfault_nr[tid]) , pgfault_max[tid] );
653
654 // save to instrumentation file
655 fprintf( f , "%s" , string );
656 if( ret < 0 )
657 {
658 printf("\n[fft error] cannot save thread %d results to file <%s>\n", tid, path );
659 printf("%s", string );
660 exit(0);
661 }
662
663 // compute global values
664 if (parallel_time[tid] > time_para) time_para = parallel_time[tid];
665 if (sync_time[tid] > time_sync) time_sync = sync_time[tid];
666
667 pgfaults_nr += pgfault_nr[tid];
668 pgfaults_cost += pgfault_cost[tid];
669
670 if (pgfault_max[tid] > pgfaults_max) pgfaults_max = pgfault_max[tid];
671 }
672
673 // display global values on terminal and save to file
674 snprintf( string , 256 ,
675 "\nSeq %d / Para %d / Sync %d / Pgfaults %d ( cost %d / max %d )\n",
676 init_time, time_para, time_sync, pgfaults_nr, (pgfaults_cost / pgfaults_nr), pgfaults_max );
677
678 printf("%s", string );
679
680 // save global values to file
681 ret = fprintf( f , "%s", string );
682
683 if( ret < 0 )
684 {
685 printf("\n[fft error] cannot save global results to file <%s>\n", path );
686 exit(0);
687 }
688
689 // close instrumentation file
690 ret = fclose( f );
691
692 if( ret < 0 )
693 {
694 printf("\n[fft error] cannot close file <%s>\n", path );
695 exit(0);
696 }
697
698#if DEBUG_MAIN
699get_cycle( &debug_cycle );
700printf("\n[fft] main exit <%s> at cycle %d\n",
701path, (unsigned int)debug_cycle );
702#endif
703
704 exit( 0 );
705
706 return 0;
707
708} // end main()
709
710/////////////////////////////////////////////////////////////////
711// This function is executed in parallel by all <work> threads.
712/////////////////////////////////////////////////////////////////
713void * work( void * arguments )
714{
715 unsigned int tid; // this thread continuous index
716 unsigned int lid; // core local index
717 unsigned int cid; // cluster continuous index
718
719 unsigned int MyFirst; // index first row allocated to thread
720 unsigned int MyLast; // index last row allocated to thread
721 double * upriv; // private array of FFT coefs
722
723 unsigned long long parallel_start;
724 unsigned long long parallel_stop;
725 unsigned long long barrier_start;
726 unsigned long long barrier_stop;
727
728 get_cycle( &parallel_start );
729
730 // get thread arguments
731 pthread_parallel_work_args_t * args = (pthread_parallel_work_args_t *)arguments;
732
733 tid = args->tid;
734 pthread_barrier_t * parent_barrier = args->barrier;
735
736 // compute lid and cid from tid
737 lid = tid % ncores;
738 cid = tid / ncores;
739
740#if DEBUG_WORK
741printf("\n[fft] %s : thread %d enter / cycle %d\n",
742__FUNCTION__, tid, (unsigned int)parallel_start );
743#endif
744
745 // thread on core 0 allocates memory from the local cluster
746 // for the distributed data[], trans[], twid[] buffers
747 if( lid == 0 )
748 {
749 unsigned int data_size = (N / nclusters) * 2 * sizeof(double);
750
751 data[cid] = (double *)malloc( data_size );
752 if( data[cid] == NULL )
753 {
754 printf("\n[fft_error] in work : cannot allocate data[%d] buffer\n", cid );
755 pthread_barrier_wait( parent_barrier );
756 pthread_exit( NULL );
757 }
758
759 trans[cid] = (double *)malloc( data_size );
760 if( trans[cid] == NULL )
761 {
762 printf("\n[fft_error] in work : cannot allocate trans[%d] buffer\n", cid );
763 pthread_barrier_wait( parent_barrier );
764 pthread_exit( NULL );
765 }
766
767 twid[cid] = (double *)malloc( data_size );
768 if( twid[cid] == NULL )
769 {
770 printf("\n[fft_error] in work : cannot allocate twid[%d] buffer\n", cid );
771 pthread_barrier_wait( parent_barrier );
772 pthread_exit( NULL );
773 }
774 }
775
776 // BARRIER to wait distributed buffers allocation
777 get_cycle( &barrier_start );
778 pthread_barrier_wait( &barrier );
779 get_cycle( &barrier_stop );
780 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
781
782#if DEBUG_WORK
783printf("\n[fft] %s : thread %d exit barrier for buffer allocation / cycle %d\n",
784__FUNCTION__, tid, (unsigned int)barrier_stop );
785#endif
786
787 // all threads contribute to data[] local array initialisation
788 InitD( data , MODE , tid );
789
790 // all threads contribute to data[] local array initialisation
791 InitT( twid , tid );
792
793 // BARRIER to wait distributed buffers initialisation
794 get_cycle( &barrier_start );
795 pthread_barrier_wait( &barrier );
796 get_cycle( &barrier_stop );
797 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
798
799#if DEBUG_WORK
800printf("\n[fft] %s : thread %d exit barrier for buffer initialisation / cycle %d\n",
801__FUNCTION__, tid, (unsigned int)barrier_stop );
802#endif
803
804 // all threads allocate memory from the local cluster
805 // for the private upriv[] buffer
806 upriv = (double *)malloc( (rootN - 1) * 2 * sizeof(double) );
807 if( upriv == NULL )
808 {
809 printf("\n[fft_error] in work : cannot allocate trans[%d] buffer\n", cid );
810 pthread_barrier_wait( parent_barrier );
811 pthread_exit( NULL );
812 }
813
814 // all threads initialise the private upriv[] array
815 InitU( upriv );
816
817 // all threads compute first and last rows handled by the thread
818 MyFirst = rootN * tid / nthreads;
819 MyLast = rootN * (tid + 1) / nthreads;
820
821 // all threads perform forward FFT
822 FFT1D( 1 , data , trans , upriv , twid , tid , MyFirst , MyLast );
823
824#if CHECK
825get_cycle( &barrier_start );
826pthread_barrier_wait( &barrier );
827get_cycle( &barrier_stop );
828sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
829FFT1D( -1 , data , trans , upriv , twid , tid , MyFirst , MyLast );
830#endif
831
832 get_cycle( &parallel_stop );
833
834 // register parallel time in instrumentation counters
835 parallel_time[tid] = (unsigned int)(parallel_stop - parallel_start);
836
837 // get work thread info for page faults
838 thread_info_t info;
839 get_thread_info( &info );
840
841 // register page faults in instrumentation counters
842 pgfault_nr[tid] = info.false_pgfault_nr +
843 info.local_pgfault_nr +
844 info.global_pgfault_nr;
845 pgfault_cost[tid] = info.false_pgfault_cost +
846 info.local_pgfault_cost +
847 info.global_pgfault_cost;
848 pgfault_max[tid] = info.false_pgfault_max +
849 info.local_pgfault_max +
850 info.global_pgfault_max;
851#if DEBUG_WORK
852printf("\n[fft] %s : thread %d completes fft / p_start %d / p_stop %d\n",
853__FUNCTION__, tid, (unsigned int)parallel_start, (unsigned int)parallel_stop );
854#endif
855
856 // work thread signals completion to main
857 pthread_barrier_wait( parent_barrier );
858
859#if DEBUG_WORK
860printf("\n[fft] %s : thread %d exit\n",
861__FUNCTION__, tid );
862#endif
863
864#if DISPLAY_SCHED_AND_VMM
865printf("\n[fft] %s : thread %d exit\n", __FUNCTION__, tid );
866if( lid == 0 ) display_vmm( cxy , getpid() , 0 );
867#endif
868
869 // work thread exit
870 pthread_exit( NULL );
871
872 return NULL;
873
874} // end work()
875
876////////////////////////////////////////////////////////////////////////////////////////
877// This function makes the DFT from the src[nclusters][points_per_cluster] distributed
878// buffer, to the dst[nclusters][points_per_cluster] distributed buffer.
879////////////////////////////////////////////////////////////////////////////////////////
880void SimpleDft( int direction, // 1 direct / -1 reverse
881 unsigned int size, // number of points
882 double ** src, // source distributed buffer
883 unsigned int src_offset, // offset in source array
884 double ** dst, // destination distributed buffer
885 unsigned int dst_offset ) // offset in destination array
886{
887 unsigned int n , k;
888 double phi; // 2*PI*n*k/N
889 double u_r; // cos( phi )
890 double u_c; // sin( phi )
891 double d_r; // Re(data[n])
892 double d_c; // Im(data[n])
893 double accu_r; // Re(accu)
894 double accu_c; // Im(accu)
895 unsigned int c_id; // distributed buffer cluster index
896 unsigned int c_offset; // offset in distributed buffer
897
898 for ( k = 0 ; k < size ; k++ ) // loop on the output data points
899 {
900 // initialise accu
901 accu_r = 0;
902 accu_c = 0;
903
904 for ( n = 0 ; n < size ; n++ ) // loop on the input data points
905 {
906 // compute coef
907 phi = (double)(2*PI*n*k) / size;
908 u_r = cos( phi );
909 u_c = -sin( phi ) * direction;
910
911 // get input data point
912 c_id = (src_offset + n) / (points_per_cluster);
913 c_offset = (src_offset + n) % (points_per_cluster);
914 d_r = src[c_id][2*c_offset];
915 d_c = src[c_id][2*c_offset+1];
916
917 // increment accu
918 accu_r += ((u_r*d_r) - (u_c*d_c));
919 accu_c += ((u_r*d_c) + (u_c*d_r));
920 }
921
922 // scale for inverse DFT
923 if ( direction == -1 )
924 {
925 accu_r /= size;
926 accu_c /= size;
927 }
928
929 // set output data point
930 c_id = (dst_offset + k) / (points_per_cluster);
931 c_offset = (dst_offset + k) % (points_per_cluster);
932 dst[c_id][2*c_offset] = accu_r;
933 dst[c_id][2*c_offset+1] = accu_c;
934 }
935
936} // end SimpleDft()
937
938///////////////////////
939double CheckSum( void )
940{
941 unsigned int i , j;
942 unsigned int c_id;
943 unsigned int c_offset;
944 double cks;
945
946 cks = 0.0;
947 for (j = 0; j < rootN ; j++)
948 {
949 for (i = 0; i < rootN ; i++)
950 {
951 c_id = (rootN * j + i) / (points_per_cluster);
952 c_offset = (rootN * j + i) % (points_per_cluster);
953
954 cks += data[c_id][2*c_offset] + data[c_id][2*c_offset+1];
955 }
956 }
957 return(cks);
958}
959
960//////////////////////////////////////////////////////////////////////////////////////
961// Each working thread <tid> contributes to initialize (rootN / nthreads) rows,
962// in the shared - and distributed - <data> array.
963//////////////////////////////////////////////////////////////////////////////////////
964void InitD(double ** data,
965 unsigned int mode,
966 unsigned int tid )
967{
968 unsigned int i , j;
969 unsigned int c_id;
970 unsigned int c_offset;
971 unsigned int index;
972
973 // compute row_min and row_max
974 unsigned int row_min = tid * rows_per_thread;
975 unsigned int row_max = row_min + rows_per_thread;
976
977 for ( j = row_min ; j < row_max ; j++ ) // loop on rows
978 {
979 for ( i = 0 ; i < rootN ; i++ ) // loop on points in a row
980 {
981 index = j * rootN + i;
982 c_id = index / (points_per_cluster);
983 c_offset = index % (points_per_cluster);
984
985 // complex input signal is random
986 if ( mode == RANDOM )
987 {
988 data[c_id][2*c_offset] = ( (double)rand() ) / 65536;
989 data[c_id][2*c_offset+1] = ( (double)rand() ) / 65536;
990 }
991
992
993 // complex input signal is cos(n/N) / sin(n/N)
994 if ( mode == COSIN )
995 {
996 double phi = (double)( 2 * PI * index) / N;
997 data[c_id][2*c_offset] = cos( phi );
998 data[c_id][2*c_offset+1] = sin( phi );
999 }
1000
1001 // complex input signal is constant
1002 if ( mode == CONSTANT )
1003 {
1004 data[c_id][2*c_offset] = 1.0;
1005 data[c_id][2*c_offset+1] = 0.0;
1006 }
1007 }
1008 }
1009}
1010
1011///////////////////////////////////////////////////////////////////////////////////////
1012// Each working thread <tid> contributes to initialize (rootN / nthreads) rows,
1013// in the shared - and distributed - <twiddle> array.
1014///////////////////////////////////////////////////////////////////////////////////////
1015void InitT( double ** twid,
1016 unsigned int tid )
1017{
1018 unsigned int i, j;
1019 unsigned int index;
1020 unsigned int c_id;
1021 unsigned int c_offset;
1022 double phi;
1023
1024 // compute row_min and row_max
1025 unsigned int row_min = tid * rows_per_thread;
1026 unsigned int row_max = row_min + rows_per_thread;
1027
1028 for ( j = row_min ; j < row_max ; j++ ) // loop on rows
1029 {
1030 for ( i = 0 ; i < rootN ; i++ ) // loop on points in a row
1031 {
1032 index = j * rootN + i;
1033 c_id = index / (points_per_cluster);
1034 c_offset = index % (points_per_cluster);
1035
1036 phi = (double)(2.0 * PI * i * j) / N;
1037 twid[c_id][2*c_offset] = cos( phi );
1038 twid[c_id][2*c_offset+1] = -sin( phi );
1039 }
1040 }
1041}
1042
1043///////////////////////////////////////////////////////////////////////////////////////
1044// Each working thread initialize the private <upriv> array / (rootN - 1) entries.
1045///////////////////////////////////////////////////////////////////////////////////////
1046void InitU( double * upriv )
1047{
1048 unsigned int q;
1049 unsigned int j;
1050 unsigned int base;
1051 unsigned int n1;
1052 double phi;
1053
1054 for (q = 0 ; ((unsigned int)(1 << q) < N) ; q++)
1055 {
1056 n1 = 1 << q; // n1 == 2**q
1057 base = n1 - 1;
1058 for (j = 0; (j < n1) ; j++)
1059 {
1060 if (base + j > rootN - 1) return;
1061
1062 phi = (double)(2.0 * PI * j) / (2 * n1);
1063 upriv[2*(base+j)] = cos( phi );
1064 upriv[2*(base+j)+1] = -sin( phi );
1065 }
1066 }
1067}
1068
1069////////////////////////////////////////////////////////////////////////////////////////
1070// This function returns an index value that is the bit reverse of the input value.
1071////////////////////////////////////////////////////////////////////////////////////////
1072unsigned int BitReverse( unsigned int k )
1073{
1074 unsigned int i;
1075 unsigned int j;
1076 unsigned int tmp;
1077
1078 j = 0;
1079 tmp = k;
1080 for (i = 0; i < M/2 ; i++)
1081 {
1082 j = 2 * j + (tmp & 0x1);
1083 tmp = tmp >> 1;
1084 }
1085 return j;
1086}
1087
1088////////////////////////////////////////////////////////////////////////////////////////
1089// This function perform the in place (direct or inverse) FFT on the N data points
1090// contained in the distributed buffers x[nclusters][points_per_cluster].
1091// It handles the (N) points 1D array as a (rootN*rootN) points 2D array.
1092// 1) it fft (rootN/nthreads ) rows from x to tmp.
1093// 2) it make (rootN/nthreads) FFT on the tmp rows and apply the twiddle factor.
1094// 3) it fft (rootN/nthreads) columns from tmp to x.
1095// 4) it make (rootN/nthreads) FFT on the x rows.
1096// It calls the FFTRow() 2*(rootN/nthreads) times to perform the in place FFT
1097// on the rootN points contained in a row.
1098////////////////////////////////////////////////////////////////////////////////////////
1099void FFT1D( int direction, // direct 1 / inverse -1
1100 double ** x, // input & output distributed data points array
1101 double ** tmp, // auxiliary distributed data points array
1102 double * upriv, // local array containing coefs for rootN FFT
1103 double ** twid, // distributed arrays containing N twiddle factors
1104 unsigned int tid, // thread continuous index
1105 unsigned int MyFirst,
1106 unsigned int MyLast )
1107{
1108 unsigned int j;
1109 unsigned long long barrier_start;
1110 unsigned long long barrier_stop;
1111
1112#if DEBUG_FFT1D
1113unsigned long long cycle;
1114get_cycle( &cycle );
1115printf("\n[fft] %s : thread %d enter / first %d / last %d / cycle %d\n",
1116__FUNCTION__, tid, MyFirst, MyLast, (unsigned int)cycle );
1117#endif
1118
1119 // fft (rootN/nthreads) rows from x to tmp
1120 Transpose( x , tmp , MyFirst , MyLast );
1121
1122#if( DEBUG_FFT1D & 1 )
1123get_cycle( &cycle );
1124printf("\n[fft] %s : thread %d after first fft / cycle %d\n",
1125__FUNCTION__, tid, (unsigned int)cycle );
1126if( PRINT_ARRAY ) PrintArray( tmp , N );
1127#endif
1128
1129 // BARRIER
1130 get_cycle( &barrier_start );
1131 pthread_barrier_wait( &barrier );
1132 get_cycle( &barrier_stop );
1133 sync_time[tid] = (unsigned int)(barrier_stop - barrier_start);
1134
1135#if( DEBUG_FFT1D & 1 )
1136get_cycle( &cycle );
1137printf("\n[fft] %s : thread %d exit barrier after first fft / cycle %d\n",
1138__FUNCTION__, tid, (unsigned int)cycle );
1139#endif
1140
1141 // do FFTs on rows of tmp (i.e. columns of x) and apply twiddle factor
1142 for (j = MyFirst; j < MyLast; j++)
1143 {
1144 FFTRow( direction , upriv , tmp , j * rootN );
1145
1146 TwiddleOneCol( direction , j , twid , tmp , j * rootN );
1147 }
1148
1149#if( DEBUG_FFT1D & 1 )
1150printf("\n[fft] %s : thread %d after first twiddle\n", __FUNCTION__, tid);
1151if( PRINT_ARRAY ) PrintArray( tmp , N );
1152#endif
1153
1154 // BARRIER
1155 get_cycle( &barrier_start );
1156 pthread_barrier_wait( &barrier );
1157 get_cycle( &barrier_stop );
1158
1159#if( DEBUG_FFT1D & 1 )
1160printf("\n[fft] %s : thread %d exit barrier after first twiddle\n", __FUNCTION__, tid);
1161#endif
1162
1163 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
1164
1165 // fft tmp to x
1166 Transpose( tmp , x , MyFirst , MyLast );
1167
1168#if( DEBUG_FFT1D & 1 )
1169printf("\n[fft] %s : thread %d after second fft\n", __FUNCTION__, tid);
1170if( PRINT_ARRAY ) PrintArray( x , N );
1171#endif
1172
1173 // BARRIER
1174 get_cycle( &barrier_start );
1175 pthread_barrier_wait( &barrier );
1176 get_cycle( &barrier_stop );
1177
1178#if( DEBUG_FFT1D & 1 )
1179printf("\n[fft] %s : thread %d exit barrier after second fft\n", __FUNCTION__, tid);
1180#endif
1181
1182 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
1183
1184 // do FFTs on rows of x and apply the scaling factor
1185 for (j = MyFirst; j < MyLast; j++)
1186 {
1187 FFTRow( direction , upriv , x , j * rootN );
1188 if (direction == -1) Scale( x , j * rootN );
1189 }
1190
1191#if( DEBUG_FFT1D & 1 )
1192printf("\n[fft] %s : thread %d after FFT on rows\n", __FUNCTION__, tid);
1193if( PRINT_ARRAY ) PrintArray( x , N );
1194#endif
1195
1196 // BARRIER
1197 get_cycle( &barrier_start );
1198 pthread_barrier_wait( &barrier );
1199 get_cycle( &barrier_stop );
1200
1201#if( DEBUG_FFT1D & 1 )
1202printf("\n[fft] %s : thread %d exit barrier after FFT on rows\n", __FUNCTION__, tid);
1203#endif
1204 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
1205
1206 // fft x to tmp
1207 Transpose( x , tmp , MyFirst , MyLast );
1208
1209#if( DEBUG_FFT1D & 1 )
1210printf("\n[fft] %s : thread %x after third fft\n", __FUNCTION__, tid);
1211if( PRINT_ARRAY ) PrintArray( x , N );
1212#endif
1213
1214 // BARRIER
1215 get_cycle( &barrier_start );
1216 pthread_barrier_wait( &barrier );
1217 get_cycle( &barrier_stop );
1218
1219#if( DEBUG_FFT1D & 1 )
1220printf("\n[fft] %s : thread %d exit barrier after third fft\n", __FUNCTION__, tid);
1221#endif
1222
1223 sync_time[tid] += (unsigned int)(barrier_stop - barrier_start);
1224 sync_time[tid] += (long)(barrier_stop - barrier_start);
1225
1226 // copy tmp to x
1227 Copy( tmp , x , MyFirst , MyLast );
1228
1229#if DEBUG_FFT1D
1230printf("\n[fft] %s : thread %d completed\n", __FUNCTION__, tid);
1231if( PRINT_ARRAY ) PrintArray( x , N );
1232#endif
1233
1234} // end FFT1D()
1235
1236/////////////////////////////////////////////////////////////////////////////////////
1237// This function multiply all points contained in a row (rootN points) of the
1238// x[] array by the corresponding twiddle factor, contained in the u[] array.
1239/////////////////////////////////////////////////////////////////////////////////////
1240void TwiddleOneCol( int direction,
1241 unsigned int j, // y coordinate in 2D view of coef array
1242 double ** u, // coef array base address
1243 double ** x, // data array base address
1244 unsigned int offset_x ) // first point in N points data array
1245{
1246 unsigned int i;
1247 double omega_r;
1248 double omega_c;
1249 double x_r;
1250 double x_c;
1251 unsigned int c_id;
1252 unsigned int c_offset;
1253
1254 for (i = 0; i < rootN ; i++) // loop on the rootN points
1255 {
1256 // get coef
1257 c_id = (j * rootN + i) / (points_per_cluster);
1258 c_offset = (j * rootN + i) % (points_per_cluster);
1259 omega_r = u[c_id][2*c_offset];
1260 omega_c = direction * u[c_id][2*c_offset+1];
1261
1262 // access data
1263 c_id = (offset_x + i) / (points_per_cluster);
1264 c_offset = (offset_x + i) % (points_per_cluster);
1265 x_r = x[c_id][2*c_offset];
1266 x_c = x[c_id][2*c_offset+1];
1267
1268 x[c_id][2*c_offset] = omega_r*x_r - omega_c * x_c;
1269 x[c_id][2*c_offset+1] = omega_r*x_c + omega_c * x_r;
1270 }
1271} // end TwiddleOneCol()
1272
1273////////////////////////////
1274void Scale( double ** x, // data array base address
1275 unsigned int offset_x ) // first point of the row to be scaled
1276{
1277 unsigned int i;
1278 unsigned int c_id;
1279 unsigned int c_offset;
1280
1281 for (i = 0; i < rootN ; i++)
1282 {
1283 c_id = (offset_x + i) / (points_per_cluster);
1284 c_offset = (offset_x + i) % (points_per_cluster);
1285 x[c_id][2*c_offset] /= N;
1286 x[c_id][2*c_offset + 1] /= N;
1287 }
1288}
1289
1290///////////////////////////////////
1291void Transpose( double ** src, // source buffer (array of pointers)
1292 double ** dest, // destination buffer (array of pointers)
1293 unsigned int MyFirst, // first row allocated to the thread
1294 unsigned int MyLast ) // last row allocated to the thread
1295{
1296 unsigned int row; // row index
1297 unsigned int point; // data point index in a row
1298
1299 unsigned int index_src; // absolute index in the source N points array
1300 unsigned int c_id_src; // cluster for the source buffer
1301 unsigned int c_offset_src; // offset in the source buffer
1302
1303 unsigned int index_dst; // absolute index in the dest N points array
1304 unsigned int c_id_dst; // cluster for the dest buffer
1305 unsigned int c_offset_dst; // offset in the dest buffer
1306
1307
1308 // scan all data points allocated to the thread
1309 // (between MyFirst row and MyLast row) from the source buffer
1310 // and write these points to the destination buffer
1311 for ( row = MyFirst ; row < MyLast ; row++ ) // loop on the rows
1312 {
1313 for ( point = 0 ; point < rootN ; point++ ) // loop on points in row
1314 {
1315 index_src = row * rootN + point;
1316 c_id_src = index_src / (points_per_cluster);
1317 c_offset_src = index_src % (points_per_cluster);
1318
1319 index_dst = point * rootN + row;
1320 c_id_dst = index_dst / (points_per_cluster);
1321 c_offset_dst = index_dst % (points_per_cluster);
1322
1323 dest[c_id_dst][2*c_offset_dst] = src[c_id_src][2*c_offset_src];
1324 dest[c_id_dst][2*c_offset_dst+1] = src[c_id_src][2*c_offset_src+1];
1325 }
1326 }
1327} // end Transpose()
1328
1329//////////////////////////////
1330void Copy( double ** src, // source buffer (array of pointers)
1331 double ** dest, // destination buffer (array of pointers)
1332 unsigned int MyFirst, // first row allocated to the thread
1333 unsigned int MyLast ) // last row allocated to the thread
1334{
1335 unsigned int row; // row index
1336 unsigned int point; // data point index in a row
1337
1338 unsigned int index; // absolute index in the N points array
1339 unsigned int c_id; // cluster index
1340 unsigned int c_offset; // offset in local buffer
1341
1342 // scan all data points allocated to the thread
1343 for ( row = MyFirst ; row < MyLast ; row++ ) // loop on the rows
1344 {
1345 for ( point = 0 ; point < rootN ; point++ ) // loop on points in row
1346 {
1347 index = row * rootN + point;
1348 c_id = index / (points_per_cluster);
1349 c_offset = index % (points_per_cluster);
1350
1351 dest[c_id][2*c_offset] = src[c_id][2*c_offset];
1352 dest[c_id][2*c_offset+1] = src[c_id][2*c_offset+1];
1353 }
1354 }
1355} // end Copy()
1356
1357///////////////////////////////
1358void Reverse( double ** x,
1359 unsigned int offset_x )
1360{
1361 unsigned int j, k;
1362 unsigned int c_id_j;
1363 unsigned int c_offset_j;
1364 unsigned int c_id_k;
1365 unsigned int c_offset_k;
1366
1367 for (k = 0 ; k < rootN ; k++)
1368 {
1369 j = BitReverse( k );
1370 if (j > k)
1371 {
1372 c_id_j = (offset_x + j) / (points_per_cluster);
1373 c_offset_j = (offset_x + j) % (points_per_cluster);
1374 c_id_k = (offset_x + k) / (points_per_cluster);
1375 c_offset_k = (offset_x + k) % (points_per_cluster);
1376
1377 SWAP(x[c_id_j][2*c_offset_j] , x[c_id_k][2*c_offset_k]);
1378 SWAP(x[c_id_j][2*c_offset_j+1], x[c_id_k][2*c_offset_k+1]);
1379 }
1380 }
1381}
1382
1383/////////////////////////////////////////////////////////////////////////////
1384// This function makes the in-place FFT on all points contained in a row
1385// (i.e. rootN points) of the x[nclusters][points_per_cluster] array.
1386/////////////////////////////////////////////////////////////////////////////
1387void FFTRow( int direction, // 1 direct / -1 inverse
1388 double * u, // private coefs array
1389 double ** x, // array of pointers on distributed buffers
1390 unsigned int offset_x ) // absolute offset in the x array
1391{
1392 unsigned int j;
1393 unsigned int k;
1394 unsigned int q;
1395 unsigned int L;
1396 unsigned int r;
1397 unsigned int Lstar;
1398 double * u1;
1399
1400 unsigned int offset_x1; // index first butterfly input
1401 unsigned int offset_x2; // index second butterfly output
1402
1403 double omega_r; // real part butterfy coef
1404 double omega_c; // complex part butterfly coef
1405
1406 double tau_r;
1407 double tau_c;
1408
1409 double d1_r; // real part first butterfly input
1410 double d1_c; // imag part first butterfly input
1411 double d2_r; // real part second butterfly input
1412 double d2_c; // imag part second butterfly input
1413
1414 unsigned int c_id_1; // cluster index for first butterfly input
1415 unsigned int c_offset_1; // offset for first butterfly input
1416 unsigned int c_id_2; // cluster index for second butterfly input
1417 unsigned int c_offset_2; // offset for second butterfly input
1418
1419#if DEBUG_ROW
1420unsigned int p;
1421printf("\n[fft] ROW data in / %d points / offset = %d\n", rootN , offset_x );
1422
1423for ( p = 0 ; p < rootN ; p++ )
1424{
1425 unsigned int index = offset_x + p;
1426 unsigned int c_id = index / (points_per_cluster);
1427 unsigned int c_offset = index % (points_per_cluster);
1428 printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1429}
1430printf("\n");
1431#endif
1432
1433 // This makes the rootN input points reordering
1434 Reverse( x , offset_x );
1435
1436#if DEBUG_ROW
1437printf("\n[fft] ROW data after reverse / %d points / offset = %d\n", rootN , offset_x );
1438
1439for ( p = 0 ; p < rootN ; p++ )
1440{
1441 unsigned int index = offset_x + p;
1442 unsigned int c_id = index / (points_per_cluster);
1443 unsigned int c_offset = index % (points_per_cluster);
1444 printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1445}
1446printf("\n");
1447#endif
1448
1449 // This implements the multi-stages, in place Butterfly network
1450 for (q = 1; q <= M/2 ; q++) // loop on stages
1451 {
1452 L = 1 << q; // number of points per subset for current stage
1453 r = rootN / L; // number of subsets
1454 Lstar = L / 2;
1455 u1 = &u[2 * (Lstar - 1)];
1456 for (k = 0; k < r; k++) // loop on the subsets
1457 {
1458 offset_x1 = offset_x + (k * L); // index first point
1459 offset_x2 = offset_x + (k * L + Lstar); // index second point
1460
1461#if (DEBUG_ROW & 1)
1462printf("\n ### q = %d / k = %d / x1 = %d / x2 = %d\n", q , k , offset_x1 , offset_x2 );
1463#endif
1464 // makes all in-place butterfly(s) for subset
1465 for (j = 0; j < Lstar; j++)
1466 {
1467 // get coef
1468 omega_r = u1[2*j];
1469 omega_c = direction * u1[2*j+1];
1470
1471 // get d[x1] address and value
1472 c_id_1 = (offset_x1 + j) / (points_per_cluster);
1473 c_offset_1 = (offset_x1 + j) % (points_per_cluster);
1474 d1_r = x[c_id_1][2*c_offset_1];
1475 d1_c = x[c_id_1][2*c_offset_1+1];
1476
1477 // get d[x2] address and value
1478 c_id_2 = (offset_x2 + j) / (points_per_cluster);
1479 c_offset_2 = (offset_x2 + j) % (points_per_cluster);
1480 d2_r = x[c_id_2][2*c_offset_2];
1481 d2_c = x[c_id_2][2*c_offset_2+1];
1482
1483#if (DEBUG_ROW & 1)
1484printf("\n ### d1_in = (%f , %f) / d2_in = (%f , %f) / coef = (%f , %f)\n",
1485 d1_r , d1_c , d2_r , d2_c , omega_r , omega_c);
1486#endif
1487 // tau = omega * d[x2]
1488 tau_r = omega_r * d2_r - omega_c * d2_c;
1489 tau_c = omega_r * d2_c + omega_c * d2_r;
1490
1491 // set new value for d[x1] = d[x1] + omega * d[x2]
1492 x[c_id_1][2*c_offset_1] = d1_r + tau_r;
1493 x[c_id_1][2*c_offset_1+1] = d1_c + tau_c;
1494
1495 // set new value for d[x2] = d[x1] - omega * d[x2]
1496 x[c_id_2][2*c_offset_2] = d1_r - tau_r;
1497 x[c_id_2][2*c_offset_2+1] = d1_c - tau_c;
1498
1499#if (DEBUG_ROW & 1)
1500printf("\n ### d1_out = (%f , %f) / d2_out = (%f , %f)\n",
1501 d1_r + tau_r , d1_c + tau_c , d2_r - tau_r , d2_c - tau_c );
1502#endif
1503 }
1504 }
1505 }
1506
1507#if DEBUG_ROW
1508printf("\n[fft] ROW data out / %d points / offset = %d\n", rootN , offset_x );
1509for ( p = 0 ; p < rootN ; p++ )
1510{
1511 unsigned int index = offset_x + p;
1512 unsigned int c_id = index / (points_per_cluster);
1513 unsigned int c_offset = index % (points_per_cluster);
1514 printf("%f , %f | ", x[c_id][2*c_offset] , x[c_id][2*c_offset+1] );
1515}
1516printf("\n");
1517#endif
1518
1519} // end FFTRow()
1520
1521///////////////////////////////////////
1522void PrintArray( double ** array,
1523 unsigned int size )
1524{
1525 unsigned int i;
1526 unsigned int c_id;
1527 unsigned int c_offset;
1528
1529 // float display
1530 for (i = 0; i < size ; i++)
1531 {
1532 c_id = i / (points_per_cluster);
1533 c_offset = i % (points_per_cluster);
1534
1535 printf(" %f %f |", array[c_id][2*c_offset], array[c_id][2*c_offset+1]);
1536
1537 if ( (i+1) % 4 == 0) printf("\n");
1538 }
1539 printf("\n");
1540}
1541
1542
1543// Local Variables:
1544// tab-width: 4
1545// c-basic-offset: 4
1546// c-file-offsets:((innamespace . 0)(inline-open . 0))
1547// indent-tabs-mode: nil
1548// End:
1549
1550// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1551
Note: See TracBrowser for help on using the repository browser.