函数结果的 OpenMP Fortran 位置
OpenMP Fortran location of function result
编辑:我添加了一些输出和 link github 上的代码。
我尝试使用 OpenMP 在 Fortran 中编写有限差分函数,但 ifort (15.0.1 20141023) 和 gfortran (4.8.5 20150623) 之间的行为似乎有所不同。该代码按顺序运行良好。
事实上,该函数的结果似乎与 gfortran 共享,我不太了解它如何与 ifort 一起工作。
下面的代码适用于 gfortran (-g -O3 -fopenmp
):所有线程都使用相同的 fd
位置,这是我的函数的结果。
但是用ifort(-g -O3 -traceback -heap-arrays
),好像不是这样的
我不太了解OpenMP规范,我没有找到与函数结果的属性相关的内容。
最后,valgrind 运行 gfortran 很好,但是 return ifort 有很多错误
我是不是漏掉了什么?
program test
!$ use OMP_lib
use iso_fortran_env
implicit none
integer :: x,y
integer,parameter :: Nbx = 1000, Nby = 1000
real(real64), dimension(Nbx,Nby) :: trucAD=0, trucD=0
real(real64) :: dx=1
!$OMP PARALLEL
!$OMP DO
do y=1,Nby
do x=1,Nbx
trucAD(x,y) = x*dx
enddo
enddo
!$OMP END DO
trucD = dfonc2dxd(trucAD,Nbx,Nby,dx)
!$OMP SINGLE
write(*,*) 'Reference result =====> ', Nbx*Nby*dx
write(*,*) 'Result per threads:'
!$OMP END SINGLE
!$OMP CRITICAL
!$ write(*,*) '#t: ',omp_get_thread_num(), 'test: ', sum(trucD)
!$OMP END CRITICAL
!$OMP END PARALLEL
contains
function dfonc2dxd(foncad,DimX, DimY,da) result(fd)
implicit none
integer, intent(in) :: DimX, DimY
real(real64), dimension(DimX,DimY) :: fd
real(real64), dimension(DimX,DimY), intent(in) :: foncad
real(real64),intent(in) :: da
integer :: qq , ii , xx
real(real64), dimension(11,5), parameter :: coef_diff5dc = reshape((/&
-2.391602219538d0, 5.832490322294d0, -7.650218001181d0, 7.907810563576d0, -5.922599052629d0, 3.071037015445d0,&
-1.014956769726d0, 0.170022256519d0, 0.002819958377d0,-0.004791009708d0, -0.000013063429d0,&
-0.180022054228d0, -1.237550583044d0, 2.484731692990d0,-1.810320814061d0, 1.112990048440d0, -0.481086916514d0,&
0.126598690230d0, -0.015510730165d0, 0.000021609059d0, 0.000156447570d0, -0.000007390277d0,&
0.057982271137d0, -0.536135360383d0, -0.264089548965d0, 0.917445877604d0, -0.169688364841d0, -0.029716326170d0,&
0.029681617641d0, -0.005222483773d0, -0.000118806260d0,-0.000118806260d0, -0.000020069730d0,&
-0.013277273810d0, 0.115976072920d0, -0.617479187931d0,-0.274113948204d0, 1.086208764653d0, -0.402951626982d0,&
0.131066986242d0, -0.028154858354d0, 0.002596328316d0, 0.000128743150d0, 0.000000000000d0,&
0.016756572303d0, -0.117478455239d0, 0.411034935097d0,-1.130286765151d0, 0.341435872099d0, 0.556396830543d0,&
-0.082525734207d0, 0.003565834658d0, 0.001173034777d0,-0.000071772607d0, -0.000000352273d0 /) &
,shape(coef_diff5dc),order=(/1,2/))
real(real64),dimension(5),parameter::coef_diff=(/0.872756993962667d0,-0.286511173973333d0,0.09032000128000002d0,&
-0.020779405824000d0,0.0024845946880000d0/)
real(real64) :: unsda
unsda = 1.0d0/da
!$OMP SINGLE
!$ write(*,*) 'Location of fd for every threads'
!$OMP END SINGLE
!$ write(*,*) omp_get_thread_num(), loc(fd)
!$OMP BARRIER
!$OMP DO SCHEDULE(STATIC)
do qq = 1, DimY
!calcul des points centrés
do ii=6, DimX-5
fd(ii,qq) = 0
do xx=1, 5
fd(ii,qq) = fd(ii,qq) + coef_diff(xx)*(foncad(ii+xx,qq) - foncad(ii-xx,qq))
enddo
fd(ii,qq) = unsda * fd(ii,qq)
enddo
! calcul des points décentrés
do ii=1,5 !points avant
fd(ii,qq) = 0
do xx=1, 11
fd(ii,qq) = fd(ii,qq) + coef_diff5dc(xx,ii)*foncad(xx,qq)
enddo
fd(ii,qq) = unsda*fd(ii,qq)
enddo
do ii = DimX, DimX-4,-1 !points arriere
fd(ii,qq) = 0
do xx=1, 11
fd(ii,qq) = fd(ii,qq) - coef_diff5dc(xx,DimX-ii+1)*foncad(DimX-xx+1,qq)
enddo
fd(ii,qq) = unsda * fd(ii,qq)
enddo
enddo
!$OMP END DO
end function dfonc2dxd
end program test
当我使用 gfortran 时,我得到:
Location of result fd, for every threads
4 6304000
3 6304000
0 6304000
2 6304000
1 6304000
Reference=====> 1000000.0000000000
Result per threads:
#t: 4 test: 1000000.0000000000
#t: 2 test: 1000000.0000000000
#t: 3 test: 1000000.0000000000
#t: 1 test: 1000000.0000000000
#t: 0 test: 1000000.0000000000
所有线程在 fortran 函数中处理相同的结果,结果似乎是正确的。没有 valgrind 警告。
当我尝试使用 ifort 时:
Location of result fd, for every threads
0 47402661998608
3 47402629984272
2 47402645991440
1 47402637987856
4 47402653995024
Reference=====> 1000000.00000000
Result per threads:
并且已锁定。每个线程的结果位置不同。
使用 valgrind,我得到了大量的错误日志。我把它放在 github 上:
https://github.com/Hilid/test_OMP/blob/master/logval.txt
我认为 loc(fd)
没有任何用处。它可以是内存中任何位置的临时变量(可能是堆栈),或者通过一些 return 值优化,它可以是它被分配给的实际变量。但前提是它被分配给一个变量。我认为 OpenMP 在这方面没有太大变化。
这段代码让我怀疑存在竞争条件,不是多个线程写入同一个共享变量吗?
!$OMP PARALLEL
...
trucD = dfonc2dxd(trucAD,Nbx,Nby,dx)
编辑:我添加了一些输出和 link github 上的代码。
我尝试使用 OpenMP 在 Fortran 中编写有限差分函数,但 ifort (15.0.1 20141023) 和 gfortran (4.8.5 20150623) 之间的行为似乎有所不同。该代码按顺序运行良好。
事实上,该函数的结果似乎与 gfortran 共享,我不太了解它如何与 ifort 一起工作。
下面的代码适用于 gfortran (-g -O3 -fopenmp
):所有线程都使用相同的 fd
位置,这是我的函数的结果。
但是用ifort(-g -O3 -traceback -heap-arrays
),好像不是这样的
我不太了解OpenMP规范,我没有找到与函数结果的属性相关的内容。
最后,valgrind 运行 gfortran 很好,但是 return ifort 有很多错误
我是不是漏掉了什么?
program test
!$ use OMP_lib
use iso_fortran_env
implicit none
integer :: x,y
integer,parameter :: Nbx = 1000, Nby = 1000
real(real64), dimension(Nbx,Nby) :: trucAD=0, trucD=0
real(real64) :: dx=1
!$OMP PARALLEL
!$OMP DO
do y=1,Nby
do x=1,Nbx
trucAD(x,y) = x*dx
enddo
enddo
!$OMP END DO
trucD = dfonc2dxd(trucAD,Nbx,Nby,dx)
!$OMP SINGLE
write(*,*) 'Reference result =====> ', Nbx*Nby*dx
write(*,*) 'Result per threads:'
!$OMP END SINGLE
!$OMP CRITICAL
!$ write(*,*) '#t: ',omp_get_thread_num(), 'test: ', sum(trucD)
!$OMP END CRITICAL
!$OMP END PARALLEL
contains
function dfonc2dxd(foncad,DimX, DimY,da) result(fd)
implicit none
integer, intent(in) :: DimX, DimY
real(real64), dimension(DimX,DimY) :: fd
real(real64), dimension(DimX,DimY), intent(in) :: foncad
real(real64),intent(in) :: da
integer :: qq , ii , xx
real(real64), dimension(11,5), parameter :: coef_diff5dc = reshape((/&
-2.391602219538d0, 5.832490322294d0, -7.650218001181d0, 7.907810563576d0, -5.922599052629d0, 3.071037015445d0,&
-1.014956769726d0, 0.170022256519d0, 0.002819958377d0,-0.004791009708d0, -0.000013063429d0,&
-0.180022054228d0, -1.237550583044d0, 2.484731692990d0,-1.810320814061d0, 1.112990048440d0, -0.481086916514d0,&
0.126598690230d0, -0.015510730165d0, 0.000021609059d0, 0.000156447570d0, -0.000007390277d0,&
0.057982271137d0, -0.536135360383d0, -0.264089548965d0, 0.917445877604d0, -0.169688364841d0, -0.029716326170d0,&
0.029681617641d0, -0.005222483773d0, -0.000118806260d0,-0.000118806260d0, -0.000020069730d0,&
-0.013277273810d0, 0.115976072920d0, -0.617479187931d0,-0.274113948204d0, 1.086208764653d0, -0.402951626982d0,&
0.131066986242d0, -0.028154858354d0, 0.002596328316d0, 0.000128743150d0, 0.000000000000d0,&
0.016756572303d0, -0.117478455239d0, 0.411034935097d0,-1.130286765151d0, 0.341435872099d0, 0.556396830543d0,&
-0.082525734207d0, 0.003565834658d0, 0.001173034777d0,-0.000071772607d0, -0.000000352273d0 /) &
,shape(coef_diff5dc),order=(/1,2/))
real(real64),dimension(5),parameter::coef_diff=(/0.872756993962667d0,-0.286511173973333d0,0.09032000128000002d0,&
-0.020779405824000d0,0.0024845946880000d0/)
real(real64) :: unsda
unsda = 1.0d0/da
!$OMP SINGLE
!$ write(*,*) 'Location of fd for every threads'
!$OMP END SINGLE
!$ write(*,*) omp_get_thread_num(), loc(fd)
!$OMP BARRIER
!$OMP DO SCHEDULE(STATIC)
do qq = 1, DimY
!calcul des points centrés
do ii=6, DimX-5
fd(ii,qq) = 0
do xx=1, 5
fd(ii,qq) = fd(ii,qq) + coef_diff(xx)*(foncad(ii+xx,qq) - foncad(ii-xx,qq))
enddo
fd(ii,qq) = unsda * fd(ii,qq)
enddo
! calcul des points décentrés
do ii=1,5 !points avant
fd(ii,qq) = 0
do xx=1, 11
fd(ii,qq) = fd(ii,qq) + coef_diff5dc(xx,ii)*foncad(xx,qq)
enddo
fd(ii,qq) = unsda*fd(ii,qq)
enddo
do ii = DimX, DimX-4,-1 !points arriere
fd(ii,qq) = 0
do xx=1, 11
fd(ii,qq) = fd(ii,qq) - coef_diff5dc(xx,DimX-ii+1)*foncad(DimX-xx+1,qq)
enddo
fd(ii,qq) = unsda * fd(ii,qq)
enddo
enddo
!$OMP END DO
end function dfonc2dxd
end program test
当我使用 gfortran 时,我得到:
Location of result fd, for every threads
4 6304000
3 6304000
0 6304000
2 6304000
1 6304000
Reference=====> 1000000.0000000000
Result per threads:
#t: 4 test: 1000000.0000000000
#t: 2 test: 1000000.0000000000
#t: 3 test: 1000000.0000000000
#t: 1 test: 1000000.0000000000
#t: 0 test: 1000000.0000000000
所有线程在 fortran 函数中处理相同的结果,结果似乎是正确的。没有 valgrind 警告。
当我尝试使用 ifort 时:
Location of result fd, for every threads
0 47402661998608
3 47402629984272
2 47402645991440
1 47402637987856
4 47402653995024
Reference=====> 1000000.00000000
Result per threads:
并且已锁定。每个线程的结果位置不同。 使用 valgrind,我得到了大量的错误日志。我把它放在 github 上: https://github.com/Hilid/test_OMP/blob/master/logval.txt
我认为 loc(fd)
没有任何用处。它可以是内存中任何位置的临时变量(可能是堆栈),或者通过一些 return 值优化,它可以是它被分配给的实际变量。但前提是它被分配给一个变量。我认为 OpenMP 在这方面没有太大变化。
这段代码让我怀疑存在竞争条件,不是多个线程写入同一个共享变量吗?
!$OMP PARALLEL
...
trucD = dfonc2dxd(trucAD,Nbx,Nby,dx)