我正在尝试并行执行几个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真的不是一个“孤儿”,对吗?是因为两个线程可能同时尝试命中 numberOfRows 或 numberOfColumns 内存位置吗?
答案 0 :(得分:7)
这几乎全部都写在关于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(后)Nehalem系统)上运行,则应启用线程绑定以实现最佳性能。