7

複数のFFTを並行して実行しようとしています。私はFFTWとOpenMPを使用しています。FFTはそれぞれ異なるので、FFTWの組み込みマルチスレッド(OpenMPを使用していることはわかっています)に依存していません。

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メモリ位置に同時にヒットしようとする可能性があるためですか?

4

1 に答える 1

7

スレッドセーフに関するFFTWのドキュメントにはほとんどすべて書かれています:

...しかし、プランナールーチンは呼び出しとプランの間でデータ(たとえば、知恵と三角関数表)を共有するため、注意が必要です。

結果として、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);
}

これで、プランは各スレッドで1回だけ作成され、シリアル化のオーバーヘッドは。を実行するたびに減少しますfftw_execute()。NUMAシステム(マルチソケットAMD64またはIntel(ポスト)Nehalemシステムなど)で実行している場合は、最大のパフォーマンスを実現するためにスレッドバインディングを有効にする必要があります。

于 2013-02-21T22:24:01.203 に答える