Fortran中MPI_FINALIZE()期间的分段错误

时间:2012-07-19 16:12:13

标签: segmentation-fault fortran mpi fortran90 memory-management

在Fortran 90程序中调用MPI_FINALIZE()期间,我遇到了分段错误。虽然代码非常广泛,但我将发布伪代码并查看它是否会引发任何标志。我有预感(但还没有尝试过),它可能可能是由于不解除分配数组引起的?但是我不确定 - 在调用MPI_FINALIZE期间,Fortran 90中的数组无法解除分配会导致分段错误吗?

if(<rank 0>) then
  do iat = 1,natoms
    do il = 0, LMAX
      do im = -il,il
        <mpi_recv "rank_rdy"> ! find out which rank is ready for (at,l,m)
        <mpi_send "(iat,il,im)"> ! send (at,l,m) to the rank asking for it
      enddo
    enddo
  enddo
else ! other ranks send a 'ready' signal and recieve the (at,l,m) to optimize
  if(<rank 0 is not finished processing (at,l,m)'s>)
    <mpi_send "my_rank"> ! tell rank 0 that i am ready to receive
    <mpi_recv "(iat,il,im)"> ! recieve (at,l,m) from rank 0
    call optimize(iat,il,im) ! do work on (at,l,m)
  endif
endif

if(<rank 0>)
  <read temp files created by other ranks>
  <write temp files to one master file>
endif

print*, 'calling finalize'

call MPI_BARRIER(MPI_COMM_WORLD, ierr)
call MPI_FINALIZE()

现在在输出中,除了与此问题无关的其他信息之外,我得到以下内容:

 calling finalize
 calling finalize
 calling finalize
 calling finalize
 calling finalize
 calling finalize

=====================================================================================
=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   EXIT CODE: 11
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
=====================================================================================
APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)

即使我不打电话MPI_BARRIER,我也会遇到同样的问题,但我认为这可能会有所帮助。请注意,每个级别都使用的数组我不打算解除分配,因为我在整个程序中使用它们所以我不担心内存泄漏或任何其他问题。由于MPI_FINALIZE()被调用而没有释放内存,是否可能发生此段错误?

我将自己更多地探讨这个问题,但我想发布这个问题有几个原因:

  1. 调用MPI_FINALIZE()

    时,想知道这是否是一个已知问题
  2. 在调用MPI_FINALIZE()时,想知道为什么会发生这种情况(如果实际上是问题)。在内部,发生了什么导致了这个段错误?

  3. 我在网上搜索得很高,没有发现这个问题,所以对后人来说,这可能是一个很好的问题,可以在网上回答。

  4. 编辑:我忘记提及此问题,但在串行运行时无法复制此问题。显然,我没有按顺序分发(at,l,m)。唯一的过程只是遍历所有组合并逐一优化它们。我,但是释放我认为可能导致MPI问题的数组,我仍然没有得到段错误。

1 个答案:

答案 0 :(得分:4)

如果可用,应始终使用Fortran 90 MPI接口,而不是旧的FORTRAN 77接口。那就是你应该总是

USE mpi

而不是

INCLUDE 'mpif.h'

两者之间的区别在于Fortran 90接口将所有MPI子例程放在一个模块中,因此生成了显式接口。这允许编译器在调用中进行参数检查并发出错误信号,例如:省略一个论点。

在Fortran的调用约定中,所有参数都通过地址传递,而不管其类型如何。这允许编译器生成对函数和子例程的正确调用,而不需要像C中那样的原型。但是这也意味着可以自由地传递INTEGER参数,其中REAL数组是预期的,几乎全部FORTRAN 77编译器将很乐意编译这样的代码,或者可以传递比预期更少/更多的参数。有一些外部工具,通常用C工具lint的名称称为 linters ,它解析整个源代码树并可以查明这些错误以及编译器无需查找的许多其他错误。为Fortran执行此类静态代码分析的一个此类工具是flint。 Fortran 90添加了接口以补偿Fortran的这种易出错的特性。

调用具有比预期更少的参数的Fortran子例程可能会有许多不同的不良影响,具体取决于体系结构,但在大多数情况下会导致崩溃,尤其是如果省略的参数是输出的。被调用的函数不知道传递的参数较少 - 它只是查看其地址应该的位置,并获取它在那里找到的任何地址。由于ierr是输出参数,因此会在该地址处写入。地址很可能不会指向与映射内存对应的虚拟地址,并且操作系统会提供大量的分段错误。即使地址指向用户分配的内存中的某个位置,结果也可能是某些控制结构中重要值的覆盖。如果即使这样也没有发生,那么就存在调用约定,其中被调用者清理堆栈帧 - 在这种情况下,堆栈指针将被错误地递增,并且返回地址将与正确的地址完全不同,这几乎是肯定会导致跳转到不可执行(甚至非映射)的内存,并再次跳转到分段错误。