我正在尝试修改遗留代码以使用openmp初始化数组。但是,在以下代码部分中启用$ OMP DO衍生时遇到Segmentation fault。你能指出可能有什么问题吗?
我正在使用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 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
答案 0 :(得分:0)
您是否测量过程序中的CPU消耗量?加速不耗费大量CPU时间的部分是浪费精力。如果数组初始化占CPU使用率的很大一部分,我会感到惊讶。如果您使用数组表示法,例如rv_avg (0:nstates - 1) = 0d0
,则代码将更具可读性。
答案 1 :(得分:0)
您尚未显示任何数组尺寸的声明,因此我推测这些行
do m = 0, nstates - 1
rv_avg(m) = 0d0
写入rv_avg
的不存在元素,即索引0
的元素。由于Fortran程序默认情况下不检查数组元素访问是否在边界内,因此运行时不会捕获边界外的写入。如果写入在执行时保持在程序的地址空间内,则不会导致分段错误。给定公共块声明,0
的{{1}}元素可能是rv_avg
的一部分。
通过引入OpenMP来调整变量到地址空间的映射,并且很容易相信d_coup
的{{1}}元素现在位于线程的地址空间之外并导致分段错误
由于程序在0
处对数组元素进行了其他引用,因此它们中的任何一个都可能是分段错误的根源。
当然,如果你遵循@ M.S.B.的建议并使用数组语法表示法,你可以避免越界数组访问。
答案 2 :(得分:0)
问题可能是您在OpenMP线程中没有足够的堆栈空间来容纳所有这些数组的私有副本。特别是d_coup
看起来像一个非常大的3 x natoms x nstates^2
元素。现在大多数Fortran编译器会自动使用堆分配来处理大型数组,但是当涉及到(first|last)private
个变量时,一些OpenMP编译器(包括GCC和Intel Fortran编译器)总是将它们放在堆栈中。有关详细信息,请参阅我的回答here。
编辑:现在我看到M. S. B.在评论中实际上与同一个问题有关。