«   »

MPI/C – An advanced send & receive

MPI

For my understanding of what MPI is &/or does, please refer to this post.

MPI_Send & MPI_Recv

Rarely does the MASTER in a parallelized program sends some information to a WORKER solely for the purpose of being displayed. Albeit simple, the program below demonstrates usage of MPI_Send & MPI_Recv where the WORKER manipulates the information received from MASTER; sends that new information to MASTER and MASTER displays it.

Program Listing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* send_receive_advanced.c
 * PARALLEL [MPI] C PROGRAM TO DEMONSTRATE MPI_Send & MPI_Recv FUNCTIONS.
 * MASTER [proc_id = 0] SENDS SOME DATA TO A WORKER [proc_id = 1].
 * WORKER PERFORMS SOME MATHEMATICAL OPERATION AND RETURNS THE
 * 'NEW INFORMATION' TO MASTER.
 *
 * TESTED SUCCESSFULLY WITH MPICH2 (1.3.1) COMPILED AGAINST GCC (4.1.2) 
 * IN A LINUX BOX WITH QUAD CORE INTEL XEON PROCESSOR (1.86 GHz) & 4GB OF RAM.
 *
 * FIRST WRITTEN: GOWTHAM; Sat, 27 Nov 2010 17:10:10 -0500
 * LAST MODIFIED: GOWTHAM; Sat, 27 Nov 2010 18:15:23 -0500
 *
 * URL:
 * http://sgowtham.com/journal/2010/11/28/mpi-c-an-advanced-send-receive/
 *
 * COMPILATION:
 * mpicc -g -Wall -lm send_receive_advanced.c -o send_receive_advanced.x
 *
 * EXECUTION:
 * mpirun -machinefile MACHINEFILE -np NPROC ./send_receive_advanced.x
 *
 * NPROC       : NUMBER OF PROCESSORS ALLOCATED TO RUNNING THIS PROGRAM;
 *               MUST BE EQUAL TO 2
 * MACHINEFILE : FILE LISTING THE HOSTNAMES OF PROCESSORS ALLOCATED TO
 *               RUNNING THIS PROGRAM
 *
*/
 
/* STANDARD HEADERS AND DEFINITIONS 
 * REFERENCE: http://en.wikipedia.org/wiki/C_standard_library
*/
#include <stdio.h>  /* Core input/output operations                         */
#include <stdlib.h> /* Conversions, random numbers, memory allocation, etc. */
#include <math.h>   /* Common mathematical functions                        */
#include <time.h>   /* Converting between various date/time formats         */
#include <mpi.h>    /* MPI functionality                                    */
 
#define MASTER  0   /* Process ID for MASTER                                */
#define WORKER  1   /* Process ID for WORKER                                */
#define N      10   /* Array size                                           */
 
/* MAIN PROGRAM BEGINS */
int main(int argc, char **argv) {
 
  /* VARIABLE DECLARATION */
  int    proc_id,       /* Process identifier                    */
         n_procs,       /* Number of processors                  */
         i;             /* Dummy/Running index                   */
 
  double x[N],          /* 1D array of size N
                           Information sent from MASTER
                           Information received by WORKER        */
         y[N];          /* 1D array of size N
                           Information sent from WORKER
                           Information received by MASTER        */
 
  MPI_Status status;    /* MPI structure containing return codes
                           for message passing operations        */
 
  /* INITIALIZE MPI */
  MPI_Init(&argc, &argv);
 
  /* GET THE PROCESS ID AND NUMBER OF PROCESSORS */
  MPI_Comm_rank(MPI_COMM_WORLD, &proc_id);
  MPI_Comm_size(MPI_COMM_WORLD, &n_procs);
 
  /* IF MASTER, THEN DO THE FOLLOWING:
   * POPULATE x[N]
   * SEND x[N] TO WORKER 
   * RECEIVE y[N] FROM WORKER
   * DISPLAY y[N]
  */
  if (proc_id == MASTER) {
 
    /* POPULATE x[N] - EACH ARRAY ELEMENT IS JUST THE INDEX */
    for (i=0; i < N; i++) {
      x[i] = i;
    }
 
    /* SEND x[N] TO WORKER */
    /* MPI_Send(buf, count, datatype, dest, tag, comm) */
    printf("\n  Sending x[N] to WORKER [proc_id = 1] with TAG = 0\n");
    MPI_Send(x, N, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
 
    /* RECEIVE y[N] FROM WORKER */
    /* MPI_Recv(buf, count, datatype, source, tag, comm, status) */
    printf("\n  Receiving y[N] from WORKER [proc_id = 1] with TAG = 1\n");
    MPI_Recv(y, N, MPI_DOUBLE, 1, 1, MPI_COMM_WORLD, &status);
 
    /* DISPLAY y[N] */
    for (i=0; i < N; i++) {
      printf("    y[%d] = %2.0lf\n", i, y[i]);
    }
 
  } /* MASTER LOOP ENDS */
 
 
  /* IF WORKER, THEN DO THE FOLLOWING:
   * RECEIVE x[N] FROM MASTER 
   * CREATE y[N]
   * SEND y[N] TO MASTER
  */
  if (proc_id == WORKER) {
 
    /* RECEIVE x[N] FROM MASTER */
    printf("\n  Receiving x[N] from MASTER [proc_id = 0] with TAG = 0\n");
    MPI_Recv(x, N, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
 
    /* CREATE A NEW ARRAY y[N]
     * A SIMPLE MATHEMATICAL MANIPULATION 
     * TAKE THE ELEMENTS OF x[N] AND SQUARE THEM
    */
    for (i=0; i < N; i++) {
      y[i] = x[i] * x[i];
    }
 
    /* SEND y[N] TO MASTER */
    printf("\n  Sending y[N] to MASTER [proc_id = 0] with TAG = 1\n");
    MPI_Send(y, N, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);
 
  } /* WORKER LOOP ENDS */
 
  /* FINALIZE MPI */
  MPI_Finalize();
 
  /* INDICATE THE TERMINATION OF THE PROGRAM */
  return 0;
 
} /* MAIN PROGRAM ENDS */

Program Compilation & Execution

The machine where I am running this calculation, dirac, has 4 processors and has MPICH2 v1.3.1 compiled against GCC v4.1.2 compilers.

[guest@dirac mpi_samples]$ which mpicc
alias mpicc='mpicc -g -Wall -lm'
	~/mpich2/1.3.1/gcc/4.1.2/bin/mpicc
 
[guest@dirac mpi_samples]$ which mpirun
alias mpirun='mpirun -machinefile $HOME/machinefile'
	~/mpich2/1.3.1/gcc/4.1.2/bin/mpirun
 
[guest@dirac mpi_samples]$ mpicc send_receive_advanced.c -o send_receive_advanced.x
 
[guest@dirac mpi_samples]$ mpirun -np 2 ./send_receive_advanced.x
 
  Sending x[N] to WORKER [proc_id = 1] with TAG = 0
 
  Receiving y[N] from WORKER [proc_id = 1] with TAG = 1
    y[0] =  0
    y[1] =  1
    y[2] =  4
 
  Receiving x[N] from MASTER [proc_id = 0] with TAG = 0
 
  Sending y[N] to MASTER [proc_id = 0] with TAG = 1
    y[3] =  9
    y[4] = 16
    y[5] = 25
    y[6] = 36
    y[7] = 49
    y[8] = 64
    y[9] = 81
 
[guest@dirac mpi_samples]$



Often, the output is not synchronized – by that, one means that printf statements from MASTER and WORKERS don’t always show up in the logically expected order. One way to fix this issue is to remove all printf statements from WORKERS.

Comments are closed.