2011-12-31 40 views
2

私はfftwライブラリ(fftw3.a,fftw3.lib)を使ってLinuxとWindowsに2つの同一のプログラムを書いて、fftwf_execute(m_wfpFFTplan)ステートメント(16-fft)の継続時間を計算しました。 LinuxのWindowsでFFTWがLinuxよりも高速なのはなぜですか?

  • :10000回のランの

    平均時間は、Windows上では0.9

  • です:平均時間は、私はこれが9倍も速く、Windows上である理由として混乱しています0.12

ですLinuxよりも

プロセッサ:インテル(R)Core(TM)i7のCPUの870 2.93GHz

@各OS(Windows XPの32ビットおよびLinuxのopenSUSE 11.4 32ビット)が同じマシン上にインストールされています。

インターネットからfftw.lib(Windows用)をダウンロードしましたが、その設定はわかりません。私は、この設定をFFTWを構築するとします。Linuxで

/configure --enable-float --enable-threads --with-combined-threads --disable-fortran --with-slow-timer --enable-sse --enable-sse2 --enable-avx 

、それはデフォルトのコンフィグ(0.4ミリ秒)よりも4倍高速であるlibになります。

+0

fftwライブラリは同じコンパイラ(およびバージョン)でコンパイルされていますか?彼らは同じ旗で集められていますか?同じアーキテクチャのためにコンパイルされていますか?たぶん、WindowsのビルドがCPU機能をより有効に活用しているのかもしれません。多分それは別のコンパイラなので多分最適化されています。 –

+0

両方のプラットフォームで使用したコンパイラの詳細と、コードとそのライブラリの構築に使用されるコンパイルオプションを投稿してください。 – Mat

+0

は同じビット数です(32対64ビット)?同じ量のRAMを利用できますか?他のプロセスが並行して実行しているものは何ですか?任意の仮想化はアクティブですか? – Yahia

答えて

7

16 FFTが非常に小さい。あなたが見つけることになるのは、最高のパフォーマンスを得るために、ループを持たないハードコーディングされたアセンブラであると言う64より小さいFFTです。これは、命令セット、コンパイラの最適化、64ビットまたは32ビットのワードでさえ、それらが非常に影響を受けやすいことを意味します。

2の累乗で16 - > 1048576のFFTサイズのテストを実行するとどうなりますか?私はこれをハードコーディングされたasmルーチンがLinux上ではあなたのマシンに最適化されていないかもしれないと言っていますが、その特定のサイズのWindows実装では幸運かもしれません。この範囲のすべてのサイズを比較すると、Linux対Windowsのパフォーマンスをより正確に把握できます。

FFTWをキャリブレーションしましたか? FFTWを最初に実行すると、マシンごとに最速の実装が推測されますが、特別な命令セット、または特定のサイズのキャッシュやその他のプロセッサ機能がある場合、実行速度に劇的な影響を与えます。その結果、キャリブレーションを実行すると、さまざまなFFTルーチンの速度がテストされ、特定のハードウェアのサイズごとに最速のものが選択されます。キャリブレーションでは、計画を繰り返し計算し、生成されたFFTW「知恵」ファイルを保存します。保存された較正データ(これは長いプロセスです)を再利用することができます。あなたのソフトウェアが起動し、そのたびにファイルを再利用するときは、一度やり直すことをお勧めします。私はキャリブレーション後に一定のサイズに対して4〜10倍のパフォーマンス改善が見られました!

以下は、特定のサイズのFFTWを較正するために使用したコードスニペットです。このコードは、私が作業しているDSPライブラリから逐語的に貼り付けられているので、いくつかの関数呼び出しは私のライブラリ固有のものです。私はFFTWの特定の呼び出しが役立つことを願っています。

