0

当我使用 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 错误而终止。

4

1 回答 1

0

设备重启后未观察到此问题。即使我在相同的条件下同时运行了 4 个程序,也没有出现问题。此外,其他使用该设备的团队也出现了类似问题,重启后得到解决。结论有点可笑,但是如果有遇到类似问题的人,我想总结如下。

如果您的程序在读取或写入文件时由于内存错误(如 sigbus 和 sigsegv)而异常终止,您可以检查以下内容。

  • 确保您的程序中没有错误。检查错误发生的时间是恒定的还是不规则的,其他程序是否有相同的症状,在其他机器上是否运行良好,使用valgrind等内存错误检查工具运行时是否有问题。
  • 优化文件I/O部分。在 fortran 的情况下,处理整个数组比按元素处理快几十倍。
  • 出现错误后立即尝试ssh连接机器(或节点),检查连接是否顺畅,文件系统是否访问良好。如果您无法访问bashrc文件或出现文件句柄陈旧等错误,请结合以上审核信息与系统管理员联系。

如果有人有什么要补充的,或者这篇文章不合适,请告诉我。

于 2020-08-16T14:20:20.090 回答