MPI_INEIGHBOR_ALLTOALLW(3)
π MPI_INEIGHBOR_ALLTOALLW π
okay bestie sit down, we're reading the Open MPI manual page for MPI_Ineighbor_alltoallw and its two sibling functions, and ngl it's kind of a lot but we're gonna get through it together. grab a snack. π
β¨ NAME β¨
So there's a whole little family here, three functions, one page:
MPI_Neighbor_alltoallwMPI_Ineighbor_alltoallwMPI_Neighbor_alltoallw_init
and what they do, like as a group, is: all processes send data of different types to, and receive data of different types from, all processes. yes really. different types!! every single neighbor!! iconic behavior honestly. π
π οΈ SYNTAX π οΈ
C Syntax
#include <mpi.h>
int MPI_Neighbor_alltoallw(const void *sendbuf, const int sendcounts[],
const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
const MPI_Datatype recvtypes[], MPI_Comm comm)
int MPI_Ineighbor_alltoallw(const void *sendbuf, const int sendcounts[],
const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
const MPI_Datatype recvtypes[], MPI_Comm comm, MPI_Request *request)
int MPI_Neighbor_alltoallw_init(const void *sendbuf, const int sendcounts[],
const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
const MPI_Datatype recvtypes[], MPI_Comm comm, MPI_Info info, MPI_Request *request)
Fortran Syntax
USE MPI
! or the older form: INCLUDE 'mpif.h'
MPI_NEIGHBOR_ALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNTS(*), SENDTYPES(*)
INTEGER RECVCOUNTS(*), RECVTYPES(*)
INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
INTEGER COMM, IERROR
MPI_INEIGHBOR_ALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, REQUEST, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNTS(*), SENDTYPES(*)
INTEGER RECVCOUNTS(*), RECVTYPES(*)
INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
INTEGER COMM, REQUEST, IERROR
MPI_NEIGHBOR_ALLTOALLW_INIT(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, INFO, REQUEST, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNTS(*), SENDTYPES(*)
INTEGER RECVCOUNTS(*), RECVTYPES(*)
INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
INTEGER COMM, INFO, REQUEST, IERROR
Fortran 2008 Syntax
USE mpi_f08
MPI_Neighbor_alltoallw(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
recvcounts, rdispls, recvtypes, comm, ierror)
TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
TYPE(*), DIMENSION(..) :: recvbuf
INTEGER, INTENT(IN) :: sendcounts(*), recvcounts(*)
INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN) :: sdispls(*), rdispls(*)
TYPE(MPI_Datatype), INTENT(IN) :: sendtypes(*), recvtypes(*)
TYPE(MPI_Comm), INTENT(IN) :: comm
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
MPI_Ineighbor_alltoallw(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
recvcounts, rdispls, recvtypes, comm, request, ierror)
TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
INTEGER, INTENT(IN), ASYNCHRONOUS :: sendcounts(*), recvcounts(*)
INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN), ASYNCHRONOUS ::
sdispls(*), rdispls(*)
TYPE(MPI_Datatype), INTENT(IN), ASYNCHRONOUS :: sendtypes(*),
recvtypes(*)
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Request), INTENT(OUT) :: request
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
MPI_Neighbor_alltoallw_init(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
recvcounts, rdispls, recvtypes, comm, info, request, ierror)
TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
INTEGER, INTENT(IN), ASYNCHRONOUS :: sendcounts(*), recvcounts(*)
INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN), ASYNCHRONOUS ::
sdispls(*), rdispls(*)
TYPE(MPI_Datatype), INTENT(IN), ASYNCHRONOUS :: sendtypes(*),
recvtypes(*)
TYPE(MPI_Comm), INTENT(IN) :: comm
TYPE(MPI_Info), INTENT(IN) :: info
TYPE(MPI_Request), INTENT(OUT) :: request
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
like yes, the ASYNCHRONOUS keywords are doing the most but they're important, don't touch them. π
π₯ INPUT PARAMETERS π₯
sendbufβ the starting address of the send buffer. that's where the goods leave from. π¦sendcountsβ an integer array, and entry i says how many elements to send to neighbor i.sdisplsβ an integer array, entry i is the displacement (in bytes, offset fromsendbuf) to send data to neighbor i from.sendtypesβ a datatype array, entry i is the datatype to use when sending data to neighbor i. yes you pick per-neighbor. main character flexibility. β¨recvcountsβ an integer array, entry j is how many elements to receive from neighbor j.rdisplsβ an integer array, entry j is the displacement (in bytes, offset fromrecvbuf) where data from neighbor j should be written.recvtypesβ a datatype array, entry j is the datatype to use when receiving data from neighbor j.commβ the communicator over which all this data is gonna be exchanged. the group chat, basically. π«Άinfoβ Info (handle, persistent only).
π€ OUTPUT PARAMETERS π€
recvbufβ address of the receive buffer. where the gifts land. πrequestβ Request (handle, non-blocking only).ierrorβ Fortran only: error status.
π DESCRIPTION π
MPI_Neighbor_alltoallw is a generalized collective operation where literally every process sends data to and receives data from all of its neighbors. she's giving all-to-all but make it neighbor-aware.
so how is this different from MPI_Neighbor_alltoallv? bestie it adds flexibility π
β it lets you specify the datatype of individual data blocks, not just displacement and element count. so you get per-block type control. obsessed.
the way to think about it: each process performs 2n independent point-to-point communications, where n is the number of neighbors in the topology of communicator comm. and the neighbors plus the buffer layout are both determined by the topology of comm. no cap.
here's the vibe in code, verbatim:
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 + sdispls[i] * extent(sendtype),
sendcount, sendtypes[i], r0, ..., comm, ...);
MPI_Irecv(recvbuf + rdispls[i] * extent(recvtype),
recvcount, recvtypes[i], r0, ..., comm, ...);
++i;
MPI_Isend(sendbuf + sdispls[i] * extent(sendtype),
sendcount, sendtypes[i], r1, ..., comm, &req[i]);
MPI_Irecv(recvbuf + rdispls[i] * extent(recvtype),
recvcount, recvtypes[i], r1, ..., comm, ...);
++i;
}
MPI_Wait_all (...);
MPI_Comm_size(comm, &n);
for (i = 0, i < n; i++)
MPI_Send(sendbuf + sdispls[i], sendcounts[i],
sendtypes[i], i, ..., comm);
for (i = 0, i < n; i++)
MPI_Recv(recvbuf + rdispls[i], recvcounts[i],
recvtypes[i], i, ..., comm);
so 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. cute little handoff. π€
when a pair of processes exchanges data, each one may pass different element count and datatype arguments β as long as the sender specifies the same amount of data to send (in bytes) as the receiver expects to receive. that's the deal. bytes must match, everything else is your business.
also note: process i may send a different amount of data to process j than it receives from process j. and a process may send entirely different amounts and types of data to different processes in the communicator. it's giving chaotic good. she contains multitudes. π₯
π NOTES π
bestie read these, they're the rules not the vibes.
- The
MPI_IN_PLACEoption forsendbufis not meaningful for this operation. don't do it. it's not it. - The specification of counts, types, and displacements should not cause any location to be written more than once. seriously β writing the same spot twice is an undefined-behavior situation and you do not want that smoke.
- All arguments on all processes are significant. The
commargument, in particular, must describe the same communicator on all processes. everybody has to be on the same page, fr fr. - The offsets of
sdisplsandrdisplsare measured in bytes. compare this toMPI_Neighbor_alltoallv, where those offsets are measured in units ofsendtypeandrecvtype, respectively. so yeah. bytes here, not types. this is the classic gotcha, write it on your hand. ποΈ
π₯ ERRORS π₯
okay bestie this part is important so lock in π
Almost all MPI routines return an error value β and like, where does it go? For the C routines it's the return result of the function, and for Fortran routines it's the last argument. classic.
But listen β before that error value ever gets returned, the current MPI error handler that's associated with the communication object (think communicator, window, file, whatever) gets called. β¨
And if there's no communication object associated with the MPI call? Then the call is considered attached to MPI_COMM_SELF and it'll call the error handler associated with that. π«Ά
Now here's the plot twist: when MPI_COMM_SELF is not initialized β meaning before MPI_Init/MPI_Init_thread, or after MPI_Finalize, or when you're using the Sessions Model exclusively β the error raises the initial error handler. π
And you can change that initial error handler, no cap:
- by calling
MPI_Comm_set_errhandleronMPI_COMM_SELFwhen you're using the World model, or - with the
mpi_initial_errhandlerCLI argument tompiexec, or - with the info key to
MPI_Comm_spawn/MPI_Comm_spawn_multiple.
If no other appropriate error handler has been set, then the MPI_ERRORS_RETURN error handler gets called for MPI I/O functions, and the MPI_ERRORS_ABORT error handler gets called for all other MPI functions. periodt. β
π the three predefined error handlers in Open MPI π
Open MPI ships three of them and they're iconic:
MPI_ERRORS_ARE_FATALβ Causes the program to abort all connected MPI processes. πMPI_ERRORS_ABORTβ An error handler that can be invoked on a communicator, window, file, or session. When called on a communicator, it acts as ifMPI_Abortwas called on that communicator. If called on a window or file, it acts as ifMPI_Abortwas called on a communicator containing the group of processes in the corresponding window or file. If called on a session, it aborts only the local process.MPI_ERRORS_RETURNβ Returns an error code to the application. (the "just tell me what went wrong, I'll handle it" girlie π)
πΈ making your own error handler πΈ
MPI applications can also implement their own error handlers, and the way you do that is by calling:
MPI_Comm_create_errhandlerthenMPI_Comm_set_errhandlerMPI_File_create_errhandlerthenMPI_File_set_errhandlerMPI_Session_create_errhandlerthenMPI_Session_set_errhandleror atMPI_Session_initMPI_Win_create_errhandlerthenMPI_Win_set_errhandler
π heads up: note that MPI does not guarantee that an MPI program can continue past an error. like, fr fr, don't count on it.
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.
π¦ See also:
MPI_Neighbor_alltoallMPI_Neighbor_alltoallvMPI_Cart_createMPI_Graph_createMPI_Dist_graph_create
π Copyright π
2003-2026, The Open MPI Community
and that's the whole page bestie, we ate and left no crumbs π
β¨ this version is the MPI_INEIGHBOR_ALLTOALLW(3) page dated Sep 10, 2026, straight from The Open MPI Community β go forth and neighbor-alltoall-w your little heart out, ily π«Άππ
π¦ where this page comes from
- ubuntu stonking: openmpi-doc 5.0.10-6 Β· other
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms