Tag Archive : distributed

/ distributed

Installing OpenMPI from Source for Slackware64

December 11, 2015 | Article | No Comments

The Open MPI Project is an open source Message Passing Interface (MPI) implementation that is developed and maintained by a consortium of academic, research, and industry partners.

Message Passing Interface itself is a system designed by a group of researchers from academica and industry to function on a wide variety in parallel computers.The standard defines the syntax and semantics of a core routines useful to a wide range of users writing protable message-passing programs in Fortran77 or the C programming language.

This article will cover about compiling and installing latest OpenMPI for Linux Slackware64.

Obtain the Materials

The latest version (per May 23th, 2014) is 1.8.1. To build the program we need the source code. Download it from OpenMPI site or direct download from here.

Installation

Assuming we have downloaded the source code, we then extract and do compilation process:

tar -xvfj openmpi-1.8.1.tar.bz2
cd openmpi-1.8.1
./configure CFLAGS=-m64 CXXFLAGS=-m64 --with-wrapper-cflags=-m64 --with-wrapper-cxxflags=-m64
make

The flags we passed to configure script is used to ensure the -m64 flag to gcc and g++ during the build phase and also that mpicc wrapper knows to use -m64 when it compiles our code later.

Next we install it once the compilation process is successful.

make install

To check whether you have successfully install openmpi, invoke this command on terminal:

mpicc --version

Testing

Now let’s make a simple MPI application. Copy this source code and name it as mpi.c:

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

int main(int argc, char** argv) {
   int size, rank;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &size);
   MPI_Comm_rank(MPI_COMM_WORLD, &rank);

   printf("Hello world from %d of %d\n", rank, size);

   MPI_Finalize();
}

Compile it using:

mpicc -o my_mpi mpi.c

There is a special way to run MPI program. In general, we do like this:

mpirun <program name> <list of arguments>

Thus, to run our program we invoke:

mpirun my_mpi

Watch it and note the result 😉

Token Ring-Like Program in MPI

December 9, 2015 | Uncategorized | No Comments

In this article, we will discuss sample send and receive mechanism in MPI inclusively we will imitate the concept of token ring topology. In this article we use ten processes with rank from 0 to 9. Starting from 0, the nth process will pass token to (n+1) th process, except 9 which will send to 0. When the token comes back to rank 0, the program will be terminated.

This sample code is using logical topology implemented on program.

In this article I assume you have installed MPICH, OpenMPI, or other MPI implementation.

Source Code

Create a file mpi_token_rin.c and write this:

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

