问题描述
我对于fortran还是相当陌生,对于openmp还是很陌生。我已经从同事那里继承了一个fortran代码,并被要求使用openmp对其进行并行化。该代码最初是从matlab转换而来的,无需使用openmp即可正常运行。但是当我尝试并行化它时,我遇到了不同的问题。
我只有一个do循环,里面包含多个计算,例如:maxval,reshape,sum,sum和product和几个where语句(我正在复制下面的一些代码)。我正在阅读教程,有些建议使用关键部分,其他建议减少使用,另一些则使用工作共享。现在的代码如下,我没有显示所有变量,因为它会更长:
subroutine COMPUTE_RIM(variables)
use hdf5
use omp_lib
use precision,only: pr => sp !it's a module to define number precision,I'm using single prec.
implicit none
!variable declaration. I'm showing some as an example
integer :: NAN = -9999
integer(hsize_t),dimension(1:2) :: lat_dims
real(pr),dimension(480,1440,96) :: precipitation_new
real(pr) :: dilf,rim,hyc,pick
real(pr),allocatable,dimension(:) :: dilIns,dil,wVec
real(pr),dimension(:,:) :: t_rain,dil_Hyst,dilM,cc,time
integer :: a,b,aa,bb,id1,kz1,cc2,timeIns
integer,dimension(:) :: lat_indF,long_indF,ind_rowF,ind_colF,indNan2
integer,:) :: indNan1
real(pr),dimension(1,lat_dims(2)) :: sec
real(pr),dimension(lat_dims(1),lat_dims(2)):: anc_sss
!arrays allocation,I'm showing some
allocate(sample_time(1,48),t_dif(1,t_rain(13,49),indNan1(13,indNan2(13))
allocate(dilM(13,time(13,cc(13,dilIns(13),dil_Hyst(13,dil(13))
allocate(wVec(13),RIM_SSS(lat_dims(1),lat_dims(2)))
!arrays initialization,showing some
t_rain(:,:) = NAN
RIM_SSS(:,:) = NAN
!defining parameters
z = 0.005_pr !just one example,there are more param. that are used in the loop
!$OMP PARALLEL PRIVATE(b,a,pick,id1)
!$OMP DO
do itemp = 1,size(lat_indF)
a = ind_rowF(itemp)
b = ind_colF(itemp)
aa = lat_indF(itemp) - 120
bb = long_indF(itemp)
t_dif = (sample_time - (sec(1,b)/3600._pr))
hyc = anc_sss(a,b)
!$OMP CRITICAL
pick = maxval(pack(t_dif,t_dif .lt. 0))
id1 = maxloc((pack(t_dif,t_dif .lt. 0)),dim=1)
!$OMP END CRITICAL
timeIns = -pick*3600._pr;
!$OMP CRITICAL
t_rain(1,:) = reshape(precipitation_new(aa - 2,id1:id1 + 48),shape(t_rain(1,:)))
.
.
.
!$OMP END CRITICAL
where (t_rain .ge. 0)
indNan1 = 1
elsewhere
indNan1 = 0
endwhere
dilM = (1._pr + (((t_rain(:,1:48)*real(indNan1(:,1:48),pr)*(cc/1000._pr))/&
(sqrt(time*kz1)))*exp((-z**2._pr)/(4._pr*kz1*time))))
dilIns = (1._pr + (((t_rain(:,49)*real(indNan1(:,pr)*((1800._pr*cc2)/&
3600._pr)/(1000._pr))/(sqrt(timeIns*kz1)))*exp((-z**2._pr)/(4._pr*kz1*timeIns))))
dil_Hyst(1:13,1:48) = dilM
dil_Hyst(1:13,49) = dilIns
dil = (product(dil_Hyst,2))**(-1._pr)
dilf = (sum((dil*wVec*real(indNan2,pr)),1))/(sum(wVec*real(indNan2,pr),1))
rim = hyc*dilf;
RIM_SSS(a,b) = rim
enddo
!$OMP END DO
!$OMP END PARALLEL\
!deallocate variables
我将代码编译为:gfortran -fopenmp -g -fcheck =所有主要main.f90(和hdf5模块)
到目前为止,我已经尝试过:
-
原样的代码可以编译并运行(假设我执行ulimit -s unlimited),但是会产生错误的结果。它与应有的外观相似,但有很多噪音(污染,值很大或非常小。可变边距不应大于50或小于0,除非靠近未定义的边界且应为-9999或NaN)。
-
即使代码按原样运行,执行perf stat ./main也会出现分段错误。
-
如果不执行ulimit -s unlimited,则会出现分段错误。
-
如果我将工作共享添加到!$ OMP PARALLEL,它将无法识别!$ OMP DO。它说:意外的!$ OMP DO语句在(1)。
我在另一篇文章中读到我可以做vagrind ./main,然后得到:
==6309== Warning: client switching stacks? SP change: 0x1ffefffd28 --> 0x1fdf5bf7d0
==6309== to suppress,use: --max-stackframe=530842968 or greater
==6309== Invalid write of size 8
==6309== at 0x115974: MAIN__ (main_omp.f90:6)
==6309== Address 0x1fdf5bf9f8 is on thread 1's stack
==6309==
==6309== Can't extend stack to 0x1fdf5be888 during signal delivery for thread 1:
==6309== no stack segment
由于我的经验不足,我无法理解我是否有基本错误或基本错误。我是否以错误的方式使用了openmp指令,或者缺少了一些? 任何帮助表示赞赏。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)