2012-11-03 51 views
1

当我尝试发送MPI派生数据类型与“大”数组(每个100 000浮点数2阵列),我的程序段错误。它通常与较小的阵列运行。MPI发送错误与派生数据类型(Fortran)

下面是一个小的可重复的例子。 这个小程序段错误与以下MPI执行:IntelMPI,BullXMPI。 它的工作原理与OpenMPIPlatformMPI。 这里是一个带回溯示例的日志:http://pastebin.com/FMBpCuj2

更改mpi_sendmpi_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 implentations之间的比较是不客观的测试是不是所有在同一台计算机(其中有些是超级计算机)上。不过,我认为这不应该有所作为。

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

+0

我不知道很多的Fortran,但我不认为MPI工作与自定义数据类型'allocatable'。您可以尝试从该结构的其余部分分开转移该组件。有人纠正我,如果我错了。 –

+0

没有更多的段错误与静态数组!我用不同的编译器(gfortran,pgf90,ifortran)测试了代码,没有任何抱怨。直到我开始增加尺寸时才有问题。 –

回答

6

我可以建议你使用调试器吗?我只是在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个字节的整数 - 因此存在缺陷。

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

祝你好运!

+0

感谢您提供非常详细的答案。我确实用DDT运行代码,但没有激活内存调试...经验教训! –