1

I am trying to reproduce this C example in Fortran. my code so far:

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)

but i am running into segmentation faults and can not figure out why. I have a feeling it is due to the request array. can someone explain the correct way of using the request array in Fortran? none of the references I found clarify this.

thx in advance

1 Answer 1

2

In case you haven't already done so, consider compiling your program with some flags that will help you in debugging, e.g. with gfortran, you can use -O0 -g -fbounds-check (if that does not help, you might add -fsanitize=address for versions >= 4.8). Other compilers have similar options for debugging.

Doing that, and running with 2 processes, you program crashes at the MPI_Reduce line. If you look up the specifications (e.g. OpenMPI 1.8) you can see that this subroutine requires one more argument, i.e., you forgot to add the ierror argument at the end.

It is a bit tragic that even though the subprograms from the mpi module are accessible through a use association, and thus should be checked for argument consistency to avoid these trivial errors, not all subprograms are necessarily in that module. I don't know which MPI implementation you use, but I checked my local MPICH installation and it does not have most subroutines in the module, so no explicit interfaces exist for them. I guess you are in a similar situation, but I guess other implementations might suffer a similar fate. You could compare it to the C header file missing the function prototype for MPI_Reduce. I guess the reason for this is that originally there was only a Fortran 77 interface for most implementations.

Some final comments: be careful not to just copy-paste the C code. The arrays you pass are not contiguous and will result in a temporary copy to be passed to the MPI routines, which is very inefficient (not that it really matters in this case).

Sign up to request clarification or add additional context in comments.

3 Comments

thx for the answer and the tips on the flags, and the arrays! Weird tho; the code worked fine with blocking send/recv.
offtopic: what does -fsanitize=address do exactly?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.