MBR*_*MBR 4 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
Run Code Online (Sandbox Code Playgroud)
任何帮助将非常感谢!
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)
Run Code Online (Sandbox Code Playgroud)
当传递而不是MPI_STATUS_IGNORE它导致MPI_File_write_all调用C实现时,status参数指向一个常量(只读)内存位置,该内存位置保存MPI_INFO_NULL(Fortran如何通过地址实现传递常量).当C函数即将完成时,它会尝试填充状态对象,这会导致尝试写入常量内存并最终导致分段错误.
在编写新的Fortran程序时,建议不要使用非常旧的mpif.h接口,因为它不提供任何错误检查.相反,应该使用该mpi模块,或者甚至mpi_f08当更多MPI实现变得符合MPI-3.0时.因此,程序的开头应如下所示:
program test
use mpi
implicit none
...
end program test
Run Code Online (Sandbox Code Playgroud)
一旦您使用mpi模块而不是mpif.h,编译器就能够对某些MPI调用执行参数类型检查,包括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)
Run Code Online (Sandbox Code Playgroud)
原因是第二个参数MPI_FILE_SET_VIEW是类型的INTEGER(KIND=MPI_OFFSET_KIND),在大多数现代平台上是64位.常量0只是类型INTEGER,因此在大多数平台上都是32位.发生的事情是,mpif.h编译器将指针传递给INTEGER值为的常量0,但子例程将其解释为指向较大整数的指针,并将相邻值解释为常量值的一部分.因此,作为文件中的偏移量传递的零最终为非零值.
替换0在MPI_FILE_SET_VIEW呼叫与0_MPI_OFFSET_KIND或声明类型的恒定INTEGER(KIND=MPI_OFFSET_KIND)和零值,然后把它传递.
call MPI_File_Set_View(fhandle, 0_MPI_OFFSET_KIND, MPI_DOUBLE_PRECISION, ...
Run Code Online (Sandbox Code Playgroud)
要么
integer(kind=MPI_OFFSET_KIND), parameter :: zero_off = 0
...
call MPI_File_Set_View(fhandle, zero_off, MPI_DOUBLE_PRECISION, ...
Run Code Online (Sandbox Code Playgroud)
这两种方法都会导致大小为3200字节的输出文件(如预期的那样).