Message Buffers
MPI documentation refers to “send buffers” and “receive buffers.” These refer to variables in the program whose contents are to be sent or received. These variables must be set up by the programmer. The send and receive buffers cannot be the same unless the special “receive buffer” MPI_IN_PLACE
is specified.
When a buffer is specified, the MPI library will look at the starting point in memory (the pointer to the variable). From other information in the command, it will compute the number of bytes to be sent or received. It will then set up a separate location in memory; this is the actual buffer. Often the buffer is not the same size as the original data since it is just used for streaming within the network. In any case, the application programmer need not be concerned about the details of the buffers and should just regard them as variables.
For the send buffer, MPI will copy the sequence of bytes into the buffer and send them over the appropriate network interface to the receiver. The receiver will acquire the stream of data into its receive buffer and copy them into the variable specified in the program.
Buffer Datatypes
MPI supports most of the primitive datatypes available in the target programming language, as well as a few others.
In every language, it is imperative that the data types in the send and receive buffers match. If they do not, the result can be anything from garbage to a segmentation violation.
C/C++
MPI supports most C/C++ datatypes as well as some extensions. The most commonly used are listed below.
C/C++ type | MPI_Datatype |
---|---|
int | MPI_INT |
short | MPI_SHORT |
long | MPI_LONG |
long long | MPI_LONG_LONG_INT |
unsigned int | MPI_UNSIGNED |
unsigned short | MPI_UNSIGNED_SHORT |
unsigned long | MPI_UNSIGNED_LONG |
unsigned long long | MPI_UNSIGNED_LONG_LONG |
float | MPI_FLOAT |
double | MPI_DOUBLE |
long double | MPI_LONG_DOUBLE |
char | MPI_CHAR |
wchar | MPI_WCHAR |
Specific to C:
C type | MPI_Datatype |
---|---|
bool | MPI_C_BOOL |
complex | MPI_C_COMPLEX |
double complex | MPI_C_DOUBLE_COMPLEX |
Specific to C++:
C++ type | MPI_Datatype |
---|---|
bool | MPI_CXX_BOOL |
complex | MPI_CXX_COMPLEX |
double complex | MPI_CXX_DOUBLE_COMPLEX |
Extensions
C/C++ type | MPI_Datatype |
---|---|
none | MPI_BYTE |
none | MPI_PACKED |
Fortran
Fortran type | MPI_Datatype |
---|---|
integer | MPI_INTEGER |
integer*8 | MPI_INTEGER8 |
real | MPI_REAL |
double precision | MPI_DOUBLE_PRECISION |
complex | MPI_COMPLEX |
logical | MPI_LOGICAL |
character | MPI_CHARACTER |
none | MPI_BYTE |
none | MPI_PACKED |
Most MPI distributions support the following types. These are Fortran 77 style declarations; newer code should use KIND
but care must be taken that the number of byes specified is correct.
Fortran type | MPI_Datatype |
---|---|
integer*16 | MPI_INTEGER16 |
real*8 | MPI_REAL8 |
real*16 | MPI_REAL16 |
Python
As we have mentioned, the basic MPI communication routines are in the Communicator class of the MPI subpackge of mpi4py. Each communication subprogram has two forms, a lower-case version and another where the first letter of the method is upper case. The lower-case version can be used to send or receive an object; mpi4py pickles it before communicating. The argument of these routines is the sent object; the received object is the return value of the function.
The upper-case version works only with buffered objects, usually NumPy Ndarrays. Communicating Ndarrays is faster and is recommended when possible. However, every buffer must be a Ndarray in this case, so even scalars must be placed into a one-element array. The upper-case buffered functions are more similar to the corresponding C/C++ functions. For the buffered functions, it is very important that the types match, so use of dtype
is recommended in declaring NumPy arrays.
The mpi4py package supports the C datatypes, in the format MPI.Dtype
rather than MPI_Dtype
, but they are seldom required as an argument to the MPI functions. It is strongly recommended that the type of each NumPy array be explicitly declared with the dtype
option, to ensure that the types match in both send and receive buffers.
import sys
import numpy as np
from mpi4py import MPI
#Run on two processes
comm=MPI.COMM_WORLD
rank=comm.Get_rank()
nprocs=comm.Get_size()
x=None
a=np.empty(11,dtype='float')
if rank==0:
x=10
a=np.arange(11.,dtype='float')
comm.send(x,dest=1)
comm.Send([a,MPI.FLOAT],dest=1)
else:
x=comm.recv(source=0)
comm.Recv([a,MPI.FLOAT],source=0)
print(rank,x)
print(rank,a)