我正在使用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机器,结果相同,但都使用相同的配置,例如Windows 7与gfortran编译器。代码总是编译没有问题,但在运行时崩溃。
答案 0 :(得分:3)
OpenMP不会对可以实例化的数组大小施加任何限制。您的Fortran编译器可能;检查文档。
您正在使用的硬件确实施加了限制 - 您将无法在计算机上声明索引值大于HUGE(int)的阵列;因为HUGE(int)可能是(2 ^ 31)-1或(2 ^ 63)-1(Fortran没有无符号整数),所以这可能不会影响你。
可能影响您的另一个限制是,编译器允许您声明的变量大小可能存在限制。我不熟悉gfortran,但我建议你到谷歌或查看文档。可能是gfortran可以处理的堆栈大小有限制,在许多平台上,静态声明(即不可分配)的Fortran变量将放在堆栈上。我怀疑这是你问题的根源。
如果无法说服编译器让你在编译时声明一个更大的数组,请尝试使用数组ALLOCATABLE并在运行时分配它。
答案 1 :(得分:3)
在GNU Fortran中指定-fopenmp
意味着-frecursive
这意味着所有局部变量(甚至大型数组)都是自动的(即在堆栈上分配)。在Windows上,堆栈大小在PE可执行头文件中是固定的,必须在链接阶段指定,与Unix系统不同,它可以通过限制机制动态控制。
要增加Windows可执行文件的堆栈大小,可以使用Microsoft的editbin.exe
命令行,如:
editbin /STACK:<size> yourexe.exe
或向GCC提供以下选项:-Wl,--stack,<size in bytes>
,其中<size in bytes>
是所需的堆栈大小(以字节为单位)。您应该将堆栈大小设置为至少足以适合整个数组(即8*NUMLOOPS
)以及局部变量和东西。
答案 2 :(得分:2)
我遇到了同样的问题。据我所知,-fopenmp选项默认带有-frecursive。后者迫使大阵列成堆,这就是我们的问题。
伪解决方案是使用针对它的另一个选项覆盖-fopenmp隐含的-frecursive选项。为此,我为gfortran编译器选项
添加了选项-fno-automatic答案 3 :(得分:0)
与前一个解决方案相比,我有一个更好的解决方案,其中包括在运行代码之前插入以下cmd:ulimit -s unlimited
。这是为了摆脱默认的堆栈大小限制。