Fortran MPI-IO:写入子阵列
我开始使用MPI-IO,并尝试编写一个非常简单的示例,说明我想用它做的事情;然而,尽管这是一个简单的代码,并且我从这里和那里阅读的示例中获得了一些灵感,但我还是发现了一个我不理解的分段错误 这段代码的逻辑非常简单:每个线程将处理一个本地数组,它是我要编写的globlal数组的一部分。我使用Fortran MPI-IO:写入子阵列,fortran,mpi,mpi-io,Fortran,Mpi,Mpi Io,我开始使用MPI-IO,并尝试编写一个非常简单的示例,说明我想用它做的事情;然而,尽管这是一个简单的代码,并且我从这里和那里阅读的示例中获得了一些灵感,但我还是发现了一个我不理解的分段错误 这段代码的逻辑非常简单:每个线程将处理一个本地数组,它是我要编写的globlal数组的一部分。我使用MPI\u type\u create\u subarray来创建子数组类型。然后我打开文件,设置一个视图并尝试写入数据。我在MPI\u文件\u Write\u All期间遇到分段错误 代码如下: progra
MPI\u type\u create\u subarray
来创建子数组类型。然后我打开文件,设置一个视图并尝试写入数据。我在MPI\u文件\u Write\u 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
任何帮助都将不胜感激 错误输出参数之前的
MPI\u FILE\u WRITE\u ALL
的最后一个参数是MPI状态对象,而不是MPI信息对象。因此,使用MPI\u INFO\u NULL
进行调用是错误的。如果您对写入操作的状态不感兴趣,则应通过MPI\u status\u IGNORE
。使用MPI\u INFO\u NULL
进行调用可能在某些MPI实现中有效,因为这两个常量的定义方式都很具体,但在其他MPI实现中可能会失败
例如,在Open MPIMPI\u INFO\u NULL
中声明为:
parameter (MPI_INFO_NULL=0)
当传递而不是MPI\u STATUS\u IGNORE
时,会导致调用MPI\u File\u write\u all
的C实现,其状态参数指向一个常量(只读)内存位置,该位置保存MPI\u INFO\u NULL
(Fortran如何实现按地址传递常量)。当C函数即将完成时,它尝试填充status对象,这导致尝试写入常量内存,最终导致分段错误
在编写新的Fortran程序时,建议不要使用非常旧的
mpif.h
接口,因为它不提供任何错误检查。相反,当更多的mpi实现与mpi-3.0兼容时,应该使用mpi
模块甚至mpi\u f08
。因此,您的计划的开始应该如下所示:
program test
use mpi
implicit none
...
end program test
使用mpi
模块而不是mpif.h
后,编译器可以对某些mpi调用执行参数类型检查,包括mpi\u FILE\u SET\u 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\u FILE\u SET\u VIEW
的第二个参数类型为INTEGER(KIND=MPI\u OFFSET\u KIND)
,在大多数现代平台上为64位。常量0
仅为INTEGER
类型,因此在大多数平台上为32位。发生的情况是,使用mpif.h
编译器传递一个指向值为0
的整数
常量的指针,但子例程将其解释为指向更大整数的指针,并将相邻值解释为常量值的一部分。因此,作为文件内部偏移量传递的零最终成为非零值
用0\u MPI\u OFFSET\u KIND
替换MPI\u FILE\u SET\u视图中的0
,或者声明一个类型为INTEGER(KIND=MPI\u OFFSET\u KIND)
的常量和一个值为零,然后传递它
call MPI_File_Set_View(fhandle, 0_MPI_OFFSET_KIND, MPI_DOUBLE_PRECISION, ...
或
这两种方法都会产生大小为3200字节的输出文件(如预期)。谢谢您的回答!然而,我仍然遇到一个严重的问题:编写的文件太大了,我现在还不知道为什么。如果你知道它为什么会这样…你找到输出文件如此巨大的原因了吗?除了被误用的MPI\u INFO\u NULL
,我在你的代码中找不到其他错误。不,这对我来说仍然是个奇迹。我想我会专门针对这个问题创建一个新问题,因为如果我使用MPI\u File\u Seek
而不是MPI\u File\u Set\u View
,它似乎可以正常工作。我想我已经解决了您的问题-请参阅更新的答案。太好了,谢谢!它解决了我的问题。不幸的是,我不能对你的答案投两次赞成票,否则我会投的。
integer(kind=MPI_OFFSET_KIND), parameter :: zero_off = 0
...
call MPI_File_Set_View(fhandle, zero_off, MPI_DOUBLE_PRECISION, ...