MPI-IO:写子阵列

时间:2013-07-29 14:08:48

标签: fortran mpi mpi-io

我开始使用MPI-IO并尝试写一个非常简单的例子,说明我想用它做什么;然而,即使它是一个简单的代码,我从这里和那里的例子中获得了一些灵感,我得到了一个我不明白的分段错误。

这段代码的逻辑非常简单:每个线程都将处理一个本地数组,该数组是我想写的全局数组的一部分。我使用MPI_Type_Create_Subarray创建了一个子阵列类型。然后我只是打开文件,设置视图并尝试写入数据。我在MPI_File_Write_All期间得到了分段错误。

以下是代码:

program test
  implicit none

  include "mpif.h"

  integer :: myrank, nproc, fhandle, ierr
  integer :: xpos, ypos
  integer, parameter :: loc_x=10, loc_y=10
  integer :: loc_dim
  integer :: nx=2, ny=2
  real(8), dimension(loc_x, loc_y) :: data
  integer :: written_arr
  integer, dimension(2) :: wa_size, wa_subsize, wa_start

  call MPI_Init(ierr)
  call MPI_Comm_Rank(MPI_COMM_WORLD, myrank, ierr)
  call MPI_Comm_Size(MPI_COMM_WORLD, nproc, ierr)

  xpos = mod(myrank, nx)
  ypos = mod(myrank/nx, ny)

  data = myrank

  loc_dim    = loc_x*loc_y
  wa_size    = (/ nx*loc_x, ny*loc_y /)
  wa_subsize = (/ loc_x, loc_y /)
  wa_start   = (/ xpos, ypos /)*wa_subsize
  call MPI_Type_Create_Subarray(2, wa_size, wa_subsize, wa_start &
       , MPI_ORDER_FORTRAN, MPI_DOUBLE_PRECISION, written_arr, ierr)
  call MPI_Type_Commit(written_arr, ierr)

  call MPI_File_Open(MPI_COMM_WORLD, "file.dat" &
       & , MPI_MODE_WRONLY + MPI_MODE_CREATE, MPI_INFO_NULL, fhandle, ierr)
  call MPI_File_Set_View(fhandle, 0, MPI_DOUBLE_PRECISION, written_arr &
       , "native", MPI_INFO_NULL, ierr)
  call MPI_File_Write_All(fhandle, data, loc_dim, MPI_DOUBLE_PRECISION &
       , MPI_INFO_NULL, ierr)
  call MPI_File_Close(fhandle, ierr)

  call MPI_Finalize(ierr)

end program test

任何帮助都将受到高度赞赏!

1 个答案:

答案 0 :(得分:6)

错误输出参数之前MPI_FILE_WRITE_ALL的最后一个参数是MPI状态对象而不是MPI信息对象。因此,使用MPI_INFO_NULL拨打电话是错误的。如果您对写操作的状态不感兴趣,那么您应该通过MPI_STATUS_IGNORE。使用MPI_INFO_NULL进行调用可能在某些MPI实现中有效,因为两个常量的定义方式都有,但在其他常量中失败。

例如,在Open MPI MPI_INFO_NULL中声明为:

parameter (MPI_INFO_NULL=0)

当传递而不是MPI_STATUS_IGNORE时,它会导致MPI_File_write_all的C实现被调用,而status参数指向一个保持{{1}值的常量(只读)内存位置(Fortran如何通过地址实现传递常量)。当C函数即将完成时,它会尝试填充状态对象,这会导致尝试写入常量内存并最终导致分段错误。


编写新的Fortran程序时,建议不要使用非常旧的MPI_INFO_NULL接口,因为它不提供任何错误检查。相反,当更多MPI实现符合MPI-3.0标准时,应该使用mpif.h模块甚至mpi。因此,程序的开头应如下所示:

mpi_f08

使用program test use mpi implicit none ... end program test 模块而不是mpi后,编译器可以对某些MPI调用执行参数类型检查,包括mpif.h,并发现错误:

MPI_FILE_SET_VIEW

原因是test.f90(34): error #6285: There is no matching specific subroutine for this generic subroutine call. [MPI_FILE_SET_VIEW] call MPI_File_Set_View(fhandle, 0, MPI_DOUBLE_PRECISION, written_arr & -------^ compilation aborted for test.f90 (code 1) 的第二个参数是MPI_FILE_SET_VIEW类型,在大多数现代平台上都是64位。常量INTEGER(KIND=MPI_OFFSET_KIND)只是类型0,因此在大多数平台上都是32位。会发生的是INTEGER,编译器将指针传递给值为mpif.h的{​​{1}}常量,但子例程将其解释为指向更大整数的指针,并将相邻值解释为恒定值的一部分。因此,作为文件中的偏移量传递的零结果为非零值。

INTEGER调用中的0替换为0,或者声明类型为MPI_FILE_SET_VIEW的常量且值为零,然后传递它。

0_MPI_OFFSET_KIND

INTEGER(KIND=MPI_OFFSET_KIND)

两种方法都会产生大小为3200字节的输出文件(如预期的那样)。