带有 Fortran 的 OpenMP FFTW 不是线程安全的
OpenMP FFTW with Fortran not thread safe
我正在尝试将 FFTW 与 openMP 和 Fortran 一起使用,但是在并行执行时我得到了错误的结果,这也会在每个执行步骤更改它们的值,显示并行化出错时的典型行为。
我的目标是进行简单的 3d 实景到复杂的转换。在 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 的实现中,而是在程序本身的某个地方。
您通常应该在 parallel
区域 外部 调用 fftw 执行例程。它们内部有自己的并行区域,它们将根据您在规划期间请求的那么多线程并行处理 运行 转换。他们将重新使用您现有的 OpenMP 线程。
您也可以在并行区域内调用它们,但要在不同的数组上调用,而不是在同一个数组上!然后你的计划应该计划使用 1 个线程。例如,每个线程然后会对数组的一部分执行二维转换。
线程安全意味着您可以同时调用例程,但每个例程针对不同的数据。
我正在尝试将 FFTW 与 openMP 和 Fortran 一起使用,但是在并行执行时我得到了错误的结果,这也会在每个执行步骤更改它们的值,显示并行化出错时的典型行为。
我的目标是进行简单的 3d 实景到复杂的转换。在 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 的实现中,而是在程序本身的某个地方。
您通常应该在 parallel
区域 外部 调用 fftw 执行例程。它们内部有自己的并行区域,它们将根据您在规划期间请求的那么多线程并行处理 运行 转换。他们将重新使用您现有的 OpenMP 线程。
您也可以在并行区域内调用它们,但要在不同的数组上调用,而不是在同一个数组上!然后你的计划应该计划使用 1 个线程。例如,每个线程然后会对数组的一部分执行二维转换。
线程安全意味着您可以同时调用例程,但每个例程针对不同的数据。