MPI Basic Point-to-Point Communication
Basic point-to-point communication with MPI
When two processes communicate with each other, we call this communication pattern as point-to-point communication [3]. MPI allows for easy information exchange between processes or nodes although the resulting interfaces may be quite overwhelming. In this notebook, we introduce the two most basic point-to-point communication functions in MPI namely MPI_Send (doc) and MPI_Recv (doc).
MPI_Send performs a blocking send; that is the function call may block until the message is received by the destination process [1]. An MPI_Send must be matched with a receive operation. MPI_Recv (doc) performs a blocking receive [2].
Remark
Note that MPI_Send may return before the message is delivered. MPI_Send uses the so called standard communication mode [3]. Behind the scenes, MPI decides whether to block or not based on the size of the message. The blocking lasts until the the destination process collects the message. Thus, if the message is small MPI_Send returns as soon as the message is copied to a local MPI buffer [3]. This copy is needed in order to release the buffer used by
the source process for subsequent operations, because with this form of send, there
is no way for the sender process to know when the message has been delivered [3].
MPI_Send sends a buffer of data of a certain type to another process. It requires the following arguments.
- A pointer to a data buffer
- The datatype contained in the specified data buffer
- How many elements are contained in the buffer
- A message tag (sort of the id of the message) which should be a non-negative integer
- The receiving process id wihin the communicator
- The communicator used
The datatype must correspond precisely to the data stored in the buffer. For this, MPI has predefined types that can be used. MPI has most of the usual C types. Furthermore, the standard has made provisions for creating and communicating user defined types as well.
Note also that MPI_Send returns an error value code. If this value is 0 (or the symbolic constant MPI_SUCCESS ), no error has occurred [3].
Remark
The default behaviour when a fatal error occurs in any of the participating processes is to abort the whole execution. In a sense, the default MPI behaviour when an error occurs is not fault tolerant.
MPI_Recv has a very similar signature with MPI_Send. The exception is that there is no destination id parameter but the id of the process from the process receives. Note also that the buffer set aside must be at least as large as the number or elements expected to be received.
Specification of the sent/received datatype is required so that machines wiht different endianness or machines with different memory types (32-bit, 64-bit, 128-bit) to be able to communicate.
Below is a simple example of how to use MPI_Send and MPI_Recv. You can also find the example here.
#include <mpi.h>
#include <iostream>
int main(int argc, char** argv){
int rank;
int n_procs;
// initialize MPI. No MPI calls
// prior to this point should be made
MPI_Init(&argc, &argv);
// what's my rank
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// how may procs
MPI_Comm_size(MPI_COMM_WORLD, &n_procs);
MPI_Status status;
if(rank == 0){
std::cout<<"Hello from process "<<rank<<" of "<<n_procs<<std::endl;
int num = 2;
// send a number to the worker
MPI_Send(&num, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
// recv the answer
int ans = -1;
MPI_Recv(&ans, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &status);
if(ans == 0){
std::cout<<"Number "<<num<<" is odd"<<std::endl;
}
else{
std::cout<<"Number "<<num<<" is even"<<std::endl;
}
}
else if(rank == 1){
// receive
int data = -1;
MPI_Recv(&data, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if(data % 2 == 0){
data = 1;
MPI_Send(&data, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
}
else{
data = 0;
MPI_Send(&data, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
}
}
MPI_Finalize();
// No MPI calls beyond this point
return 0;
}
Note the following
- The tag can be any integer between 0-32767
-
MPI Recvmay use for the tag the wildcardMPI_ANY_TAG. This allows anMPI_Recvto receive from a send using any tag. -
MPI_Sendcannot use the wildcardMPI_ANY_TAG. A specific tag must be specified. -
MPI_Recvmay use for the source the wildcardMPI_ANY_SOURCE. This allows anMPI_Recvto receive from a send from any source. -
MPI_Sendmust specify the process rank of the destination. No wildcard exists.
In this section, we introduced the two most basic point-to-point communication functions available in MPI. Namly we saw, MPI_Send and MPI_Recv. Although these functions, and MPI in general, hide much of the boilerplate code needed so that two processes can communicate, still the resulting program is rather verbose. This is something that we would like to hide as much as possible both for application maintenance as well as for development and performance considerations.