Scientific Computing & Visualization
Help Contact
About Accounts Computation Visualization Documentation Services

Multiprocessing by Message Passing MPI

Example 1.3 Integration with MPI Nonblocking Send

Associative and Commutative Rules

An operator ¤ satifies the associative rule if:
a ¤ (b ¤ c) = (a ¤ b) ¤ c

For example, addition (+) satisfies the associative rule but subtraction (-) does not.

An operator ¤ satisfies the commutative rule if:
a ¤ b = b ¤ a

For example, multiplication (*) satisfies the commutative rule but division (/) does not.

Starts MPI on a processor. It must be called only once in the entire program. If no error, ierr returns 0.

Querry for the identity of the current processor, myid. Knowing myid, the user program may act on different data or different tasks accordingly. For this example, it is used to determine the range of integration and hence each processor acts on its own data (see ai). In addition, the total integral sum is computed only on the process with myid = 0.

A communicator dictates which processes can participate in a message passing operation. MPI_COMM_WORLD is a commonly used communicator pre-defined in mpif.h (for fortran) or mpi.h (for C). It enables all processes to participate in message passing operations such as MPI_Recv. On the other hand, a programmer can define a communicator which restricts accessibility to specific (e.g., odd or even numbered) processors for any message passing operation that requires it.

A communicator has type INTEGER.
Buffer, buffer size, data type

All MPI message passing routines, such as MPI_Send and MPI_Recv, require these three arguments to define the (send or receive) buffer, its size, and MPI data type. Examples of MPI data types are:
MPI_REAL, MPI_INTEGER, MPI_CHARACTER

Querry for the number of processors. This is provided by the user at runtime to the executable a.out via the command
katana% mpirun -np 4 a.out

In this example, MPI_Comm_size returns p = 4.

Exit MPI. Like MPI_Init, this routine should only be called once in the entire program, after all MPI parallel processing is done.

Performs point-to-point blocking send. The call to this routine continue to block until the send buffer can be safely overwritten (i.e., the content of the send buffer has been received at the destination).

Performs point-to-point blocking receive. The call to this routine continue to block until the receive buffer contains the intended data (or message).

Performs point-to-point nonblocking send. The send buffer should not be overwritten until the operation is confirmed to be complete by way of MPI_Wait.

Block until the operation (in this case, signaled by request arising from MPI_Isend) is completed.
Message Source

It tells the receiver where the message comes from.

MPI_ANY_SOURCE is a constant pre-defined in mpif.h. This represents a source (processor) "wild card."

For the parallel numerical integration example, the integration is the sum of all partial integral sums from all processors. Because summation is an operation that satisfies the associative rule which means the result is not dependent on any specific order of summation, the use of MPI_ANY_SOURCE can potentially be more efficient (first come first served) as well as less likely to deadlock. When a message is received with MPI_ANY_SOURCE, the source can be retrieved via status(MPI_SOURCE).
Message Destination

It tells the sender where to send the message.
Message Tag

Tag serves as a secondary means to define the identity of a message. The primary means is the processor rank, myid.
Message Status

Returns the status of a message receive operation. This contains information about where the message came from and its tag when wild cards MPI_ANY_SOURCE and MPI_ANY_TAG are used as source and tag, respectively.

The status is declared "integer status(MPI_STATUS_SIZE)".

MPI_ANY_TAG is a constant pre-defined in mpif.h. This represents a tag "wild card." Generally, a tag is used as a secondary means to identify a message -- the primary means is myid. An example that requires a tag in addition to myid is when multiple messages are passed between a pair of processors. Upon receive of these messages, if the receiver needs to distinguish the identities of them in order to place them or act on them accordingly, then tag can be used to differentiate the messages. When a message is received with MPI_ANY_TAG, the tag can be retrieved via status(MPI_TAG).
Compute integral with range defined by i (i.e., process myid).

real function integral(ai, h, n)
implicit none
integer n, j
real h, ai, aij

integral = 0.0         ! initialize integral
do j=0,n-1             ! sum integrals
  aij = ai + (j+0.5)*h ! abscissa mid-point
  integral = integral + cos(aij)*h
enddo

return
end

Starts MPI on a processor. It must be called only once in the entire program. All MPI C functions return an error flag. If no error, ierr returns 0.

Querry for the identity of the current processor, myid. Knowing myid, the user program may act on different data or different tasks accordingly. For this example, it is used to determine the range of integration and hence each processor acts on its own data (see ai). In addition, the total integral sum is computed only on the process with myid = 0.

A communicator dictates which processes can participate in a message passing operation. MPI_COMM_WORLD is a commonly used communicator pre-defined in mpif.h (for fortran) or mpi.h (for C). It enables all processes to participate in message passing operations such as MPI_Recv. On the other hand, a programmer can define a communicator which restricts accessibility to specific (e.g., odd or even numbered) processors for any message passing operation that requires it.

A communicator has type MPI_Comm.
Buffer, buffer size, data type

All MPI message passing routines, such as MPI_Send and MPI_Recv, require these three arguments to define the (send or receive) buffer, its size, and MPI data type. Examples of MPI data types are:
MPI_FLOAT, MPI_INT, MPI_CHAR

