MPI_INEIGHBOR_ALLTOALL(3)

πŸ“¦
version 5.0.10 Β· 4 versions
, in ubuntu stonking

πŸ’– MPI_INEIGHBOR_ALLTOALL πŸ’–

okay bestie so this is a page from the Open MPI manual, and it's all about MPI_Neighbor_alltoall, MPI_Ineighbor_alltoall, and MPI_Neighbor_alltoall_init β€” the trio of neighbor-exchange collectives. yes the manpage name is MPI_INEIGHBOR_ALLTOALL(3) (iykyk, the non-blocking one got top billing) but the whole squad lives here. let's get into it ✨


🌈 SYNOPSIS 🌈

✨ C Syntax ✨

#include <mpi.h>

int MPI_Neighbor_alltoall(const void *sendbuf, int sendcount,
     MPI_Datatype sendtype, void *recvbuf, int recvcount,
     MPI_Datatype recvtype, MPI_Comm comm)

int MPI_Ineighbor_alltoall(const void *sendbuf, int sendcount,
     MPI_Datatype sendtype, void *recvbuf, int recvcount,
     MPI_Datatype recvtype, MPI_Comm comm, MPI_Request *request)

int MPI_Neighbor_alltoall_init(const void *sendbuf, int sendcount,
     MPI_Datatype sendtype, void *recvbuf, int recvcount,
     MPI_Datatype recvtype, MPI_Comm comm, MPI_Info info, MPI_Request *request)

πŸŽ€ Fortran Syntax πŸŽ€

