【问题标题】:OpenMP Crashing with Large Arrays大型数组导致 OpenMP 崩溃
【发布时间】:2012-05-03 10:22:51
【问题描述】:

我正在使用 Fortran 和 OpenMP,但是当我尝试使用 OpenMP 在有大型数组时并行化循环时,我一直遇到问题。例如以下代码:

PROGRAM main
IMPLICIT NONE   
INTEGER, PARAMETER :: NUMLOOPS = 300000
REAL(8) :: TESTMAT(NUMLOOPS)
INTEGER :: i,j

!$OMP PARALLEL SHARED(TESTMAT)
!$OMP DO
DO i=1,NUMLOOPS         
    TESTMAT(i) = i
END DO
!$OMP END DO
!$OMP END PARALLEL

write(*,*) SUM(TESTMAT)/(NUMLOOPS)

END PROGRAM main

使用这个 Makefile 编译:

.SUFFIXES: .f90

F90 = gfortran
FFLAGS_PFM = -ffree-form -ffree-line-length-none -fopenmp
LIB = -llapack
OBJ90 = main.o 

main: $(OBJ90)
    $(F90) $(FFLAGS_PFM) -o $@ $(LIB) $(OBJ90)

${OBJ90}: %.o: %.f90
    $(F90) $(FFLAGS_PFM) $(LIB) -c -o $@ $<

在使用 gfortran 编译的 windows 机器上时崩溃。但是,如果我将 NUMLOOPS 值更改为小于 260000 左右,程序运行得很好。同样,大约 1000x1000 的矩阵会崩溃(事实上,任何高于 500x500 的矩阵都不起作用)。因此,使用 OpenMP 时似乎允许最大数组大小?不过我还没有遇到过这种情况。我在多台 Windows 机器上尝试过,结果相同,但是都使用相同的配置,例如带有 gfortran 编译器的 Windows 7。代码总是编译没有问题,但运行时崩溃。

【问题讨论】:

    标签: fortran openmp fortran90 gfortran


    【解决方案1】:

    在 GNU Fortran 中指定 -fopenmp 意味着 -frecursive 这意味着所有局部变量(甚至是大型数组)都是自动的(即在堆栈上分配)。在 Windows 上,堆栈大小在 PE 可执行头文件中是固定的,并且必须在链接阶段指定,这与在 Unix 系统上可以通过限制机制动态控制非常不同。

    要增加 Windows 可执行文件的堆栈大小,您可以使用 Microsoft 的 editbin.exe 和如下命令行:

    editbin /STACK:<size> yourexe.exe
    

    或向 GCC 提供以下选项:-Wl,--stack,&lt;size in bytes&gt;,其中&lt;size in bytes&gt; 是所需的堆栈大小(以字节为单位)。您应该将堆栈大小设置为至少足以容纳整个数组(即8*NUMLOOPS)以及局部变量和其他内容。

    【讨论】:

      【解决方案2】:

      OpenMP 对您可以实例化的数组的大小没有任何限制。您的 Fortran 编译器可能会;检查文档。

      您使用的硬件确实施加了限制——您将无法在您的机器上声明索引值大于 HUGE(int) 的数组;因为 HUGE(int) 可能是 (2^31)-1 或 (2^63)-1(Fortran 没有无符号整数),所以目前这可能不会影响您。

      另一个可能会影响您的限制是,您的编译器允许您声明的变量的大小可能存在限制。我对 gfortran 不熟悉,但我建议您在 Google 周围搜索或查看文档。 gfortran 可以处理的堆栈大小可能存在限制,在许多平台上,静态声明的 Fortran 变量(即不是 ALLOCATABLE)将被放置在堆栈上。我怀疑这是你问题的根源。

      如果您无法说服编译器允许您在编译时声明更大的数组,请尝试使数组 ALLOCATABLE 并在运行时分配它。

      【讨论】:

      • 感谢您的回复。使 TESTMAT 可分配确实有效!但是,我仍然很好奇为什么会发生这种情况。我想我忘了提到如果我删除 OpenMP 位,即 OMP 声明和 makefile 中的 -fopenmp 标志,上面的代码可以工作,所以行为似乎特定于 gfortran+openmp。但无论哪种方式,向前迈出一步,再次感谢!
      • 可能是,在 OpenMP 版本中,编译器将数组放在堆栈上而不是可执行文件中的静态位置,在这种情况下,您也可以通过不限制堆栈大小来解决问题,通常通过“ulimit -s unlimited”来实现。
      【解决方案3】:

      我遇到了同样的问题。据我了解,-fopenmp 选项默认带有-frecursive。后者迫使大型阵列位于堆栈中,这就是我们的问题。

      伪解决方案是使用另一个选项覆盖 -fopenmp 隐含的 -frecursive 选项。为此,我为 gfortran 编译器选项添加了选项 -fno-automatic

      【讨论】:

        【解决方案4】:

        与我之前的解决方案相比,我有一个更好的解决方案,即在运行代码之前插入以下 cmd:ulimit -s unlimited。这是为了摆脱对堆栈大小的默认限制。

        【讨论】:

          猜你喜欢
          • 2015-06-23
          • 1970-01-01
          • 1970-01-01
          • 2019-01-01
          • 2015-11-01
          • 2011-07-05
          • 2021-05-11
          • 1970-01-01
          • 2015-02-15
          相关资源
          最近更新 更多