I'm writing a halo-exchange routine that looks like this:
halo exchange diagram, example with 3 processors
where non-blocking send/recv calls are used as described by the following pseudo-code:
- mpi_irecv from left_neighbour ( + same for right neighbour)
- pack data and mpi_isend to left_neighbour ( + same for right neighbour)
- mpi_wait(recv_request from left_neighbour) and unpack ( + same for right neighbour)
- mpi_wait(send_request to left_neighbour) ( + same for right neighbour)
This works fine in all cases, except for the specific case where I request two processors, and the boundaries are periodic. In this situation the data is mixed, i.e. recv_buffer_left has the data I expect recv_buffer_right to have, and v.v.
The rank for the left & right neighbours are the same in this case, so I assume I'm missing some subtlety in the request handles/tags? The code is below, would appreciate any thoughts!
! --- 1. issue non-blocking receives
if ( left_neighbour_exists ) call mpi_irecv( recv_buffer_left, buffer_size, MPI_REAL, left_neighbour, itag, world_comm, request_recv_left, ierr )
if ( right_neighbour_exists ) call mpi_irecv( recv_buffer_right, buffer_size, MPI_REAL, right_neighbour, itag, world_comm, request_recv_right, ierr )
! --- 2. pack for sending, then issue non-blocking sends
call pack_data( my_data, send_buffer_left, send_buffer_right )
!
if ( left_neighbour_exists ) call mpi_isend( send_buffer_left, buffer_size, MPI_REAL, left_neighbour, itag, world_comm, request_send_left, ierr )
if ( right_neighbour_exists ) call mpi_isend( send_buffer_right, buffer_size, MPI_REAL, right_neighbour, itag, world_comm, request_send_right, ierr )
! --- 3. wait for receives, then unpack
if ( left_neighbour_exists ) then
!
call mpi_wait( request_recv_left, status, ierr )
!
call unpack_data( recv_buffer_left, my_data )
!
endif
!
if ( right_neighbour_exists ) then
!
call mpi_wait( request_recv_right, status, ierr )
!
call unpack_data( recv_buffer_right, my_data )
!
endif
! --- 4. wait for sends
if ( left_neighbour_exists ) call mpi_wait( request_send_left, status, ierr )
if ( right_neighbour_exists ) call mpi_wait( request_send_right, status, ierr )