Hello World for MPI

From BCCD 3.0

Jump to: navigation, search

This tutorial will take you through the basics of MPI (Message Passing Interface) using C. For information on compiling and running MPI programs using the BCCD, please see Compiling and Running MPI.


As with other computer languages, it is often useful to begin looking at the MPI parallel programming protocol in its simplest terms. One of the most basic computer programs that can be written is Hello World. We will begin our journey into MPI with the same basic task of getting the computer to simply say hello.

As a first step, let us start with the basic Hello World program in C familiar to most programmers.

#include <stdio.h>

int main(int argc, char ** argv) {

     printf("Hello World!\n");

}

This program keeps things simple. We have the basic C program structure of include statements and a main routine with a single print statement. The first change we will make in creating a Hello MPI program will simply be to make this code run on each node in a parallel environment. We will need to include the MPI libraries, and use the first of 6 key routines used in MPI programming, MPI_Init and MPI_Finalize.

#include <stdio.h>
#include <mpi.h>

int main(int argc, char ** argv) {
 
     MPI_Init(&argc, &argv);
     // note that argc and argv are passed by address

     printf("Hello MPI!\n");

     MPI_Finalize(); 
}

In addition to including the MPI header files, we have done two things. First, we have allowed the local implementation of MPI to know that a parallel program is starting, and to access the command line variables that may or may have not been passed to the program. We do this with MPI_Init(). Notice that the command line arguments are passed by reference, so that the local MPI implementation can remove anything needed by mpirun, and pass back whatever command line arguments are specific to the program. Similarly, before the program ends, we let the program know that we are done using MPI commands by invoking MPI_Finalize().

Compile and run the modified program. (See Compiling and Running MPI for help.) You should get a Hello MPI! message from each node. But how can you be sure which message is from which node, or which node is which?

MPI programs exist in what is referred to as a “communicator.” A communicator is a set of processes which are capable of communicating. For most of your MPI programs, you can use the default communicator MPI_COMM_WORLD which consists of all processes available. If you specified in mpirun that you wanted to run on 4 nodes, you will have 4 processes in your communicator. Each of those will be assigned a rank, and you can ask MPI to give you your rank as well as the size of the communicator from within your program. Let's do this.

#include <stdio.h>
#include <mpi.h>

int main(int argc, char ** argv) {

	int size,rank;

	MPI_Init(&argc, &argv);
	// note that argc and argv are passed by address

	MPI_Comm_rank(MPI_COMM_WORLD,&rank);
	MPI_Comm_size(MPI_COMM_WORLD,&size);

	printf("Hello MPI! Process %d of %d\n",
	 	rank,size);

	MPI_Finalize(); 
}

This will allow you to see which process each Hello MPI! comes from, but not which computer it is running on. The MPICH implementation of MPI includes a command that will let you do just this, MPI_Get_processor_name (*note: this is not an official MPI command and may not be in other MPI implementations).

#include <stdio.h>
#include <mpi.h>

int main(int argc, char ** argv) {

	int size,rank;
	int length;
	char name[80];

	MPI_Init(&argc, &argv);
	// note that argc and argv are passed by address

	MPI_Comm_rank(MPI_COMM_WORLD,&rank);
	MPI_Comm_size(MPI_COMM_WORLD,&size);
	MPI_Get_processor_name(name,&length);

	printf("Hello MPI! Process %d of %d on %s\n",
	 	rank,size,name);

	MPI_Finalize(); 
}

Compile and run the above changes. Do you get a separate hostname from each node?

Each of these programs are running on separate nodes, but other than the initial setup, you have merely allowed the nodes to communicate with the standard output stream (in this case the screen in the terminal window) and not with each other. The primary method of communication in MPI is sending and receiving messages (thus the name message passing interface.) You do this with two commands, MPI_Send and MPI_Recv.

#include <stdio.h>
#include <mpi.h>

int main(int argc, char ** argv) {

	int size,rank;
	int length;
	char name[80];
	MPI_Status status;
	int i;

	MPI_Init(&argc, &argv);
	// note that argc and argv are passed by address

	MPI_Comm_rank(MPI_COMM_WORLD,&rank);
	MPI_Comm_size(MPI_COMM_WORLD,&size);
	MPI_Get_processor_name(name,&length);

	//instead of printing to the screen, send
	//	messages to the “server”
	//printf("Hello MPI! Process %d of %d on %s\n",
	//	rank,size,name);

	if (rank==0) {
     	// server commands
		for (i=1;i<size;i++) {
			MPI_Recv(name,80,MPI_CHAR,i,999,MPI_COMM_WORLD,&status);
			printf("Hello MPI!\n");
			printf(" mesg from %d of %d on %s\n",i,size,name);
		}
	} else {
		// client commands
		MPI_Send(name,80,MPI_CHAR,0,999,MPI_COMM_WORLD);
	}

	MPI_Finalize(); 
}

Congratulations! At this point, you should have a basic understanding of the six key routines used in MPI programming: MPI_Init, MPI_Finalize, MPI_Comm_rank, MPI_Comm_size, MPI_Send, and MPI_Recv. Ready for a more advanced example? Continue on to the Simpson Rule MPI Example.

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox