Создание плана FFTW с использованием OpenMP

Я пытаюсь выполнить несколько БПФ параллельно. Я использую 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 или же Число столбцов расположение памяти одновременно?

6

Решение

Это почти все написано в документации 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), вам следует включить привязку потоков для достижения максимальной производительности.

7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]