【发布时间】:2020-11-16 14:46:40
【问题描述】:
当我使用 mpirun 在 linux 集群上并行运行我的 fortran 代码时,我得到一个 sigbus 错误。 读取文件时出现,时间不规律,有时继续无误。 我已经尝试过调试编译选项,如 -g,但我没有得到任何关于错误来自哪一行的信息。 实际上,代码之前在三个不同的集群中执行过,没有出现这个错误,但这个错误只发生在这台机器上。 我个人怀疑这与机器的性能(尤其是存储 i/o)有关,但我不确定。
程序代码很简单。 mpirun 执行的每个进程都会读取其rank 对应的文件,如下所示。
!!!!!!!!!! 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
我已经按预期从终端获得了“GOOD”输出文本,但有问题的机器在运行 busread 时因 sigbus 错误而终止。
【问题讨论】:
-
欢迎您,请在网站周围转tour。一个节点有多少个进程?一个节点中的所有进程是否都读取一个文件?如果担心我们真的需要更多代码和具体示例,请参阅 How to Ask 和 minimal reproducible example。
-
您是否在打开所有运行时检查选项的情况下运行您的程序(可能是 -fcheck=all ,但那是 gfortran 的古老版本,所以我不能 100% 确定)
-
感谢 cmets。每个节点有 16 个线程,所以我每个节点使用 16 个进程。每个进程读取为进程号指定的每个文件,而不是节点号。我在文本中错误地写了节点号,但用进程号修复了它。很抱歉,我想附上实际的代码,但内容太庞大了,我试图只写相关部分作为示例。如上所述,此错误可能会或可能不会发生,具体取决于机器,因此我不确定它是否会有所帮助。另外,如果有什么我应该提供的,请告诉我。
-
对于编译选项,我使用了以下选项。 -fbounds-检查 -fbacktrace 。我愿意用其他选项对其进行测试,但我认为由于设施访问问题而无法立即进行。
-
无关注释:要将整数转换为3个字符的字符串,前导0,您可以写
write(cpunum,'(i3.3)') mype。
标签: fortran mpi gfortran openmpi sigbus