int main(int argc, char* argv[]) {
   // Initialize the MPI Environment
   MPI_Init(&argc, &argv);

   // Get the number of process
   int size;
   MPI_Comm_size( MPI_COMM_WORLD, &size );

   // Get the rank of process
   int rank;
   MPI_Comm_rank( MPI_COMM_WORLD, &rank );

   // The token
   int token;

   if( rank != 0 ) {
      MPI_Recv( &token, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

      printf("Process %d received token %d from process %d\n", rank, token, rank-1);
   } else {
      // Initialize the token value
      token = 100;
   }
   MPI_Send( &token, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD );

   if( rank == 0 ) {
      MPI_Recv( &token, 1, MPI_INT, size - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

      printf("Process 0 received token %d from process %d. End of communication\n", token, size-1 );
   }

   // Finalize the MPI environment
   MPI_Finalize();

   return 0;
}

Compile & Run

To compile:

mpicc mpi_token_ring.c -o mpi_token_ring

To Run:

mpirun -n 10 mpi_token_ring

Result

Process 1 received token 100 from process 0
Process 2 received token 100 from process 1
Process 3 received token 100 from process 2
Process 4 received token 100 from process 3
Process 5 received token 100 from process 4
Process 6 received token 100 from process 5
Process 7 received token 100 from process 6
Process 8 received token 100 from process 7
Process 9 received token 100 from process 8
Process 0 received token 100 from process 9. End of communication

Explanation

Now let’s discuss all the component we have written.

Process zero will assig token with value 100. The value is passed around every single process. Each process except zero is stand by and waiting for token passing. The system will terminate when process zero has received the token back.

Now, let see what if we modify the code like this:

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

#define LIMIT 50

int main(int argc, char** argv) {
   int size, rank;

   MPI_Init( &argc, &argv );
   MPI_Comm_size( MPI_COMM_WORLD, &size );
   MPI_Comm_rank( MPI_COMM_WORLD, &rank );

   int token = 0;

   do {
      if( rank != 0  && token < LIMIT ) {
         MPI_Recv( &token, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
         printf("Process %d received token %d from process %d\n", rank, token, rank-1);
         token++;
      } else {
         token++;
      }

      MPI_Send( &token, 1, MPI_INT, (rank+1) % size, 0, MPI_COMM_WORLD);
      token += size;

      if( rank == 0 && token < LIMIT ) {
         MPI_Recv( &token, 1, MPI_INT, size-1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
      }
   } while( token < LIMIT );

   MPI_Finalize();

   return 0;
}

What is the behavior? 😉

The Concept of Send and Receive in MPI

December 9, 2015 | Article | No Comments

The fundamental concepts of MPI is sending and receiving. Almost every single function in MPI can be implemented with basic send and receive calls.

In this article, we will discuss about how to use MPI’s blocking sending and receiving functions.

Overview

MPI’s send and receive calls operate in the following manner. First, process A decides a message needs to be sent to process B. Process A then packs up all of its necessary data into a buffer for process B. These buffers are often referred to as envelopes since the data is being packed into a single message before transmission (similar to how letters are packed into envelopes before transmission to the post office). After the data is packed into a buffer, the communication device (can be network, or internal connection but commonly a network) is responsible for routing the message to the proper location. The location of the message is defined by the process’s rank.

Even though the message is routed to B, process B still has to acknowledge that it wants to receive A’s data. Once it does this, the data has been transmitted. Process A is acknowledged that the data has been transmitted and may go back to work.

Sometimes there are cases when A might have to send many different types of messages to B. Instead of B having to go through extra measures to differentiate all these messages, MPI allows senders and receivers to also specify message IDs with the message (known as tags). When process B only requests a message with a certain tag number, messages with different tags will be buffered by the network until B is ready for them.

Now, let’s see the prototype for sending and receiving data:

Sending

MPI_Send(void* data, int count, MPI_Datatype datatype, int destination, int tag, MPI_Comm communicator)

Receiving

MPI_Recv(void* data, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm communicator, MPI_Status* status)

Although it’s quite long and variate, it is quite easier to remember since almost every MPI call uses similar syntax.

The first argument is the data buffer. Technically, a pointer to actual data. The second and third arguments describe the count and type of elements that reside in the buffer. MPI_Send sends the exact count of elements, and MPI_Recv will receive at most the count of elements. Technically speaking, in sending several data will be sent from memory pointed by data to memory pointed by data+count. The fourth and fifth arguments specify the rank of the sending/receiving process and the tag of the message. The tag can be viewed as a signature. The sixth argument specifies the communicator and the last argument (for MPI_Recv only) provides information about the received message.

Elementary MPI Datatypes

In previous section, a Datatype term is often mentioned. MPI_Send and MPI_Recv funciton will utilize MPI_Datatypes as means to specify the structure of a message at a higher level. For example, if the process wishes to send one integer to another, it would use a count of one and a datatype of MPI_INT. The other elementary MPI datatypes are listed below with their equivalent C datatypes.

[table “6” not found /]

For now, we will only make use of these datatypes in the beginner MPI tutorial. Once we have covered enough basics, you will learn how to create your own MPI datatypes for characterizing more complex types of messages.

The Blocking Properties

Blocking property is a communication properties in which the participant will wait or idle until the communication session is done. In other word, when communication is not completely done the process will not go to next instruction.

Source Code

We will demonstrate how a send and receive concept can be implemented in MPI. We use two process. First process, rank 0, will send a data to second process, rank 1. The data transported is integer which identified as MPI_INT.

Create a file mpi_send_recv.c and write this:

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

int main(int argc, char* argv[]) {
   // Initialize the MPI Environment
   MPI_Init(&argc, &argv);

   // Get the number of process
   int size;
   MPI_Comm_size( MPI_COMM_WORLD, &size );

   // Get the rank of process
   int rank;
   MPI_Comm_rank( MPI_COMM_WORLD, &rank );

   int number;
   if( rank == 0 ) {
      number = 2;
      MPI_Send( &number, 1, MPI_INT, 1, 0, MPI_COMM_WORLD );
   } else {
      MPI_Recv( &number, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
      printf("Process 1 received number %d from process 0\n", number);
   }

   // Finalize the MPI environment
   MPI_Finalize();

   return 0;
}

The MPI_Comm_rank and MPI_Comm_size are first used to determine the world size along with the rank of the process. Then process zero initialize a number to the value of two and send this value to process one. As you can see the process one is calling MPI_Recv to receive the number. It also prints off the received value.

Since we are sending and receiving exactly one integer, each process requests that one MPI_INT be sent/received. Each process also uses a tag number of zero to identify the message. The processes could have also used the predefined constant MPI_ANY_TAG for the tag number since only one type of message was being transmitted.

Compile & Run

To compile:

mpicc mpi_send_recv.c-o mpi_send_receive

To Run with two processes:

mpiexec -n 2 mpi_send_receive

Results

Running the example program looks like this:

Process 1 received number 2 from process 0

Starting the MPI, Hello World

December 9, 2015 | Article | No Comments

In this article, we will discuss about a basic MPI Hello World application and also discuss how to run an MPI program. If you have read this article, you will find similarity between this and those article. But in this article we will discuss it deeper.

In this article I assume you have installed MPICH or OpenMPI (or other MPI implementation).

Source Code

Create a file mpi_hello_world.c and write this:

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

int main(int argc, char* argv[]) {
   // Initialize the MPI Environment
   MPI_Init(&argc, &argv);

   // Get the number of process
   int size;
   MPI_Comm_size( MPI_COMM_WORLD, &size );

   // Get the rank of process
   int rank;
   MPI_Comm_rank( MPI_COMM_WORLD, &rank );

   // Get the name of processor
   char procname[ MPI_MAX_PROCESSOR_NAME ];
   int len;
   MPI_Get_processor_name( procname, &len);

   // Print off a Hello World message
   printf("Hello world from processor %s, rank %d of %d processor\n",    procname, rank, size);

   // Finalize the MPI environment
   MPI_Finalize();

   return 0;
}

Compile & Run

To compile:

mpicc mpi_hello_world.c -o mpi_hello_world

To Run:

mpirun -n 4 mpi_hello_world

Where “-n 4” specifies how many process will be used.

Explanation

Now let’s discuss all the component we have written.

The first section is list of included library. We use MPI which is defined after MPI is installed. Here we have three libraries included here: mpi for MPI and stdio for Standard input output (like printf and scanf).

The MPI some communication mechanism. To use MPI, an initialization process should be done beforehand using MPI_Init(). Once MPI initialized, it then spawn processes / threads (depends on implementation) and each process or thread will handle a specific task.

On initialization, all of MPI’s global and internal variables are constructed. For example, a communicator is formed around all of the processes that are spawned. This global communicator is referred as MPI_COMM_WORLD. For each process, an unique rank is assigned.

After initialization, two common function can be called. Almost all MPI program will invoke these functions:

MPI_Comm_size( MPI_Comm communicator, int* size )

MPI_Comm_size Returns the size of a communicator. If we use MPI_COMM_WORLD, MPI will encloses all of the processes in the job. This should return the amount of process that were requested for the job.

MPI_Comm_rank( MPI_Comm communicator, int* rank )

MPI_Comm_rank Returns the rank or id of querying process. Each process have assigned an unique id and this id is valid inside of a communicator. The id is started from zero and increment to n-1 for n process spawned.

Less used function in this program is this one:

MPI_Get_processor_name( char* name, int* name_length)

This function can obtain the actual name of the processor on which the process is executing.

At the end of process, MPI_Finalize() should be given.

MPI_Finalize()

MPI_Finalize() will clean up the MPI environment. Once finalization done, no more MPI calls can be made.

Running MPI in Cluster of Nodes

The purpose of MPI is to do distributed work. Using one program, one can divide computation or operation load to several nodes available and simultaneously do the work. If this is the case, we have to setup a host file to run the program simultaneously.

Suppose you have four nodes on a cluster: 167.205.129.1 to 167.205.129.4  and assign them as veda1 to veda4. In each machine we have to setup an authorized key file to avoid password prompt for SSH (the communication will use SSH connection). Follow this steps:

  • Choose a node as a basis, let say 167.205.129.1 (veda1)
  • Login to veda1
  • Generate public and private key for ssh. Choose passphrase you want for using that key.
ssh-keygen -t dsa
  • For other nodes, login to that node and create a directory .ssh on home directory. Make sure you set the permission as following:
chmod 700 /home/<username>/.ssh
  • From basis (veda1) copy the public key to other nodes, use following command:
scp /home/<username>/.ssh/id_dsa.pub <username>@<node's ip>:.ssh/authorized_keys
  • Try access other node via ssh. Use passphrase used at beginning of this section. For example we connect to veda2
ssh 167.205.129.2
  • In order we don’t need to write password everytime we log in, on basis node do following:
eval `ssh-agent`
ssh-add ~/.ssh/id_dsa
  • Next, write host file. This file list all nodes used for computation in MPI. In this case we have 4 nodes (veda1 to veda4) so our host file would be
# List of hosts or nodes used by MPI
veda1
veda2
veda3
veda4
# -----------------------------------

Let say it as .mpi_hostfile.

Now to run it across all of the nodes, do following in basis node:

mpirun -np <# process> --hostfile <hostfile name> <program name>

or in more concrete:

mpirun -np 20 --hostfile .mpi_hostfile hellompi

for launching 20 processes.

We can modify the hostfile for our need. Suppose our hosts are actually dual-core machine (or more core?). We can get MPI to spawn processes across the individual cores first before individual nodes. To accommodate our need, we alter the file to:

# List of hosts or nodes used by MPI
veda1:2
veda2:2
veda3:2
veda4:2
# -----------------------------------

Social media & sharing icons powered by UltimatelySocial