Fortran 启用$OMP DO循环时出现分段错误
我正在尝试修改旧代码以使用openmp初始化阵列。但是,在下面的代码部分中启用$OMP DO派生时,我遇到了分段错误。请你指出可能出了什么问题好吗 我使用fortran,并使用gfortran编译,变量被声明为公共变量Fortran 启用$OMP DO循环时出现分段错误,fortran,openmp,Fortran,Openmp,我正在尝试修改旧代码以使用openmp初始化阵列。但是,在下面的代码部分中启用$OMP DO派生时,我遇到了分段错误。请你指出可能出了什么问题好吗 我使用fortran,并使用gfortran编译,变量被声明为公共变量 common/quant/keosc,vosc,rosc,frt,grt,dipole,v_solv common/quant_avg/frt_avg,grt_avg,d_coup,rv_avg,b_avg !$OMP PARALLEL !$OMP DO
common/quant/keosc,vosc,rosc,frt,grt,dipole,v_solv
common/quant_avg/frt_avg,grt_avg,d_coup,rv_avg,b_avg
!$OMP PARALLEL
!$OMP DO private(m,j,l,mp) firstprivate(nstates,natoms) lastprivate(rv_avg,b_avg,grt_avg,frt_avg,d_coup)
do m = 0, nstates - 1
rv_avg(m) = 0d0
b_avg(m) = 0d0
do j = 1, 3
grt_avg(m,j) = 0d0
do l = 1, natoms
frt_avg(m,l,j) = 0d0
do mp = 0, nstates - 1
d_coup(m,mp,l,j) = 0d0
enddo
enddo
enddo
enddo
!$OMP END DO
!$OMP END PARALLEL
您是否测量了程序中CPU消耗的位置?加速那些不消耗太多CPU时间的部分是一种浪费。如果数组初始化占CPU使用量的比例很高,我会感到惊讶。如果改用数组表示法,代码的可读性会更高,例如,
rv_avg(0:nstates-1)=0d0
您没有显示任何数组的维度声明,因此我推测
do m = 0, nstates - 1
rv_avg(m) = 0d0
写入不存在的rv_avg
元素,即索引0
处的元素。由于Fortran程序在默认情况下不会检查数组元素访问是否在边界内,因此运行时不会捕获边界外的写入。如果执行时写操作停留在程序的地址空间内,则不会导致分段错误。给定公共块声明,rv_avg
的0
-th元素很可能是d_coup
的一部分
通过引入OpenMP,改变变量到地址空间的映射,很容易相信rv_avg
的0
-th元素现在位于线程的地址空间之外,并导致分段错误
由于程序对0
处的数组元素进行了其他引用,因此其中任何一个都可能是分段错误的根源
当然,如果您遵循@M.S.B.的建议并使用数组语法符号,则可以避免越界数组访问。问题可能是OpenMP线程中没有足够的堆栈空间来保存所有这些数组的私有副本。特别是
d_coup
看起来像是一个非常大的,有3个natoms x nstates^2个元素。如今,大多数Fortran编译器会自动对如此大的数组使用堆分配,但当涉及到(first | last)private
变量时,一些OpenMP编译器,包括GCC和Intel Fortran编译器,总是将它们放在堆栈上。更多信息请参见我的答案
编辑:现在我看到M.S.B.在他的评论中实际上已经链接到了同一个问题。感谢您的关注和评论。我知道这不会有太大的性能提升。但我想知道为什么会出现错误,尤其是我在openmp中对常见变量所做的任何错误。另外,对于来自的信息,与原始数组表示法相比,f90数组表示法的性能有所下降。我怀疑使用数组表示法进行初始化会导致性能下降。编译器越来越好了。测量并找出。。。关于分段错误:可能是堆栈大小问题。请参见使用数组表示法时,例如,rv_avg(:)=0d0
,gfortran
如果赋值语句放置在OpenMP并行工作共享
构造中,则生成并行代码。但是,它不适用于向量赋值,例如,在工作共享结构中,仍然会导致串行进行赋值。