Greetings, Master

The Concept

One of the processes in an MPI program often has a special role, e.g. to distribute work. This process is usually called the master and it is common to assign the role to the process with rank 0. The rest of the processes are often referred to as the slaves.

The Code

The following code will result in a program where the master, process 0, broadcasts its name to all of the other processes. The slaves then send a reply to the master which prints them to standard out.

$ cd basic_mpi/02_greetings_master/
$ cat src/greetings.c
/******************************************************************************
 *                                                                            *
 *  Basic MPI Example - Greetings, Master                                     *
 *                                                                            *
 *  The master process broadcasts the name of the CPU it runs on to           *
 *  the pool. All other processes respond by sending greetings                *
 *  to the master process, which collects the messages and displays           *
 *  them on standard output.                                                  *
 *                                                                            *
 ******************************************************************************
 *                                                                            *
 *  The original code was written by Gustav at University of Indiana in 2003. *
 *                                                                            *
 *  The current version has been tested/updated by the HPC department at      *
 *  the Norwegian University of Science and Technology in 2011.               *
 *                                                                            *
 ******************************************************************************/
#include     /* functions sprintf, printf and BUFSIZ defined there */
#include    /* function strcpy defined there */
#include    /* function exit defined there */
#include       /* all MPI-2 functions defined there */
 
#define TRUE 1        
#define FALSE 0
#define MASTER_RANK 0 /* It is traditional to make process 0 the master. */
 
main(argc, argv)
     int argc;
     char *argv[];
{
  int count, pool_size, my_rank, my_name_length, i_am_the_master = FALSE;
  char my_name[BUFSIZ], master_name[BUFSIZ], send_buffer[BUFSIZ],
    recv_buffer[BUFSIZ];
  MPI_Status status;
 
  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &pool_size);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Get_processor_name(my_name, &my_name_length);
 
  if (my_rank == MASTER_RANK) {
    i_am_the_master = TRUE;
    strcpy (master_name, my_name);
  }
 
  MPI_Bcast(master_name, BUFSIZ, MPI_CHAR, MASTER_RANK, MPI_COMM_WORLD);
 
  if (i_am_the_master)
    for (count = 1; count < pool_size; count++) {
      MPI_Recv (recv_buffer, BUFSIZ, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG,
                MPI_COMM_WORLD, &status);
      printf ("%s\n", recv_buffer);
    }
  else {
    sprintf(send_buffer, "hello %s, greetings from %s, rank = %d",
            master_name, my_name, my_rank);
    MPI_Send (send_buffer, strlen(send_buffer) + 1, MPI_CHAR,
              MASTER_RANK, 0, MPI_COMM_WORLD);
  }
 
  MPI_Finalize();
    
  exit(0);
}
Previous instructions

MPI_Init() and MPI_Finalize(); Is used to initialize and end the program as in any MPI program.

MPI_Rank(); Is now used to give a special role to process 0; it is assigned to be the master.

MPI_Size(); Is used to find the number of slaves to receive a message from each.

MPI_Get_processor_name(); Is used to name the computer of each process.

New instructions

MPI_Send( send_buffer, strlen(send_buffer)+1, MPI_CHAR, MASTER_RANK, 0, MPI_COMM_WORLD );  Blocks the execution until the transfer is complete. It sends strlen(send_buffer)+1 of type MPI_CHAR from the send_buffer to the process with MASTER_RANK within the MPI_COMM_WORLD communicator. The 0 between MASTER_RANK and MPI_WORLD refers to the tag value, which can be used to distinguish between different types of messages.

MPI_Recv( recv_buffer, BUFSIZ, MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG. MPI_COMM_WORLD, &status ); Blocks the execution until the transfer is complete. It receives BUFSIZE of type MPI_CHAR to the recv_buffer. The source can be any process (ANY_SOURCE) within the MPI_COMM_WORLD communicator and with any tag (ANY_TAG). status is a struct that contains at least three fields: MPI_SOURCE, MPI_TAG, and MPI_ERROR. This is useful to see the source and tag of a message when using wild cards. The use of wild cards enable the master to receive messages from the slaves as they get ready rather than in a predefined order.

MPI_Status status; Is a struct to store information like MPI_SOURCE, MPI_TAG and MPI_ERROR.

MPI_Bcast( master_name, BUFSIZ, MPI_CHAR, MASTER_RANK, MPI_COMM_WORLD ); Blocks the execution of code in the slaves until the master has performed the broadcast. master_name is an array of chars on all the processes, but only the master has something useful in the buffer before the broadcast – the aim of the broadcast is to get all the local master_name arrays to be identical. BUFSIZ is the number of the type MPI_CHAR that is to be transferred. MASTER_RANK is the root of the broadcast which is to be done within the MPI_COMM_WORLD communicator. MPI_Bcast() is a simple one to all communication which is typically faster than doing a sequential MPI_Send() and MPI_Recv.

Compile & Run

If you have not already done so, obtain all the example code here.

Switch to the Intel compiler (optional, only necessary once in each terminal session)

$ module load intel

Compile the program using

$ make

 Submit the job to the queue

$ make submit

The output from the program execution is placed in the output folder

$ cat output/*
hello compute-0-34.local, greetings from compute-0-34.local, rank = 1
hello compute-0-34.local, greetings from compute-0-34.local, rank = 2
hello compute-0-34.local, greetings from compute-0-34.local, rank = 5
hello compute-0-34.local, greetings from compute-0-34.local, rank = 6
hello compute-0-34.local, greetings from compute-0-33.local, rank = 9
hello compute-0-34.local, greetings from compute-0-33.local, rank = 10
hello compute-0-34.local, greetings from compute-0-33.local, rank = 13
hello compute-0-34.local, greetings from compute-0-33.local, rank = 14
hello compute-0-34.local, greetings from compute-0-34.local, rank = 4
hello compute-0-34.local, greetings from compute-0-34.local, rank = 3
hello compute-0-34.local, greetings from compute-0-34.local, rank = 7
hello compute-0-34.local, greetings from compute-0-33.local, rank = 15
hello compute-0-34.local, greetings from compute-0-33.local, rank = 8
hello compute-0-34.local, greetings from compute-0-33.local, rank = 12
hello compute-0-34.local, greetings from compute-0-33.local, rank = 11