MPI_ALLTOALLW(3)

πŸ’– MPI_ALLTOALLW πŸ’–

okay bestie, so this is MPI_ALLTOALLW(3) from the Open MPI manual, and it's literally the glow-up edition of all-to-all πŸ¦‹

MPI_Alltoallw, plus its chaotic little siblings MPI_Ialltoallw and MPI_Alltoallw_init β€” all processes send data of different types to, and receive data of different types from, all processes. every single one. no cap. πŸ‘‘


✨ SYNTAX ✨

🌸 C Syntax 🌸

#include <mpi.h>

int MPI_Alltoallw(const void *sendbuf, const int sendcounts[],
     const int sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const int rdispls[],
     const MPI_Datatype recvtypes[], MPI_Comm comm)

int MPI_Ialltoallw(const void *sendbuf, const int sendcounts[],
     const int sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const int rdispls[],
     const MPI_Datatype recvtypes[], MPI_Comm comm,
     MPI_Request *request)

int MPI_Alltoallw_init(const void *sendbuf, const int sendcounts[],
     const int sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const int 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_ALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SDISPLS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RDISPLS(*), RECVTYPES(*)
     INTEGER COMM, IERROR

MPI_IALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SDISPLS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RDISPLS(*), RECVTYPES(*)
     INTEGER COMM, REQUEST, IERROR

MPI_ALLTOALLW_INIT(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, INFO, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SDISPLS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RDISPLS(*), RECVTYPES(*)
     INTEGER COMM, INFO, REQUEST, IERROR

πŸ¦‹ Fortran 2008 Syntax πŸ¦‹

USE mpi_f08
MPI_Alltoallw(sendbuf, sendcounts, sdispls, sendtypes, recvbuf, recvcounts,
             rdispls, recvtypes, comm, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
     TYPE(*), DIMENSION(..) :: recvbuf
     INTEGER, INTENT(IN) :: sendcounts(*), sdispls(*), recvcounts(*),
     rdispls(*)
     TYPE(MPI_Datatype), INTENT(IN) :: sendtypes(*)
     TYPE(MPI_Datatype), INTENT(IN) :: recvtypes(*)
     TYPE(MPI_Comm), INTENT(IN) :: comm
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Ialltoallw(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(*), sdispls(*),
     recvcounts(*), 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_Alltoallw_init(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
             recvcounts, rdispls, recvtypes, comm, fIinfo, request, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN), ASYNCHRONOUS :: sendcounts(*), sdispls(*),
     recvcounts(*), 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

(yes bestie, that fIinfo is really in there, i'm not gonna touch it, it's canon πŸ’…)


πŸ’œ INPUT PARAMETERS πŸ’œ

  • sendbuf β€” starting address of the send buffer. the origin point, the home base 🏠
  • sendcounts β€” integer array, where entry i specifies the number of elements to send to rank i. one number per bestie ✨
  • sdispls β€” integer array, where entry i specifies the displacement (in bytes, offset from sendbuf) from which to send data to rank i. bytes, bestie, not elements. remember that 🫢
  • sendtypes β€” datatype array, where entry i specifies the datatype to use when sending data to rank i. every rank gets to be special πŸŽ€
  • recvcounts β€” integer array, where entry j specifies the number of elements to receive from rank j
  • rdispls β€” integer array, where entry j specifies the displacement (in bytes, offset from recvbuf) to which data from rank j should be written
  • recvtypes β€” datatype array, where entry j specifies the datatype to use when receiving data from rank j. equal opportunity type chaos 🌈
  • comm β€” communicator over which data is to be exchanged
  • info β€” Info (handle, persistent only)

🌟 OUTPUT PARAMETERS 🌟

  • recvbuf β€” address of receive buffer
  • request β€” Request (handle, non-blocking only)
  • ierror β€” Fortran only: error status

πŸ‘‘ DESCRIPTION πŸ‘‘

MPI_Alltoallw is a generalized collective operation where all processes send data to and receive data from all other processes. it's giving main character energy, but for every process simultaneously 😭

it adds flexibility to MPI_Alltoallv by letting you specify the datatype of individual data blocks β€” on top of displacement and element count. so not just "how much" and "where", but also "as what". obsessed πŸ’…

you can think of its operation like this, where each process performs 2n independent point-to-point communications (with n being the number of processes in communicator comm), including communication with itself:

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);

process j sends the k-th block of its local sendbuf to process k, which places the data in the j-th block of its local recvbuf. so cute. so symmetric. πŸ’–

when a pair of processes exchanges data, each 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. bytes are the vibe check here 🌸

note that process i may send a different amount of data to process j than it receives from process j. also, a process may send entirely different amounts and types of data to different processes in the communicator. it's giving "no two relationships are the same" πŸ¦‹

🌈 WHEN COMMUNICATOR IS AN INTER-COMMUNICATOR 🌈

when the communicator is an inter-communicator, the gather operation occurs in two phases. the data is gathered from all the members of the first group and received by all the members of the second group. then the data is gathered from all the members of the second group and received by all the members of the first. the operation exhibits a symmetric, full-duplex behavior. iconic, honestly ✨

the first group defines the root process. the root process uses MPI_ROOT as the value of root. all other processes in the first group use MPI_PROC_NULL as the value of root. all processes in the second group use the rank of the root process in the first group as the value of root.

when the communicator is an intra-communicator, these groups are the same, and the operation occurs in a single phase. one phase, one slay πŸ’…


πŸŽ€ USE OF IN-PLACE OPTION πŸŽ€

when the communicator is an intracommunicator, you can perform an all-to-all operation in-place β€” meaning the output buffer is used as the input buffer. just use the variable MPI_IN_PLACE as the value of sendbuf. ✨

in that case, sendcounts, sdispls, and sendtypes are ignored. the input data of each process is assumed to be in the area where that process would receive its own contribution to the receive buffer. it's already home, bestie 🏠🫢


πŸ’€ NOTES πŸ’€

  • the specification of counts, types, and displacements should not cause any location to be written more than once. seriously. that's undefined behavior territory and we don't go there πŸ™ˆ
  • all arguments on all processes are significant. the comm argument, in particular, must describe the same communicator on all processes. everybody on the same page, fr fr
  • the offsets of sdispls and rdispls are measured in bytes. compare this to MPI_Alltoallv, where these offsets are measured in units of sendtype and recvtype, respectively. iykyk β€” this is the trap, don't fall in it 😭

πŸ’₯ ERRORS πŸ’₯

okay so bestie, here's the tea on errors, and it's kinda important so like, pay attention 🌸

Almost all MPI routines return an error value. In C routines that's the return result of the function, and in Fortran routines it's the last argument. iykyk πŸ’…

Before that error value ever comes back to you, the current MPI error handler associated with the communication object (think communicator, window, file β€” the whole squad) gets called. And if there's no communication object tied to the MPI call? Then the call is considered attached to MPI_COMM_SELF and it'll call the associated MPI error handler. periodt.

Now here's the plot twist 😭 β€” when MPI_COMM_SELF is not initialized (so: before MPI_Init/MPI_Init_thread, after MPI_Finalize, or when you're using the Sessions Model exclusively), the error raises the initial error handler instead.

You can change that initial error handler by calling MPI_Comm_set_errhandler on MPI_COMM_SELF when you're using 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. slay πŸŽ€

And if literally 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 how it is bestie πŸ’€


✨ the three predefined error handlers ✨

Open MPI ships with three of these bad boys that you can use:

  • MPI_ERRORS_ARE_FATAL β€” Causes the program to abort all connected MPI processes. like, everyone goes down together 🫢
  • 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 if MPI_Abort was called on that communicator. If 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 called on a session, it aborts only the local process.
  • MPI_ERRORS_RETURN β€” Returns an error code to the application. the chill one fr fr πŸ’œ

🌈 make your own!! main character energy 🌈

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

⚠️ Note that MPI does not guarantee that an MPI program can continue past an error. no cap, that one's real. don't be out here assuming you can just keep vibing after an error 😭

See the MPI man page for a full list of MPI error codes β€” that's your reference doc bestie, bookmark it πŸ’–

See the Error Handling section of the MPI-3.1 standard for more information.

πŸ¦‹ See also: πŸ¦‹

  • MPI_Alltoall
  • MPI_Alltoallv

2003-2026, The Open MPI Community


and that's a wrap on MPI_ALLTOALLW(3) bestie!! πŸŽ€βœ¨ this lil masterpiece is from the Open MPI source, version Sep 10, 2026 β€” go forth and alltoallw responsibly, mwah πŸ’…πŸ«Ά

πŸ“¦ where this page comes from