2014-06-24 81 views
1

我試圖在Fortran中重現this C示例。我的代碼到目前爲止:請求數組在MPI中非阻塞發送/接收

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中使用請求數組的正確方法嗎?我發現的參考文獻都沒有闡明這一點。

提前THX

回答

2

如果你還沒有這樣做,考慮與一些標誌,這將有助於你在調試,例如編譯程序與gfortran,您可以使用-O0 -g -fbounds-check(如果這沒有幫助,您可能會添加-fsanitize=address版本> = 4.8)。其他編譯器有類似的調試選項。

這樣做,並運行2個進程,您編程在MPI_Reduce行崩潰。如果你查看了規範(例如OpenMPI 1.8),你可以看到這個子程序需要多一個參數,即你忘記在最後加上ierror參數。

即使通過use關聯可以訪問mpi模塊中的子程序,因此應該檢查參數一致性以避免這些微不足道的錯誤,但這並不是所有子程序都必須在該模塊中。我不知道你使用了哪個MPI實現,但是我檢查了我的本地MPICH安裝,並且它沒有模塊中的大部分子程序,所以沒有明確的接口。我想你也有類似的情況,但我想其他的實現可能會遭受類似的命運。您可以將它與缺少MPI_Reduce函數原型的C頭文件進行比較。我猜這是因爲大多數實現只有Fortran 77接口。

一些最後的評論:小心不要複製粘貼C代碼。您傳遞的數組不是連續的,並且會導致將臨時副本傳遞給MPI例程,這非常低效(而不是在這種情況下非常重要)。

+0

thx爲答案和旗幟上的提示和數組!怪異的壽;代碼工作正常阻塞send/recv。 – nluigi

+0

offtopic:什麼是--sanitize =地址做的確切嗎? – nluigi

+0

它激活使用此:https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer – steabert