OpenMP FFTW с Фортраном не безопасен для потоков - PullRequest
0 голосов
/ 08 июня 2018

Я пытаюсь использовать FFTW с openMP и Fortran, но я получаю неправильные результаты при параллельном выполнении, которые также меняют свои значения при каждом шаге выполнения, отображая типичное поведение при распараллеливании.

Ястремясь к простому трехмерному преобразованию реального в сложное.После учебника по FFTW я вынул все, кроме вызова dfftw_execute_dft_r2c(), из параллельной области, но, похоже, он не работает.

Я использую FFTW 3.3.8, настроенный с помощью ./configure --enable-threads --enable-openmp --enable-mpi и компилируюмой код с gfortran program.f03 -o program.o -I/usr/include -fopenmp -lfftw3_omp -lfftw3 -g -Wall.

Вот так выглядит моя программа:

program use_fftw

  use,intrinsic :: iso_c_binding
  use omp_lib
  implicit none
  include 'fftw3.f03'

  integer, parameter     :: dp=kind(1.0d0)
  integer, parameter     :: Nx = 10
  integer, parameter     :: Ny = 5
  integer, parameter     :: Nz = 5
  real(dp), parameter    :: pi = 3.1415926d0
  real(dp), parameter    :: physical_length_x = 20.d0
  real(dp), parameter    :: physical_length_y = 10.d0
  real(dp), parameter    :: physical_length_z = 10.d0
  real(dp), parameter    :: lambda1 = 0.5d0
  real(dp), parameter    :: lambda2 = 0.7d0
  real(dp), parameter    :: lambda3 = 0.9d0
  real(dp), parameter    :: dx = physical_length_x/real(Nx,dp)
  real(dp), parameter    :: dy = physical_length_y/real(Ny,dp)
  real(dp), parameter    :: dz = physical_length_z/real(Nz,dp)

  integer :: void, nthreads

  integer :: i, j, k
  real(dp):: d

  complex(dp), allocatable, dimension(:,:,:)  :: arr_out
  real(dp), allocatable, dimension(:,:,:)     :: arr_in
  integer*8                                   :: plan_forward


  allocate(arr_in( 1:Nx, 1:Ny, 1:Nz));     arr_in = 0
  allocate(arr_out(1:Nx/2+1, 1:Ny, 1:Nz)); arr_out = 0


  !------------------------------
  ! Initialize fftw stuff
  !------------------------------

  ! Call before any FFTW routine is called outside of parallel region
  void = fftw_init_threads()
  if (void==0) then
    write(*,*) "Error in fftw_init_threads, quitting"
    stop
  endif
  nthreads = omp_get_num_threads()
  call fftw_plan_with_nthreads(nthreads)

  ! plan execution is thread-safe, but plan creation and destruction are not:
  ! you should create/destroy plans only from a single thread
  call dfftw_plan_dft_r2c_3d(plan_forward, Nx, Ny, Nz, arr_in, arr_out, FFTW_ESTIMATE)


  !--------------------------------
  ! Start parallel region
  !--------------------------------

  !$OMP PARALLEL PRIVATE( j, k, d)

    ! Fill array with wave
    ! NOTE: wave only depends on x so you can plot it later.
    !$OMP DO
      do i = 1, Nx
        d = 2.0*pi*i*dx
        do j = 1, Ny
          do k = 1, Nz
            arr_in(i,j,k) = cos(d/lambda1)+sin(d/lambda2)+cos(d/lambda3) 
          enddo
        enddo
      enddo
    !$OMP END DO


    call dfftw_execute_dft_r2c(plan_forward, arr_in, arr_out)

  !$OMP END PARALLEL


  !-----------------
  ! print results
  !-----------------

  do i=1, Nx/2+1
    do j=1, Ny
      do k=1, Nz
        write(*,'(F12.6,A3,F12.6,A3)',advance='no') real(arr_out(i,j,k)), " , ", aimag(arr_out(i,j,k)), " ||"
      enddo
      write(*,*)
    enddo
    write(*,*)
  enddo



  deallocate(arr_in, arr_out)
  ! destroy plans is not thread-safe; do only with single
  call dfftw_destroy_plan(plan_forward)

end program use_fftw

Я также попытался переместить часть инициализации FFTW (void = fftw_init_threads(); call fftw_plan_with_nthreads(nthreads); call dfftw_plan_dft_r2c_3d(...) в параллельную область, используя!$OMP SINGLE блокировка и синхронизация с барьером впоследствии, но ситуация не улучшилась.

Кто-нибудь может мне помочь?

РЕДАКТИРОВАТЬ: Я смог проверить своив другой системе проблема остается, поэтому проблема, по-видимому, не в моей реализации openmp или FFTW, а где-то в самой программе.

1 Ответ

0 голосов
/ 08 июня 2018

Обычно вы должны вызывать fftw execute рутины вне области parallel.У них есть свои собственные параллельные области внутри, и они позаботятся о том, чтобы запустить преобразование параллельно с тем количеством потоков, которое вы запрашивали во время планирования.Они будут повторно использовать ваши существующие потоки OpenMP.

Вы также можете вызывать их внутри параллельной области, но в разных массивах, а не в одних и тех же!И тогда ваш план должен быть запланирован на использование 1 потока.Затем каждый поток будет предварительно преобразовывать 2D-преобразование фрагмента массива, например.

Потокобезопасность означает, что вы можете вызывать подпрограммы одновременно, но каждый для разных данных.

...