Example 1.2 Numerical Integration with MPI Blocking Send/Receive Without Deadlocking
The major drawback of example 1.1 is the potential communication deadlock stemming from sending and receiving a message on processor 0 concurrently. Since my_int is computed locally on processor 0, there is no need to perform message passing of my_int to itself. The elimination of message passing on processor 0 leads to a code that is not prone to deadlocking.
For detail explanations of functions used in this example, please read MPI: The Complete Reference.
Example 1.2 Fortran Code
Program Example1_2
c#######################################################################
c# #
c# This is an MPI example on parallel integration to demonstrate the #
c# use of: #
c# #
c# * MPI_Init, MPI_Comm_rank, MPI_Comm_size, MPI_Finalize #
c# * MPI_Recv, MPI_Send #
c# #
c# Dr. Kadin Tseng #
c# Scientific Computing and Visualization #
c# Boston University #
c# 1998 #
c# #
c# Save this example as a .f (Fortran 77) code to compile #
c# #
c# mpif90 -o ex1_2 example_1_2.f #
c# #
c#######################################################################
implicit none
integer n, p, i, j, proc, ierr, master, myid, tag, comm
real h, a, b, integral, pi, ai, my_int, integral_sum
include "mpif.h" ! brings in pre-defined MPI constants, ...
integer status(MPI_STATUS_SIZE) ! size defined in mpif.h
data master/0/ ! processor 0 collects integral sums from other processors
comm = MPI_COMM_WORLD
call MPI_Init(ierr)
! starts MPI
call MPI_Comm_rank(comm, myid, ierr)
! get current proc ID
call MPI_Comm_size(comm, p, ierr)
! get number of procs
pi = acos(-1.0) ! = 3.14159...
a = 0.0 ! lower limit of integration
b = pi/2. ! upper limit of integration
n = 500 ! number of increment within each process
tag = 123 ! set the tag to identify this particular job
h = (b-a)/n/p ! length of increment
ai = a + myid*n*h ! lower limit of integration for partition myid
my_int = integral(ai, h, n)
write(*,"('Process ',i2,' has the partial sum of',f10.6)")
& myid,my_int
if(myid .eq. master) then ! do following only on master ...
integral_sum = my_int !starts with value on master
do proc=1,p-1 ! loop on procs to collect local sums, exclude master
call MPI_Recv(
! Receive message from proc to master
& proc,
! message source
& tag,
! message tag
& comm, status, ierr)
! status reports source, tag
integral_sum = integral_sum + my_int ! sum my_int from processors
enddo
print *,'The integral =',integral_sum
else
call MPI_Send(
& my_int, 1, MPI_REAL,
! buffer, size, datatype
& master,
! where to send message
& tag,
! message tag
& comm, ierr)
endif
call MPI_Finalize(ierr)
! MPI finish up ...
end
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
Example 1.1 C code
#include <mpi.h>
#include <math.h>
#include <stdio.h>
/* Prototype */
float integral(float ai, float h, int n);
void main(int argc, char* argv[])
{
/*######################################################################
# #
# This is an MPI example on parallel integration to demonstrate the #
# use of: #
# #
# * MPI_Init, MPI_Comm_rank, MPI_Comm_size, MPI_Finalize #
# * MPI_Recv, MPI_Send #
# #
# Dr. Kadin Tseng #
# Scientific Computing and Visualization #
# Boston University #
# 1998 #
# #
######################################################################*/
int n, p, myid, tag, proc, ierr;
float h, integral_sum, a, b, ai, pi, my_int;
int master = 0; /* processor performing total sum */
MPI_Comm comm;
MPI_Status status;
comm = MPI_COMM_WORLD;
ierr = MPI_Init(&argc,&argv);
/* starts MPI */
MPI_Comm_rank(comm, &myid);
/* get current process id */
MPI_Comm_size(comm, &p);
/* get number of processes */
pi = acos(-1.0); /* = 3.14159... */
a = 0.; /* lower limit of integration */
b = pi*1./2.; /* upper limit of integration */
n = 500; /* number of increment within each process */
tag = 123; /* set the tag to identify this particular job */
h = (b-a)/n/p; /* length of increment */
ai = a + myid*n*h; /* lower limit of integration for partition myid */
my_int = integral(ai, h, n);
/* 0<=myid<=p-1 */
printf("Process %d has the partial integral of %fn", myid,my_int);
MPI_Send(
&my_int, 1, MPI_FLOAT,
master,
/* message destination */
tag,
/* message tag */
comm);
if(myid == master) {
integral_sum = 0.0;
for (proc=0;proc<proc++) { /* Serializes message receiving */
MPI_Recv(
&my_int, 1, MPI_FLOAT,
proc,
/* message source */
tag,
/* message tag */
comm, &status);
/* status reports source, tag */
integral_sum += my_int;
}
printf("The Integral =%fn",integral_sum); /* sum of my_int */
}
MPI_Finalize();
/* let MPI finish up ... */
}
float integral(float ai, float h, int n)
{
int j;
float aij, integ;
integ = 0.0; /* initialize */
for (j=0;j<j++) { /* sum integrals */
aij = ai + (j+0.5)*h; /* mid-point */
integ += cos(aij)*h;
}
return integ;
}
Discussion
In the next example, a non-blocking point-to-point send routine is introduced to replace the blocking send. This enables any work that follows the send to proceed while the send is pending or in progress.
Example 1 | Example 1.1 | Example 1.2 | Example 1.3 | Example 1.4 | Example 1.5