Querry for the number of processors. This is provided by the user at runtime to the executable a.out via the command
katana% mpirun -np 4 a.out

In this example, MPI_Comm_size returns p = 4.

Exit MPI. Like MPI_Init, this routine should only be called once in the entire program, after all MPI parallel processing is done.

Performs point-to-point blocking send. The call to this routine continue to block until the send buffer can be safely overwritten (i.e., the content of the send buffer has been received at the destination).

Performs point-to-point blocking receive. The call to this routine continue to block until the receive buffer contains the intended data (or message).

Performs point-to-point nonblocking send. The send buffer should not be overwritten until the operation is confirmed to be complete by way of MPI_Wait.

Block until the operation (in this case, signaled by request arising from MPI_Isend) is completed.
Message Destination

It tells the sender where to send the message.
Message Source

It tells the receiver where the message comes from.

MPI_ANY_SOURCE is a constant pre-defined in mpi.h. This represents a source (processor) "wild card."

For the parallel numerical integration example, the integration is the sum of all partial integral sums from all processors. Because summation is an operation that satisfies the associative rule which means the result is not dependent on any specific order of summation, the use of MPI_ANY_SOURCE can potentially be more efficient (first come first served) as well as less likely to deadlock. When a message is received with MPI_ANY_SOURCE, the source can be retrieved via status.MPI_SOURCE.
Message Tag

Tag serves as a secondary means to define the identity of a message. The primary means is the processor rank, myid.

MPI_ANY_TAG is a constant pre-defined in mpi.h. This represents a tag "wild card." Generally, a tag is used as a secondary means to identify a message -- the primary means is myid. An example that requires a tag in addition to myid is when multiple messages are passed between a pair of processors. Upon receive of these messages, if the receiver needs to distinguish the identities of them in order to place them or act on them accordingly, then tag can be used to differentiate the messages. When a message is received with MPI_ANY_TAG, the tag can be retrieved via status.MPI_TAG.
Message Status

Returns the status of a message receive operation. This contains information about where the message came from and its tag when wild cards MPI_ANY_SOURCE and MPI_ANY_TAG are used as source and tag, respectively.

This is declared with "MPI_Status status".
Compute integral with range defined by i (i.e., process myid).

float integral(float ai, float h, int n)
{
 int j;
 float aij, integ;

 integ = 0.0;            /* initialize */
 for (j=0;j<n;j++) {  /* sum integrals */
   aij = ai + (j+0.5)*h; /* mid-point */
   integ += cos(aij)*h;
 } 
 return integ;
}

Until a matching receive has signaled that it is ready to receive, a blocking send will continue to wait. In situations where work following the send does not overwrite the send buffer (i.e., array waiting to be sent), it might be more efficient to use nonblocking send so that work following the send statement can start right away while the send process is pending. Similarly, a nonblocking receive could be more efficient than its blocking counter-part if work following MPI_Recv does not depend on the safe arrival of the receive buffer.

In this example, the point-to-point blocking MPI_Send used in the preceding example is replaced with the nonblocking MPI_Isend subroutine to enable work that follows it to proceed while the send process is waiting for its matching receive process to respond.

Example 1.3 Fortran code

Example 1.3 C code

Discussion

  1. A nonblocking MPI_Isend call returns immediately to the next statement without waiting for the task to complete. This enables other_work to proceed right away. This usage of nonblocking send (or receive) to avoid processor idling has the effect of "latency hiding," where latency is the elapse time for an operation, such as MPI_Isend, to complete.
  2. Another performance enhancement parameter applied to this example is the use of MPI_ANY_SOURCE to specify message source. The wildcard nature of MPI_ANY_SOURCE enables the messages to be summed in the order of their arrival rather than any imposed sequence (such as the loop-index order used in the preceeding examples). It is important to note that summation is a mathematical operation that satisfies the associative and commutative rules and hence the order in which the integral sums from processors are added is not pertinent to the outcome.
  3. Since MPI_ANY_SOURCE is used, the source where a message came from is not known explicitly. However, the status buffer returning from MPI_Recv contains useful information about the message. For example, status(MPI_SOURCE) returns the source (i.e., processor number) of the message in a fortran code while status.MPI_SOURCE returns source for a C code.
  4. MPI_ANY_TAG is a constant pre-defined in mpif.h (or mpi.h for C). This represents a tag "wild card." Generally, a tag is used as a secondary means to identify a message -- the primary means is myid. An example that requires a tag in addition to myid is when multiple messages are passed between a pair of processors. Upon receive of these messages, if the receiver needs to distinguish the identities of them in order to place them or act on them accordingly, then tag can be used to differentiate the two messages. If a message's tag is not know explicitly (because the message was sent via a nonblocking send), the tag can be retrieved via the status(MPI_TAG) for fortran and status.MPI_TAG for C.

Example 1  | Example 1.1 | Example 1.2 | Example 1.3 | Example 1.4 | Example 1.5

Boston University
Boston University
 
OIT | CCS | July 18, 2008  
Scientific Computing & Visualization Boston University home page Boston University home page