Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Segmentation fault 派生数据类型(Fortran)的MPI发送错误_Segmentation Fault_Fortran_Mpi - Fatal编程技术网

Segmentation fault 派生数据类型(Fortran)的MPI发送错误

Segmentation fault 派生数据类型(Fortran)的MPI发送错误,segmentation-fault,fortran,mpi,Segmentation Fault,Fortran,Mpi,当我尝试发送带有“大”数组的MPI派生数据类型(两个数组,每个数组有100000个浮点)时,我的程序会出错。不过,它通常使用较小的阵列运行 下面是一个可复制的小例子。 这个小程序使用以下MPI实现:IntelMPI、BullXMPI。 它与OpenMPI和PlatformMPI一起正常工作。 下面是一个带有示例回溯的日志: 将mpi发送更改为mpi发送没有帮助。然而,mpi_send使用一个较大的2*100000浮点数组就可以了。在我看来,这指向了派生数据类型的问题 program struct

当我尝试发送带有“大”数组的MPI派生数据类型(两个数组,每个数组有100000个浮点)时,我的程序会出错。不过,它通常使用较小的阵列运行

下面是一个可复制的小例子。 这个小程序使用以下MPI实现:IntelMPI、BullXMPI。 它与OpenMPI和PlatformMPI一起正常工作。 下面是一个带有示例回溯的日志:

将mpi发送更改为mpi发送没有帮助。然而,
mpi_send
使用一个较大的2*100000浮点数组就可以了。在我看来,这指向了派生数据类型的问题

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。我可以建议您使用调试器吗?我刚刚试过你的例子,两分钟后就发现了问题所在。你需要使用一个调试器——你的代码“看起来不错”,所以是时候观察它在实践中的表现了

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

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

首先,调用MPI_Get_address-来填充偏移量数组。看看那些偏移量!整数的地址是正的,而可分配数组的偏移量是负的:一个坏符号。地址已溢出

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

如果将此不正确的偏移量数组发送到MPI_send,它将从不应该读取的位置读取数据(再次查看偏移量缓冲区以使自己确信),因此会发生错误

真正的解决办法是--

  • 使用MPI_Get_address-使用整数(KIND=MPI_address_KIND)声明偏移量-确保64位代码获得64位整数

  • MPI_type_结构应替换为MPI_type_create_结构-前者已被弃用,并且不采用MPI_ADDRESS_KIND整数形式的偏移量,只有4字节整数-因此存在缺陷

  • 通过这些更改,您的代码可以运行


    祝你好运

    我不太懂Fortran,但我认为MPI不能在自定义数据类型中使用
    allocatable
    。您可以尝试将该构件与结构的其余部分分开传输。如果我错了,有人纠正我。静态数组不再有SEGFULTS!我用不同的编译器(gfortran、pgf90、ifortran)测试了代码,没有任何抱怨。在我开始增加尺寸之前没有任何问题。谢谢你非常详细的回答。我确实用DDT运行了代码,但没有激活内存调试。。。吸取教训!