USE MPI
! or the older form: INCLUDE 'mpif.h'
MPI_NEIGHBOR_ALLTOALL(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
     RECVTYPE, COMM, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE
     INTEGER COMM, IERROR

MPI_INEIGHBOR_ALLTOALL(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
     RECVTYPE, COMM, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE
     INTEGER COMM, REQUEST, IERROR

MPI_NEIGHBOR_ALLTOALL_INIT(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
     RECVTYPE, COMM, INFO, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE
     INTEGER COMM, INFO, REQUEST, IERROR

πŸ¦‹ Fortran 2008 Syntax πŸ¦‹

USE mpi_f08
MPI_Neighbor_alltoall(sendbuf, sendcount, sendtype, recvbuf, recvcount,
             recvtype, comm, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
     TYPE(*), DIMENSION(..) :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Ineighbor_alltoall(sendbuf, sendcount, sendtype, recvbuf, recvcount,
             recvtype, comm, request, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Neighbor_alltoall_init(sendbuf, sendcount, sendtype, recvbuf, recvcount,
             recvtype, comm, info, request, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Info), INTENT(IN) :: info
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

🌸 INPUT PARAMETERS 🌸

  • sendbuf β€” starting address of the send buffer (choice, bestie, you pick the type).
  • sendcount β€” how many elements you're sending to each process (integer).
  • sendtype β€” datatype of the send buffer elements (handle).
  • recvcount β€” how many elements you're receiving from each process (integer).
  • recvtype β€” datatype of the receive buffer elements (handle).
  • comm β€” the communicator the data gets exchanged over (handle).
  • info β€” info (handle, persistent only).

🫢 OUTPUT PARAMETERS 🫢

  • recvbuf β€” starting address of the receive buffer (choice).
  • request β€” request (handle, non-blocking only).
  • ierror β€” Fortran only: error status (integer).

πŸ’… DESCRIPTION πŸ’…

so MPI_Neighbor_alltoall is a collective operation where every process sends and receives the same amount of data to each of its neighbors. the way this actually pops off: each process runs 2n independent point-to-point communications, where n is the number of neighbors in communicator comm. the neighbors themselves and the buffer layout? determined by the topology of comm. no cap.

here's what MPI_Neighbor_alltoall semantics look like for cartesian topologies, bestie:

MPI_Cart_get(comm, maxdims, dims, periods, coords);
for (dim = 0, i = 0 ; dim < dims ; ++dim) {
    MPI_Cart_shift(comm, dim, 1, &r0, &r1);
    MPI_Isend(sendbuf + i * sendcount * extent(sendtype),
              sendcount, sendtype, r0, ..., comm, ...);
    MPI_Irecv(recvbuf + i * recvcount * extent(recvtype),
              recvcount, recvtype, r0, ..., comm, ...);
    ++i;
    MPI_Isend(sendbuf + i * sendcount * extent(sendtype),
              sendcount, sendtype, r1, ..., comm, &req[i]);
    MPI_Irecv(recvbuf + i * recvcount * extent(recvtype),
              recvcount, recvtype, r1, ..., comm, ...);
    ++i;
}

MPI_Waitall (...);

so the vibe is: each process breaks its local sendbuf into n blocks β€” each one holding sendcount elements of type sendtype β€” and splits its recvbuf the same way according to recvcount and recvtype. process j sends the k-th block of its local sendbuf to neighbor k, and that neighbor drops the data into the j-th block of its local recvbuf. πŸŽ€

⚠️ the amount of data sent must equal the amount of data received, pairwise, between every pair of processes. it's giving symmetry or it's giving nothing.

πŸ‘‘ NEIGHBOR ORDERING πŸ‘‘

okay this part is lowkey important, so pay attention bestie:

  • distributed graph topology (made with MPI_Dist_graph_create): the sequence of neighbors in the send and receive buffers at each process is defined as the sequence returned by MPI_Dist_graph_neighbors β€” for destinations and sources, respectively. ✨
  • general graph topology (made with MPI_Graph_create): the order of neighbors in the send and receive buffers is the sequence of neighbors as returned by MPI_Graph_neighbors. heads up though β€” general graph topologies should generally be replaced by the distributed graph topologies. it's giving "old faithful, but the new one ate".
  • Cartesian topology (made with MPI_Cart_create): the sequence of neighbors in the send and receive buffers at each process is defined by order of the dimensions β€” first the neighbor in the negative direction, then in the positive direction, with displacement 1. the numbers of sources and destinations in the communication routines are 2*ndims, with ndims defined in MPI_Cart_create. and if a neighbor doesn't exist (i.e., you're at the border of a Cartesian topology in the case of a non-periodic virtual grid dimension, i.e., periods[…]==false), then that neighbor is defined to be MPI_PROC_NULL.

and if a neighbor in any of these functions is MPI_PROC_NULL, the neighborhood collective communication behaves like a point-to-point communication with MPI_PROC_NULL in that direction. translation: the buffer is still part of the sequence of neighbors, but it is neither communicated nor updated. it's there, it's just not participating. πŸ’€


πŸ”₯ NOTES πŸ”₯

  • the MPI_IN_PLACE option for sendbuf is not meaningful for this function. don't do it, it's not that girl.
  • all arguments on all processes are significant. comm in particular must describe the same communicator on all processes, and comm must be either a cartesian, graph, or dist graph communicator.
  • there are two MPI library functions that are more general than MPI_Neighbor_alltoall:
    • MPI_Neighbor_alltoallv lets you do all-to-all communication to and from buffers that need not be contiguous β€” different processes may send and receive different amounts of data. πŸ’…
    • MPI_Neighbor_alltoallw expands MPI_Neighbor_alltoallv's functionality to allow the exchange of data with different datatypes. iconic.

πŸ’€ ERRORS πŸ’€

okay bestie, listen up, because this is the part that saves you at 3am 🫢

  • basically almost every MPI routine hands you back an error value: C routines give it to you as the return value of the function, and Fortran routines put it in the last argument. that's the vibe. ✨
  • before that error value ever comes back to you, the current MPI error handler that's tied to the communication object (think: communicator, window, file) gets called. if there's no communication object attached to the MPI call, then the call is treated as attached to MPI_COMM_SELF and it'll call the associated MPI error handler instead. πŸ’…
  • and when MPI_COMM_SELF isn't initialized yet (that's before MPI_Init / MPI_Init_thread, or after MPI_Finalize, or if you're living that Sessions Model exclusively life), the error raises the initial error handler. you can swap that initial error handler out by calling MPI_Comm_set_errhandler on MPI_COMM_SELF when you're on the World model, or with the mpi_initial_errhandler CLI argument to mpiexec, or the info key to MPI_Comm_spawn / MPI_Comm_spawn_multiple. 🌈
  • if no other appropriate error handler has been set, then MPI_ERRORS_RETURN gets called for MPI I/O functions, and MPI_ERRORS_ABORT gets called for all other MPI functions. that's just the default, no cap.

πŸ‘‘ the three predefined error handlers Open MPI ships with πŸ‘‘

  • MPI_ERRORS_ARE_FATAL β€” Causes the program to abort all connected MPI processes. it's giving nuclear option, and honestly? sometimes that's the move πŸ’€
  • MPI_ERRORS_ABORT β€” An error handler that can be invoked on a communicator, window, file, or session. When it's called on a communicator, it acts as if MPI_Abort was called on that communicator. If it's called on a window or file, it acts as if MPI_Abort was called on a communicator containing the group of processes in the corresponding window or file. If it's called on a session, it aborts only the local process. very demure, very mindful of scope πŸŽ€
  • MPI_ERRORS_RETURN β€” Returns an error code to the application. it just hands you the receipt and lets you deal. πŸ™ˆ

πŸ¦‹ and you can make your own, because of course you can πŸ¦‹

MPI applications can also implement their own error handlers by calling:

  • MPI_Comm_create_errhandler then MPI_Comm_set_errhandler
  • MPI_File_create_errhandler then MPI_File_set_errhandler
  • MPI_Session_create_errhandler then MPI_Session_set_errhandler or at MPI_Session_init
  • MPI_Win_create_errhandler then MPI_Win_set_errhandler

⚠️ heads up bestie: note that MPI does not guarantee that an MPI program can continue past an error. like, it might, it might not, that's not something you get to assume. plan accordingly. 😭

see the MPI man page for a full list of MPI error codes. πŸ“œ

see the Error Handling section of the MPI-3.1 standard for more information. (iykyk, go read the standard, it's right there πŸ’œ)


🫢 See also 🫢

  • MPI_Neighbor_alltoallv
  • MPI_Neighbor_alltoallw
  • MPI_Cart_create
  • MPI_Graph_create
  • MPI_Dist_graph_create
  • MPI_Dist_graph_create_adjacent

2003-2026, The Open MPI Community


and that's a wrap, bestie πŸ’– this page came to you from the Open MPI crew, dated Sep 10, 2026, and yes it's MPI_INEIGHBOR_ALLTOALL(3) β€” go forth and neighbor-alltoall responsibly. slay. βœ¨πŸ‘‘πŸ¦‹

πŸ“¦ where this page comes from