【问题标题】:FFTW plan creation using OpenMP使用 OpenMP 创建 FFTW 计划
【发布时间】:2013-02-07 08:31:23
【问题描述】:

我正在尝试并行执行多个 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 并不是真正的“孤儿”,对吧?是不是因为两个线程可能同时尝试访问 numberOfRowsnumberOfColumns 内存位置?

【问题讨论】:

  • 您没有使用 fftw 的多线程功能。您实际上是在并行进行 36 个单线程转换。
  • 我知道。我说在我最初的问题中 每个 FFT 都不同,所以我不依赖 FFTW 的内置多线程 。我想并行进行 36 个单线程转换。
  • 对不起,我的错误,我读的完全相反;-)

标签: c++ openmp parallax fftw


【解决方案1】:

关于thread safety 的内容几乎都写在 FFTW 文档中:

...但必须小心,因为计划程序例程在呼叫和计划之间共享数据(例如智慧表和三角表)。

结果是 FFTW 中唯一的线程安全(可重入)例程是 fftw_execute(及其新数组变体)。所有其他例程(例如计划程序)一次只能从一个线程调用。因此,例如,您可以在对规划器的任何调用周围包裹一个信号量锁;更简单地说,您可以从一个线程创建所有计划。我们认为这不应该是一个重要的限制(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 (post-)Nehalem 系统),则应启用线程绑定以实现最大性能。

【讨论】:

  • 我刚刚阅读了手册的那部分......我回来回答我自己的问题并看到了你的问题。你得到支票。您说“除非数据的维度发生变化”,但如果维度相同但值不同怎么办?我更新了我原来的问题以反映这一点。
  • @tir38,这就是你多次执行计划的原因,不是吗?只要您重用输入和输出数组,单个计划就可以了。只是不要像那样分配给inputTest,因为它是一个指针。您宁愿拥有someDataSpecificToThisIteration(m, inputData) 之类的东西,并将函数的输出放入inputData
  • 再次抱歉。我的意思是someDataSpecificToThisIteration[m]。它不是方法调用,而是从某个通用数组中提取的。所以我只是让inputData 成为指向该数据的指针。因为我实际上有 36 个指向 36 个数组条目的指针,所以我需要 36 个计划,对吧?
  • @tir38,不,你没有。您只需要稍微不同地执行每个计划。见here
  • 优秀。那行得通!我不确定它对我的应用程序是否更快,但它可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
相关资源
最近更新 更多