当我使用 mpirun 在 linux 集群上并行运行我的 fortran 代码时,出现 sigbus 错误。读取文件时出现,时间不规律,有时继续无误。我已经尝试过调试编译选项,如 -g,但我没有得到任何关于错误来自哪一行的信息。实际上,代码之前在三个不同的集群中执行过,没有出现这个错误,但这个错误只发生在这台机器上。我个人怀疑这与机器的性能(尤其是存储 i/o)有关,但我不确定。
程序代码很简单。mpirun 执行的每个进程都会读取与其等级对应的文件,如下所示。
!!!!!!!!!! start of code
OPEN(11, FILE='FILE_NAME_WITH_RANK', FORM='UNFORMATTED')
READ(11,*) ISIZE
ALLOCATE(SOME_VARIABLE(ISIZE))
DO I = 1, ISIZE
READ(11,*) SOME_VARIABLE(I)
ENDDO
READ(11,*) ISIZE2
ALLOCATE(SOME_VARIABLE2(ISIZE2))
DO I = 1, ISIZE2
READ(11,*) SOME_VARIABLE2(I)
ENDDO
! MORE VARIABLES
CLOSE(11)
!!!!!!!!!! end of code
我使用了 191 个 cpu,它加载的 191 个文件的总大小约为 11 GB。
用于执行的集群由 24 个节点组成,每个节点有 16 个 cpu(总共 384 个 cpu),并使用与另一个集群共享的公共存储。我通过将节点 1 到 12 指定为主机文件来并行运行代码。
最初,我有 191 个 CPU 无序地同时读取所有文件。这样做之后,程序以 sigbus 错误结束。此外,对于某些节点,ssh 连接被延迟,并且节点无法找到 bashrc 文件并出现 stale file handle 错误。陈旧的文件句柄错误稍等片刻,它似乎自行恢复,但我不确定系统管理员做了什么。因此,我将其更改为以下代码,以便一次只有一个 cpu 可以读取文件。
!!!!!!!!!! start of code
DO ICPU = 0, NUMBER_OF_PROCESS-1
IF(ICPU.EQ.MY_PROCESS) CALL READ_FILE
CALL MPI_BARRIER(MPI_COMMUNICATOR,IERR)
ENDDO
!!!!!!!!!! end of code
这对于单次执行似乎工作正常,但如果我同时运行多个这些程序,第一个 mpirun 停止并且最终都以 sigbus 错误结束。
我的下一个尝试是通过在读取数组时删除 do 语句来最小化 read 语句的执行。但是,由于时间有限,我无法测试此修改的有效性。
以下是一些附加信息。
- 如果我在运行并行程序时使用 nautilus 等资源管理器执行搜索或复制文件,则 nautilus 没有响应或正在运行的程序引发 sigbus。在严重的情况下,我无法连接具有陈旧文件句柄错误的 VNC 服务器。
- 我使用 OpenMPI 2.1.1、GNU Fortran 4.9.4。我使用以下 $OPENMPIHOME/bin/mpif90 -mcmodel=large -fmax-stack-var-size-64 -cpp -O3 $SOURCE -o $EXE 编译程序我在 gnome 终端 $OPENMPIHOME/bin/ 中执行以下程序mpirun -np $NP -x $LD_LIBRARY_PATH --hostfile $HOSTFILE $EXE
- 据说该集群可以毫无问题地运行 FLUENT 等商业软件。
综上所述,我个人的怀疑是我的代码产生了过多的磁盘I/O导致集群的存储被卸载了,但是我不知道这是否有意义,因为我没有集群知识。如果是,我想知道是否有一种方法可以最小化磁盘 I/O,是否足以继续上面提到的矢量化 I/O,或者是否有额外的部分。如果您能告诉我有关此问题的任何信息,我将不胜感激。提前致谢。
!!!我写了一个示例代码。如上所述,可能不容易重现,因为发生情况因机器而异。
PROGRAM BUSWRITE
IMPLICIT NONE
INTEGER, PARAMETER :: ISIZE1 = 10000, ISIZE2 = 20000, ISIZE3 = 30000
DOUBLE PRECISION, ALLOCATABLE :: ARRAY1(:), ARRAY2(:), ARRAY3(:)
INTEGER :: I
INTEGER :: I1, I2, I3
CHARACTER*3 CPUNUM
INCLUDE 'mpif.h'
INTEGER ISTATUS(MPI_STATUS_SIZE)
INTEGER :: IERR, NPES, MYPE
CALL MPI_INIT(IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NPES,IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,MYPE,IERR)
I1=MOD(MYPE/100,10)+48
I2=MOD(MYPE/10 ,10)+48
I3=MOD(MYPE ,10)+48
CPUNUM=CHAR(I1)//CHAR(I2)//CHAR(I3)
OPEN(11, FILE=CPUNUM//'.DAT', FORM='UNFORMATTED')
ALLOCATE(ARRAY1(ISIZE1))
ALLOCATE(ARRAY2(ISIZE2))
ALLOCATE(ARRAY3(ISIZE3))
DO I = 1, ISIZE1
ARRAY1(I) = I
WRITE(11) ARRAY1(I)
ENDDO
DO I = 1, ISIZE2
ARRAY2(I) = I**2
WRITE(11) ARRAY2(I)
ENDDO
DO I = 1, ISIZE3
ARRAY3(I) = I**3
WRITE(11) ARRAY3(I)
ENDDO
CLOSE(11)
CALL MPI_FINALIZE(IERR)
END PROGRAM
mpif90 -ffree-line-length-0 ./buswrite.f90 -o ./buswrite
mpirun -np 32 ./buswrite
我有 32 000.DAT ~ 031.DAT
PROGRAM BUSREAD
IMPLICIT NONE
INTEGER, PARAMETER :: ISIZE1 = 10000, ISIZE2 = 20000, ISIZE3 = 30000
DOUBLE PRECISION, ALLOCATABLE :: ARRAY1(:), ARRAY2(:), ARRAY3(:)
INTEGER :: I
INTEGER :: I1, I2, I3
CHARACTER*3 CPUNUM
INCLUDE 'mpif.h'
INTEGER ISTATUS(MPI_STATUS_SIZE)
INTEGER :: IERR, NPES, MYPE
CALL MPI_INIT(IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NPES,IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,MYPE,IERR)
I1=MOD(MYPE/100,10)+48
I2=MOD(MYPE/10 ,10)+48
I3=MOD(MYPE ,10)+48
CPUNUM=CHAR(I1)//CHAR(I2)//CHAR(I3)
OPEN(11, FILE=CPUNUM//'.DAT', FORM='UNFORMATTED')
ALLOCATE(ARRAY1(ISIZE1))
ALLOCATE(ARRAY2(ISIZE2))
ALLOCATE(ARRAY3(ISIZE3))
DO I = 1, ISIZE1
READ(11) ARRAY1(I)
IF(ARRAY1(I).NE.I) STOP
ENDDO
DO I = 1, ISIZE2
READ(11) ARRAY2(I)
IF(ARRAY2(I).NE.I**2) STOP
ENDDO
DO I = 1, ISIZE3
READ(11) ARRAY3(I)
IF(ARRAY3(I).NE.I**3) STOP
ENDDO
CLOSE(11)
CALL MPI_BARRIER(MPI_COMM_WORLD,IERR)
IF(MYPE.EQ.0) WRITE(*,*) 'GOOD'
CALL MPI_FINALIZE(IERR)
END PROGRAM
mpif90 -ffree-line-length-0 ./busread.f90 -o ./busread
mpirun -np 32 ./busread
正如预期的那样,我从终端得到了“好”的输出文本,但是有问题的机器在运行 busread 时因 sigbus 错误而终止。