2013-02-21 9 views
5

複数のFFTを並行して実行しようとしています。私はFFTWとOpenMPを使用しています。各FFTは異なっているので、FFTWの組み込みマルチスレッド(OpenMPを使用していることがわかっています)に頼っているわけではありません。OpenMPを使用したFFTWプランの作成

int m; 

// assume: 
// int numberOfColumns = 100; 
// int numberOfRows = 100; 

#pragma omp parallel for default(none) private(m) shared(numberOfColumns, numberOfRows)// num_threads(4) 
    for(m = 0; m < 36; m++){ 

     // create pointers 
     double   *inputTest; 
     fftw_complex *outputTest; 
     fftw_plan  testPlan; 

     // preallocate vectors for FFTW 
     outputTest = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*numberOfRows*numberOfColumns); 
     inputTest = (double *)fftw_malloc(sizeof(double)*numberOfRows*numberOfColumns); 

     // confirm that preallocation worked 
     if (inputTest == NULL || outputTest == NULL){ 
      logger_.log_error("\t\t FFTW memory not allocated on m = %i", m); 
     } 

     // EDIT: insert data into inputTest 
     inputTest = someDataSpecificToThisIteration(m); // same size for all m 

     // create FFTW plan 
     #pragma omp critical (make_plan) 
     { 
      testPlan = fftw_plan_dft_r2c_2d(numberOfRows, numberOfColumns, inputTest, outputTest, FFTW_ESTIMATE); 
     } 

     // confirm that plan was created correctly 
     if (testPlan == NULL){ 
      logger_.log_error("\t\t failed to create plan on m = %i", m); 
     } 

     // execute plan 
     fftw_execute(testPlan); 

     // clean up 
     fftw_free(inputTest); 
     fftw_free(outputTest); 
     fftw_destroy_plan(testPlan); 

    }// end parallelized for loop 

これはすべて問題なく動作します。しかし、計画作成(fftw_plan_dft_r2c_2d)の周りから重要な構成要素を削除すると、コードが失敗します。なぜ誰かが説明できますか? fftw_plan_dft_r2c_2dは本当に「孤児」ではありません。これは、2つのスレッドが両方ともnumberOfRowsまたはnumberOfColumnsのメモリ位置を同時に攻撃する可能性があるためですか?

+0

fftwのマルチスレッド機能を使用していません。 実際には、36個のシングルスレッド変換を並行して行います。 –

+0

私は知っています。私は最初の質問でそれを言う_各FFTは異なるので、私はFFTWの組み込みマルチスレッドには依存していない_。 36個のシングルスレッド変換を並行して実行したい。 – tir38

+0

申し訳ありません、私の間違い、私はちょうど反対を読む;-) –

答えて

7

は、それはほとんどすべてFFTWのドキュメントに関するthread safetyで書かれています:

...しかし、いくつかの注意が必要ので、通話や計画の間プランナールーチンシェアデータ(例えば、知恵と三角関数テーブルが)。

FFTWのスレッドセーフ(リエントラント)ルーチンは、fftw_execute(およびその新しい配列の変形)のみです。他のすべてのルーチン(例えば、プランナー)は、一度に1つのスレッドからのみ呼び出されるべきです。例えば、プランナへの呼び出しの周りにセマフォー・ロックをラップすることができます。さらに簡単に言うと、1つのスレッドからすべてのプランを作成できます。これは重要な制限ではないと考えています(FFTWは、パフォーマンス重視のコードだけが変換の実際の実行を行うように設計されています)、計画間で共有されるデータのメリットは大きいです。

FFTプランの典型的なアプリケーションはめったに構築されないため、作成を同期する必要があるかどうかは関係ありません。データの次元が変更されない限り、各反復で新しいプランを作成する必要はありません。

#pragma omp parallel default(none) private(m) shared(numberOfColumns, numberOfRows) 
{ 
    // create pointers 
    double   *inputTest; 
    fftw_complex *outputTest; 
    fftw_plan  testPlan; 

    // preallocate vectors for FFTW 
    outputTest = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*numberOfRows*numberOfColumns); 
    inputTest = (double *)fftw_malloc(sizeof(double)*numberOfRows*numberOfColumns); 

    // confirm that preallocation worked 
    if (inputTest == NULL || outputTest == NULL){ 
     logger_.log_error("\t\t FFTW memory not allocated on m = %i", m); 
    } 

    // create FFTW plan 
    #pragma omp critical (make_plan) 
    testPlan = fftw_plan_dft_r2c_2d(numberOfRows, numberOfColumns, inputTest, outputTest, FFTW_ESTIMATE); 

    #pragma omp for 
    for (m = 0; m < 36; m++) { 
     // execute plan 
     fftw_execute(testPlan); 
    } 

    // clean up 
    fftw_free(inputTest); 
    fftw_free(outputTest); 
    fftw_destroy_plan(testPlan); 
} 

今計画は、各スレッドで一度だけ作成され、シリアル化のオーバーヘッドがfftw_execute()の各実行に減少するでしょう:あなたは、むしろ次の手順を実行します。 NUMAシステム(たとえば、マルチソケットAMD64またはIntel(ポスト)Nehalemシステム)で実行している場合は、パフォーマンスを最大にするためにスレッド・バインディングを使用可能にする必要があります。

+0

私はマニュアルのその部分を読んだ...私は自分の質問に答えるために戻って来て、あなたを見た。あなたは小切手を受け取る。 「データの次元が変わらない限り」と言いますが、次元は同じですが値は異なりますか?私はこれを反映するために私の元の質問を更新しました。 – tir38

+0

@ tir38だから、計画を何回も実行するのはなぜですか?入力配列と出力配列を再利用する限り、1つの計画はOKです。それはポインタなので、 'inputTest'に割り当てないでください。むしろ 'someDataSpecificToThisIteration(m、inputData)'のようなものを用意し、関数の出力を 'inputData'に入れておきます。 –

+0

もう一度申し訳ありません。私は 'someDataSpecificToThisIteration [m]'を意味しました。そのメソッド呼び出しではなく、いくつかの一般的な配列からのプル。ですから、私は 'inputData'をそのデータへのポインタにするだけです。私は36個の配列エントリに36個のポインタを効果的に持っているので、36個のプランが必要です。 – tir38

関連する問題