MPI 非阻塞发送/接收中的请求数组
Posted
技术标签:
【中文标题】MPI 非阻塞发送/接收中的请求数组【英文标题】:request array in MPI non-blocking send/recv 【发布时间】:2014-08-15 05:41:50 【问题描述】:我正在尝试在 Fortran 中重现 this C 示例。到目前为止我的代码:
use mpi
implicit none
integer, parameter :: maxn = 8
integer, allocatable :: xlocal(:,:)
integer :: i, j, lsize, errcnt, toterr, buff
integer :: ierror, nproc, pid, root = 0, nreq = 0
integer, allocatable :: request(:), status(:,:)
call MPI_INIT(ierror)
call MPI_COMM_SIZE(MPI_COMM_WORLD, nproc, ierror)
call MPI_COMM_RANK(MPI_COMM_WORLD, pid, ierror)
if (mod(maxn, nproc) /= 0) then
write(*,*) 'Array size (maxn) should be a multiple of the number of processes'
call MPI_ABORT(MPI_COMM_WORLD, 1, ierror)
end if
lsize = maxn/nproc
allocate(xlocal(0:lsize+1, maxn))
allocate(request(nproc))
allocate(status(MPI_STATUS_SIZE,nproc))
xlocal(0,:) = -1
xlocal(1:lsize,:) = pid
xlocal(lsize+1,:) = -1
! send down unless on bottom
if (pid < nproc-1) then
nreq = nreq + 1
call MPI_ISEND(xlocal(lsize,:), maxn, MPI_INTEGER, &
pid+1, 0, MPI_COMM_WORLD, request(nreq), ierror)
write(*,'(2(A,I1),A)') 'process ', pid, ' sent to process ', pid+1, ':'
write(*,*) xlocal(lsize,:)
end if
if (pid > 0) then
nreq = nreq + 1
call MPI_IRECV(xlocal(0,:), maxn, MPI_INTEGER, &
pid-1, 0, MPI_COMM_WORLD, request(nreq), ierror)
write(*,'(2(A,I1),A)') 'process ', pid, ' received from process ', pid-1, ':'
write(*,*) xlocal(0,:)
end if
! send up unless on top
if (pid > 0) then
nreq = nreq + 1
call MPI_ISEND(xlocal(1,:), maxn, MPI_INTEGER, &
pid-1, 1, MPI_COMM_WORLD, request(nreq), ierror)
write(*,'(2(A,I1),A)') 'process ', pid, ' sent to process ', pid-1, ':'
write(*,*) xlocal(1,:)
end if
if (pid < nproc-1) then
nreq = nreq + 1
call MPI_IRECV(xlocal(lsize+1,:), maxn, MPI_INTEGER, &
pid+1, 1, MPI_COMM_WORLD, request(nreq), ierror)
write(*,'(2(A,I1),A)') 'process ', pid, ' received from process ', pid+1, ':'
write(*,*) xlocal(lsize+1,:)
end if
call MPI_WAITALL(nreq, request, status, ierror)
! check results
errcnt = 0
do i = 1, lsize
do j = 1, maxn
if (xlocal(i,j) /= pid) errcnt = errcnt + 1
end do
end do
do j = 1, maxn
if (xlocal(0,j) /= pid-1) errcnt = errcnt + 1
if ((pid < nproc-1) .and. (xlocal(lsize+1,j) /= pid+1)) errcnt = errcnt + 1
end do
call MPI_REDUCE(errcnt, toterr, 1, MPI_INTEGER, MPI_SUM, 0, MPI_COMM_WORLD)
if (pid == root) then
if (toterr == 0) then
write(*,*) "no errors found"
else
write(*,*) "found ", toterr, " errors"
end if
end if
deallocate(xlocal)
deallocate(request)
deallocate(status)
call MPI_FINALIZE(ierror)
但我遇到了分段错误,无法弄清楚原因。我有一种感觉是由于请求数组。有人可以解释在 Fortran 中使用请求数组的正确方法吗?我找到的任何参考资料都没有说明这一点。
提前谢谢
【问题讨论】:
【参考方案1】:如果您还没有这样做,请考虑使用一些有助于调试的标志来编译您的程序,例如对于gfortran
,您可以使用-O0 -g -fbounds-check
(如果这没有帮助,您可以为版本>= 4.8 添加-fsanitize=address
)。其他编译器也有类似的调试选项。
这样做并使用 2 个进程运行,您的程序会在 MPI_Reduce
行崩溃。如果您查看规范(例如OpenMPI 1.8),您会发现此子例程需要一个参数,即您忘记在末尾添加ierror
参数。
有点可悲的是,即使 mpi 模块中的子程序可以通过 use
关联访问,因此应该检查参数一致性以避免这些微不足道的错误,但并非所有子程序都必须在该模块中。我不知道您使用哪种 MPI 实现,但我检查了我的本地 MPICH 安装,它在模块中没有大多数子例程,因此它们不存在显式接口。我猜您处于类似的情况,但我猜其他实现可能会遭受类似的命运。您可以将其与缺少 MPI_Reduce
的函数原型的 C 头文件进行比较。我猜这是因为最初大多数实现只有一个 Fortran 77 接口。
一些最终的 cmets:注意不要只是复制粘贴 C 代码。您传递的数组不是连续的,并且会导致将临时副本传递给 MPI 例程,这是非常低效的(在这种情况下并不重要)。
【讨论】:
感谢答案和旗帜上的提示,以及数组!很奇怪;该代码在阻止发送/接收时运行良好。 离题:-fsanitize=address 到底是做什么的? 它激活了这个的使用:code.google.com/p/address-sanitizer/wiki/AddressSanitizer以上是关于MPI 非阻塞发送/接收中的请求数组的主要内容,如果未能解决你的问题,请参考以下文章