2

我正在使用 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。代码总是编译没有问题,但运行时崩溃。

4

4 回答 4

4

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

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

editbin /STACK:<size> yourexe.exe

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

于 2012-05-04T12:15:17.883 回答
3

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

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

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

如果你不能说服你的编译器让你在编译时声明一个更大的数组,请尝试使数组 ALLOCATABLE 并在运行时分配它。

于 2012-04-22T17:40:00.617 回答
3

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

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

于 2015-08-10T16:48:13.030 回答
0

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

于 2019-08-08T12:56:54.610 回答