【问题标题】:MPI send error with derived data type (Fortran)派生数据类型的 MPI 发送错误 (Fortran)
【发布时间】:2012-10-24 02:25:57
【问题描述】:

当我尝试使用“大”数组(2 个数组,每个数组包含 100 000 个浮点数)发送 MPI 派生数据类型时,我的程序会出现段错误。不过,它可以正常运行较小的数组。

下面是一个可重现的小例子。 这个小程序使用以下 MPI 实现出现段错误:IntelMPIBullXMPI。 它与 OpenMPIPlatformMPI 一起正常工作。 这是一个带有示例回溯的日志:http://pastebin.com/FMBpCuj2

mpi_send 更改为mpi_ssend 没有帮助。但是,mpi_send 带有一个更大的 2*100 000 浮点数组可以正常工作。在我看来,这表明派生数据类型存在问题。

program struct 
include 'mpif.h' 

type Data
  integer :: id
  real, allocatable :: ratio(:)
  real, allocatable :: winds(:)
end type 

type (Data) :: test
integer :: datatype, oldtypes(3), blockcounts(3) 
integer :: offsets(3)
integer :: numtasks, rank, i,  ierr 
integer :: n, status(mpi_status_size)

call mpi_init(ierr) 
call mpi_comm_rank(mpi_comm_world, rank, ierr) 
call mpi_comm_size(mpi_comm_world, numtasks, ierr) 

if (numtasks /= 2) then
  write (*,*) "Needs 2 procs"
  call exit(1)
endif

n = 100000
allocate(test%ratio(n))
allocate(test%winds(n))
if (rank == 0) then
  test%ratio = 6
  test%winds = 7
  test%id = 2
else
  test%id = 0
  test%ratio = 0
  test%winds = 0
endif

call mpi_get_address(test%id, offsets(1), ierr)
call mpi_get_address(test%ratio, offsets(2), ierr)
call mpi_get_address(test%winds, offsets(3), ierr)

do i = 2, size(offsets)
  offsets(i) = offsets(i) - offsets(1)
end do
offsets(1) = 0

oldtypes = (/mpi_integer, mpi_real, mpi_real/)
blockcounts = (/1, n, n/)

call mpi_type_struct(3, blockcounts, offsets, oldtypes, datatype, ierr) 
call mpi_type_commit(datatype, ierr) 

if (rank == 0) then 
  !call mpi_ssend(test, 1, datatype, 1, 0,  mpi_comm_world, ierr) 
  call mpi_send(test, 1, datatype, 1, 0,  mpi_comm_world, ierr) 
else
  call mpi_recv(test, 1, datatype, 0, 0,  mpi_comm_world, status, ierr) 
end if

print *, 'rank= ',rank
print *, 'data= ',test%ratio(1:5),test%winds(1:5)

deallocate (test%ratio)
deallocate (test%winds)
call mpi_finalize(ierr) 


end 

注意:不同 MPI 实现之间的比较并不客观,因为测试并非都在同一台机器上(其中一些是超级计算机)。不过,我认为这不会有什么不同。

编辑:该代码适用于静态数组。这是 Fortran 90。

【问题讨论】:

  • 我对 Fortran 了解不多,但我认为 MPI 在自定义数据类型中不能与 allocatable 一起使用。您可以尝试将该组件与结构的其余部分分开传输。如果我错了,请有人纠正我。
  • 静态数组不再出现段错误!我用不同的编译器(gfortran、pgf90、ifortran)测试了代码,没有任何抱怨。在我开始增加尺寸之前没有任何问题。

标签: segmentation-fault fortran mpi


【解决方案1】:

我可以建议您使用调试器吗?我刚刚在Allinea DDT 中尝试了您的示例,并在两分钟内看到了问题。您需要使用调试器 - 您的代码“看起来不错”,因此是时候观察它在实践中的表现了。

我单击打开内存调试(一种强制显示一些隐藏错误的方法),然后您的示例每次都与 OpenMPI 一起崩溃。崩溃发生在发件人身上。

所以,我开始逐步使用 DDT - 打开 DDT 的内存调试。

首先,您调用 MPI_Get_address - 填充偏移量数组。看看那些偏移量!整数的地址是正数,可分配数组的偏移量是负数:这是一个不好的迹象。地址已溢出。

已分配数据的地址将位于与静态分配的整数非常不同的内存区域中。如果您使用 32 位算术来操作 64 位指针(MPI_Get_address 对此发出警告),则所有赌注都将失败。对于静态数组,它不会崩溃,因为它们的地址足够接近整数的地址而不会溢出。

您将这个不正确的偏移数组发送到 MPI_Send,它会从不应该读取的位置读取数据(再次查看偏移缓冲区以说服自己)并因此产生段错误。

真正的解决办法是——

  1. 使用 MPI_Get_address - 使用 INTEGER(KIND=MPI_ADDRESS_KIND) 声明偏移量 - 确保 64 位代码获得 64 位整数。

  2. 应将 MPI_type_struct 替换为 MPI_type_create_struct - 前者已弃用,并且不采用 MPI_ADDRESS_KIND 整数形式的偏移量,只有 4 字节整数 - 因此存在缺陷。

通过这些更改,您的代码将运行。

祝你好运!

【讨论】:

  • 感谢您非常详细的回答。我确实使用 DDT 运行了代码,但没有激活内存调试... 经验教训!
猜你喜欢
  • 2013-09-20
  • 1970-01-01
  • 2012-11-27
  • 2018-11-15
  • 2012-02-11
  • 2019-01-20
  • 2017-08-12
  • 2012-02-03
相关资源
最近更新 更多