Diana Software
BenchmarkFFT.C
Go to the documentation of this file.
1 #ifndef _HAVE_FFTW3_
2 #error Program requires FFTW3 headers to run. Check your environment settings and that DIANA_HAVE_FFTW3 is set
3 #endif
4 
5 #include <iostream>
6 #include "QVector.hh"
7 #include "QVectorC.hh"
8 #include "QRealComplexFFT.hh"
9 #include "QRealComplexFFTW3.hh"
10 #include "QRealComplexFFTGSL.hh"
11 #include "QFFTWPlan.hh"
12 #include <TRandom.h>
13 #include <TTree.h>
14 #include <TFile.h>
15 #include <vector>
16 #include <getopt.h>
17 
18 const char *progname;
19 
20 
21 struct BenchmarkData {
26  double fGSLPrepTime;
27  double fFFTWPrepTime;
34 
35 };
36 
37 void usage() {
38  std::cout << progname << std::endl;
39  std::cout << "Benchmark FFT algorithms for different size windows.\n" << std::endl;
40  std::cout << "Options: " << std::endl;
41  std::cout << " -n : Number of runs per test." << std::endl;
42  std::cout << " -w : Add a window size to test. (Can specify multiple times)." << std::endl;
43  std::cout << " -o : Output to a root file." << std::endl;
44  std::cout << " -h : This helpful message." << std::endl;
45 }
46 
47 
48 double GetTime_ms(time_t t0,clock_t c0,time_t t1,clock_t c1){
49  clock_t cDiff=c1-c0;
50  double tDiff=difftime(t1,t0);
51  int wrappedTime=((int)(tDiff/4294))*4294;
52  return (1.E3*cDiff/CLOCKS_PER_SEC)+1.E3*wrappedTime;
53 }
54 
55 
56 void BenchmarkTransform(int NRuns,int WinSize,BenchmarkData &results) {
57 
58  std::cout << "Benchmarking window size " << WinSize << " ... " << std::endl;
59  std::cout << "Running " << NRuns << " transforms per test ..." << std::endl;
60 
61  results.fNGSLTests = NRuns;
62  results.fNFFTWTests = NRuns;
63  results.fWindowSize = WinSize;
64 
65  bool compress = false;
66  Diana::QVector X1(WinSize),X2(WinSize),X3(WinSize);
67  Diana::QVectorC Y1(compress ? WinSize/2+1 : WinSize),
68  Y2(compress ? WinSize/2+1 : WinSize),
69  Y3(WinSize/2+1);
70  for(int j=0;j<WinSize;j++)
71  X1[j]=X2[j]=X3[j]=gRandom->Gaus();
72 
73  clock_t c1 = ::clock();
74  time_t t1 = ::time(NULL);
75  Diana::QRealComplexFFTW3 *FFTW = new Diana::QRealComplexFFTW3(WinSize);
76  FFTW->TransformToFreq(X1,Y1);
77  FFTW->TransformFromFreq(Y1,X1);
78  clock_t c2 = ::clock();
79  time_t t2 = ::time(NULL);
80  results.fFFTWPrepTime=1000.*GetTime_ms(t1,c1,t2,c2);
81 
82  c1 = ::clock();
83  t1 = ::time(NULL);
84  Diana::QRealComplexFFTGSL *GSL = new Diana::QRealComplexFFTGSL(WinSize);
85  c2 = ::clock();
86  t2 = ::time(NULL);
87  results.fGSLPrepTime=GetTime_ms(t1,c1,t2,c2);
88 
89  Diana::QFFTWRealComplexPlan FFTWForwardPlan = Diana::QFFTWRealComplexPlan::CreateForwardPlan(X3,Y3);
90  Diana::QFFTWRealComplexPlan FFTWBackwardPlan = Diana::QFFTWRealComplexPlan::CreateBackwardPlan(Y3,X3);
91 
92  std::cout << "Running " << NRuns << " Forward Tests With GSL ..." << std::endl;
93  c1 = ::clock();
94  t1 = ::time(NULL);
95  for(int j=0;j<NRuns;j++)
96  GSL->TransformToFreq(X2,Y2,compress);
97  c2 = ::clock();
98  t1 = ::time(NULL);
99  results.fGSLForwardTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
100 
101  std::cout << "Running " << NRuns << " Forward Tests With FFTW ..." << std::endl;
102  c1 = ::clock();
103  t1 = ::time(NULL);
104  for(int j=0;j<NRuns;j++)
105  FFTW->TransformToFreq(X1,Y1,compress);
106  c2 = ::clock();
107  t2 = ::time(NULL);
108  results.fFFTWForwardTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
109 
110  std::cout << "Running " << NRuns << " Forward Tests With FFTW Plan ..." << std::endl;
111  c1 = ::clock();
112  t1 = ::time(NULL);
113  for(int j=0;j<NRuns;j++)
114  FFTWForwardPlan.Execute();
115  c2 = ::clock();
116  t2 = ::time(NULL);
117  results.fFFTWForwardPlanTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
118 
119  std::cout << "Running " << NRuns << " Backward Tests With GSL ..." << std::endl;
120  c1 = ::clock();
121  t1 = ::time(NULL);
122  for(int j=0;j<NRuns;j++)
123  GSL->TransformFromFreq(Y2,X2,compress);
124  c2 = ::clock();
125  t2 = ::time(NULL);
126  results.fGSLBackwardTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
127 
128  std::cout << "RUnning " << NRuns << " Backward Tests With FFTW ..." << std::endl;
129  c1 = ::clock();
130  t1 = ::time(NULL);
131  for(int j=0;j<NRuns;j++)
132  FFTW->TransformFromFreq(Y1,X1,compress);
133  c2 = ::clock();
134  t2 = ::time(NULL);
135  results.fFFTWBackwardTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
136 
137  std::cout << "Running " << NRuns << " Backward Tests With FFTW Plan ..." << std::endl;
138  c1 = ::clock();
139  t1 = ::time(NULL);
140  for(int j=0;j<NRuns;j++)
141  FFTWBackwardPlan.Execute();
142  c2 = ::clock();
143  t2 = ::time(NULL);
144  results.fFFTWBackwardPlanTimePerPulse = 1000.*GetTime_ms(t1,c1,t2,c2)/NRuns;
145 
146 
147  std::cout << "GSL Prep:\t" << results.fGSLPrepTime/1000 << "ms" << std::endl;
148  std::cout << "FFTW Prep:\t" << results.fFFTWPrepTime/1000 << "ms" << std::endl;
149 
150  std::cout << Form("GSL Forward:\t%.2f ms (%4.2f us/pulse)",
151  NRuns*results.fGSLForwardTimePerPulse/1000,results.fGSLForwardTimePerPulse)
152  << std::endl;
153  std::cout << Form("FFTW Forward:\t%.2f ms (%4.2f us/pulse)",
154  NRuns*results.fFFTWForwardTimePerPulse/1000,results.fFFTWForwardTimePerPulse)
155  << std::endl;
156  std::cout << Form("FFTW Forward Plan:\t%.2f ms (%4.2f us/pulse)",
158  << std::endl;
159  Diana::QVectorC Diff=Y1-Y2;
160  std::cout << "MeanSqDif: "
161  << Diff.InterleavedVector().GetRMS(2*Diff.Size()) << std::endl;
162 
163  std::cout << Form("GSL Backward:\t%.2f ms (%4.2f us/pulse)",
164  NRuns*results.fGSLBackwardTimePerPulse/1000,results.fGSLBackwardTimePerPulse)
165  << std::endl;
166  std::cout << Form("FFTW Backward:\t%.2f ms (%4.2f us/pulse)",
167  NRuns*results.fFFTWBackwardTimePerPulse/1000,results.fFFTWBackwardTimePerPulse)
168  << std::endl;
169  std::cout << Form("FFTW Backward Plan:\t%.2f ms (%4.2f us/pulse)",
171  << std::endl;
172 
173  Diana::QVector Diff2=X1-X2;
174  std::cout << "MeanSqDif: " << Diff2.GetRMS(Diff2.Size()) << std::endl;
175 
176  std::cout<<"GSL Total:\t"<< results.fGSLPrepTime/1000 + NRuns * (results.fGSLForwardTimePerPulse + results.fGSLBackwardTimePerPulse)/1000
177  << "ms" <<std::endl;
178  std::cout<<"FFTW Total:\t"<< results.fFFTWPrepTime/1000 + NRuns * (results.fFFTWForwardTimePerPulse + results.fFFTWBackwardTimePerPulse)/1000
179  << "ms" <<std::endl;
180  std::cout << std::endl;
181 
182 
183 
184 
185 
186 
187 
188  delete GSL;delete FFTW;
189 
190 }
191 
192 int main(int argc,char *argv[]){
193 
194  progname=(progname=strrchr(argv[0],'/'))==NULL ? argv[0] : progname+1;
195 
196  int NRuns = 10000;
197  std::vector<int> windowSizes;
198  TFile *outFile = NULL;
199  TTree *tree = NULL;
200 
201  int c;
202  while((c = getopt(argc,argv,":n:w:o:h"))!=-1) {
203  switch(c) {
204  case 'n':
205  NRuns = atoi(optarg);
206  break;
207  case 'w':
208  windowSizes.push_back(atoi(optarg));
209  break;
210  case 'o':
211  if(!tree) {
212  outFile = new TFile(optarg,"RECREATE");
213  tree = new TTree("FFTBenchmark","FFT Benchmark Results");
214  }
215  break;
216  case 'h':
217  usage();
218  return 0;
219  case ':':
220  std::cout << "Option -" << (char)optopt << " requires an argument." << std::endl;
221  return 2;
222  case '?':
223  std::cout << "Unknown option: -" << (char)optopt << std::endl;
224  return 2;
225  }
226  }
227 
228  std::cout << "Testing " << NRuns << " FFTs for window sizes: ";
229  for(size_t i=0;i<windowSizes.size();i++)
230  std::cout << windowSizes[i] << " ";
231  std::cout << std::endl;
232 
233  BenchmarkData benchmarkData;
234  if(tree){
235  tree->Branch("NGSLTests",&NRuns,"NGSLTests/I");
236  tree->Branch("NFFTWTests",&NRuns,"NFFTWTests/I");
237  tree->Branch("WindowSize",&benchmarkData.fWindowSize,"WindowSize/I");
238  tree->Branch("GSLForwardTimePerPulse_us",&benchmarkData.fGSLForwardTimePerPulse,"GSLForwardTimePerPulse_us/D");
239  tree->Branch("GSLBackwardTimePerPulse_us",&benchmarkData.fGSLBackwardTimePerPulse,"GSLBackwardTimePerPulse_us/D");
240  tree->Branch("FFTWForwardTimePerPulse_us",&benchmarkData.fFFTWForwardTimePerPulse,"FFTWForwardTimePerPulse_us/D");
241  tree->Branch("FFTWBackwardTimePerPulse_us",&benchmarkData.fFFTWBackwardTimePerPulse,"FFTWBackwardTimePerPulse_us/D");
242  }
243 
244  for(size_t i=0;i<windowSizes.size();i++){
245  BenchmarkTransform(NRuns,windowSizes[i],benchmarkData);
246  if(tree) {
247  tree->Fill();
248  tree->Write("",TTree::kOverwrite);
249  }
250  }
251 
252  if(tree) {
253  tree->Write();
254  outFile->Close();
255  }
256 
257  return 0;
258 }
int main(int argc, char *argv[])
Definition: BenchmarkFFT.C:192
void usage()
Definition: BenchmarkFFT.C:37
double GetTime_ms(time_t t0, clock_t c0, time_t t1, clock_t c1)
Definition: BenchmarkFFT.C:48
void BenchmarkTransform(int NRuns, int WinSize, BenchmarkData &results)
Definition: BenchmarkFFT.C:56
const char * progname
Definition: BenchmarkFFT.C:18
double t0
Definition: CheckOF.C:26
int optopt
Definition: QOptions.cc:19
char * optarg
double fFFTWPrepTime
Definition: BenchmarkFFT.C:27
double fGSLPrepTime
Definition: BenchmarkFFT.C:26
double fFFTWForwardTimePerPulse
Definition: BenchmarkFFT.C:29
double fGSLForwardTimePerPulse
Definition: BenchmarkFFT.C:28
double fGSLBackwardTimePerPulse
Definition: BenchmarkFFT.C:30
double fFFTWForwardPlanTimePerPulse
Definition: BenchmarkFFT.C:32
double fFFTWBackwardPlanTimePerPulse
Definition: BenchmarkFFT.C:33
double fFFTWBackwardTimePerPulse
Definition: BenchmarkFFT.C:31