启用$ OMP DO循环时出现分段错误

时间:2013-12-01 01:09:42

标签: fortran openmp

我正在尝试修改遗留代码以使用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

3 个答案:

答案 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.在评论中实际上与同一个问题有关。