// Calibration FFTW 
void DSP::forceCalibration(void) 
{ 
// Try to import FFTw Wisdom for fast plan creation 
FILE *fftw_wisdom = fopen("DSPDLL.ftw", "r"); 

// If wisdom does not exist, ask user to calibrate 
if (fftw_wisdom == 0) 
{ 
    int iStatus2 = AfxMessageBox("FFTw not calibrated on this machine."\ 
     "Would you like to perform a one-time calibration?\n\n"\ 
     "Note:\tMay take 40 minutes (on P4 3GHz), but speeds all subsequent FFT-based filtering & convolution by up to 100%.\n"\ 
     "\tResults are saved to disk (DSPDLL.ftw) and need only be performed once per machine.\n\n"\ 
     "\tMAKE SURE YOU REALLY WANT TO DO THIS, THERE IS NO WAY TO CANCEL CALIBRATION PART-WAY!", 
     MB_YESNO | MB_ICONSTOP, 0); 

    if (iStatus2 == IDYES) 
    { 
     // Perform calibration for all powers of 2 from 8 to 4194304 
     // (most heavily used FFTs - for signal processing) 
     AfxMessageBox("About to perform calibration.\n"\ 
      "Close all programs, turn off your screensaver and do not move the mouse in this time!\n"\ 
      "Note:\tThis program will appear to be unresponsive until the calibration ends.\n\n" 
      "\tA MESSAGEBOX WILL BE SHOWN ONCE THE CALIBRATION IS COMPLETE.\n"); 
     startTimer(); 

     // Create a whole load of FFTw Plans (wisdom accumulates automatically) 
     for (int i = 8; i <= 4194304; i *= 2) 
     { 
      // Create new buffers and fill 
      DSP::cFFTin = new fftw_complex[i]; 
      DSP::cFFTout = new fftw_complex[i]; 
      DSP::fconv_FULL_Real_FFT_rdat = new double[i]; 
      DSP::fconv_FULL_Real_FFT_cdat = new fftw_complex[(i/2)+1]; 
      for(int j = 0; j < i; j++) 
      { 
       DSP::fconv_FULL_Real_FFT_rdat[j] = j; 
       DSP::cFFTin[j][0] = j; 
       DSP::cFFTin[j][1] = j; 
       DSP::cFFTout[j][0] = 0.0; 
       DSP::cFFTout[j][1] = 0.0; 
      } 

      // Create a plan for complex FFT. 
      // Use the measure flag to get the best possible FFT for this size 
      // FFTw "remembers" which FFTs were the fastest during this test. 
      // at the end of the test, the results are saved to disk and re-used 
      // upon every initialisation of the DSP Library 
      DSP::pCF = fftw_plan_dft_1d 
       (i, DSP::cFFTin, DSP::cFFTout, FFTW_FORWARD, FFTW_MEASURE); 

      // Destroy the plan 
      fftw_destroy_plan(DSP::pCF); 

      // Create a plan for real forward FFT 
      DSP::pCF = fftw_plan_dft_r2c_1d 
       (i, fconv_FULL_Real_FFT_rdat, fconv_FULL_Real_FFT_cdat, FFTW_MEASURE); 

      // Destroy the plan 
      fftw_destroy_plan(DSP::pCF); 

      // Create a plan for real inverse FFT 
      DSP::pCF = fftw_plan_dft_c2r_1d 
       (i, fconv_FULL_Real_FFT_cdat, fconv_FULL_Real_FFT_rdat, FFTW_MEASURE); 

      // Destroy the plan 
      fftw_destroy_plan(DSP::pCF); 

      // Destroy the buffers. Repeat for each size 
      delete [] DSP::cFFTin; 
      delete [] DSP::cFFTout; 
      delete [] DSP::fconv_FULL_Real_FFT_rdat; 
      delete [] DSP::fconv_FULL_Real_FFT_cdat; 
     } 

     double time = stopTimer(); 

     char * strOutput; 
     strOutput = (char*) malloc (100); 
     sprintf(strOutput, "DSP.DLL Calibration complete in %d minutes, %d seconds\n"\ 
      "Please keep a copy of the DSPDLL.ftw file in the root directory of your application\n"\ 
      "to avoid re-calibration in the future\n", (int)time/(int)60, (int)time%(int)60); 
     AfxMessageBox(strOutput); 

     isCalibrated = 1; 

     // Save accumulated wisdom 
     char * strWisdom = fftw_export_wisdom_to_string(); 
     FILE *fftw_wisdomsave = fopen("DSPDLL.ftw", "w"); 
     fprintf(fftw_wisdomsave, "%s", strWisdom); 

     fclose(fftw_wisdomsave); 
     DSP::pCF = NULL; 
     DSP::cFFTin = NULL; 
     DSP::cFFTout = NULL; 
     fconv_FULL_Real_FFT_cdat = NULL; 
     fconv_FULL_Real_FFT_rdat = NULL; 
     free(strOutput); 
    } 
} 
else 
{ 
    // obtain file size. 
    fseek (fftw_wisdom , 0 , SEEK_END); 
    long lSize = ftell (fftw_wisdom); 
    rewind (fftw_wisdom); 

    // allocate memory to contain the whole file. 
    char * strWisdom = (char*) malloc (lSize); 

    // copy the file into the buffer. 
    fread (strWisdom,1,lSize,fftw_wisdom); 

    // import the buffer to fftw wisdom 
    fftw_import_wisdom_from_string(strWisdom); 

    fclose(fftw_wisdom); 
    free(strWisdom); 

    isCalibrated = 1; 

    return; 
} 
} 

秘密のソースは、具体的には、あなたの特定のFFTの種類(実数、複素数、1D、2D)とサイズのための最速を見つけるために、ルーチンの数百を測定FFTW_MEASUREフラグを使用して計画を作成することです。

DSP::pCF = fftw_plan_dft_1d (i, DSP::cFFTin, DSP::cFFTout, 
    FFTW_FORWARD, FFTW_MEASURE); 

最後に、すべてのベンチマークテストは、リリースモードでコンパイルされ、デバッガから最適化されたコードから呼び出された、実行外の単一のFFTプランステージで実行する必要があります。ベンチマークは、何千(または何百万)の反復を伴うループで実行し、結果を計算するために平均実行時間を取る必要があります。計画段階にはかなりの時間がかかり、実行は単一の計画で複数回実行されるように設計されていることは、おそらく分かっています。

関連する問題