Parallélisation master-slave en MPI

Petit exemple de parallélisation en mpi selon le modèle Master/Slave.

Ici les processus dits "slaves" vont générer chacun 256 nombres aléatoires entre 1 et 10 puis faire des opérations dessus et envoyer le tout au processus Maître.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"

const int nbvals=256;
int main( argc, argv )
int argc;
char **argv;
{
int rank, size;
MPI_Comm new_comm;

MPI_Init( &amp;argc, &amp;argv );
MPI_Comm_rank( MPI_COMM_WORLD, &amp;rank );
MPI_Comm_split( MPI_COMM_WORLD, rank == 0, 0, &amp;new_comm );
if (rank == 0)
master_job( MPI_COMM_WORLD, new_comm );
else
slave_job( MPI_COMM_WORLD, new_comm );

MPI_Finalize( );
return 0;
}

/* The master i.e. process of rank 0 */
int master_job( master_comm, comm )
MPI_Comm comm;
{
int       i,j,val, size;
int       buf[nbvals];

MPI_Status status;

MPI_Comm_size( master_comm, &amp;size );
for (j=1; j<=2; j++) {
for (i=1; i<size; i++) {
MPI_Recv( &amp;buf, nbvals, MPI_INT, i, 0, master_comm, &amp;status );
if(j==1) printf("The Master received from slave n° %d those random values\t",i);
else printf("The Master received from slave n° %d the square of previous values\t",i);
for (val=0; val < nbvals; val++) printf("%d\t", buf[val]);
fputs("\n \n", stdout);
}
}
}

/* Each slave I.E proccesus with rank > 0 */
int slave_job( master_comm, comm )
MPI_Comm comm;
{
int buf[nbvals];
int  rank,i;

MPI_Comm_rank( comm, &amp;rank );

/* Simple "srand()" seed: just use "rank" */
unsigned int iseed = (unsigned int)time(NULL) + rank;
srand (iseed);
for  (i = 0; i < nbvals; i++)
{
buf[i] = 1+ (int)(10.0*rand()/(RAND_MAX+1.0));
}
MPI_Send( &amp;buf, nbvals , MPI_INT, 0, 0, master_comm );

for ( i =    0; i < nbvals; i++) buf[i]    = buf[i]*buf[i];
MPI_Send( &amp;buf, nbvals , MPI_INT, 0, 0, master_comm );

return 0;
}

compiler :

mpicc random.c -o random

lancer via qsub (sans fichier de soumission ;-) ) avec 4 processus:

qsub -N MasterSlave -pe mpirobin 4  -b y -cwd /opt/openmpi/bin/mpirun -np 4 ./random

C++ et MPI sur le cluster

Ici nous allons utiliser l’implémentation openmpi de MPI située dans /opt/openmpi.

Un petit exemple (hello_mpi.cpp) de communication simple point à point entre processus.

# include <cstdlib>
# include <iostream>
# include <iomanip>

using namespace std;

# include "mpi.h"

int main ( int argc, char *argv[] )
{
int maitre = 0; //le process 0 sera le noeud maitre
int num_procs; //nombre de processus du job
int process_id; //identifiant attribué automatiquement à chaque processus

MPI::Init ( argc, argv ); //  Initialisation de MPI.

num_procs = MPI::COMM_WORLD.Get_size ( );//  Determiner le nombre de processus obtenus.

process_id = MPI::COMM_WORLD.Get_rank ( );//  Get the individual process ID.

if ( process_id == maitre ) //  Processus 0 imprime un message.
{
cout << "\n";
cout << "HELLO_WORLD - du process Maitre:\n";
cout << "  Le nombre total de processus est " << num_procs << "\n\n";
}

cout << "  Process " << process_id << " vous dit 'Hello, world!'\n";//  Chaque process (y compris le maitre) va imprimer son identifiant et hello.

if ( process_id == maitre )// Ici le Process 0 (maitre) va dire au revoir.
{
cout << "\n";
cout << "  Le process maitre vous dit 'Au revoir, world!'\n";
}

MPI::Finalize ( );//  Fermeture de MPI.

return 0;
}

Compiler comme suit :

/opt/openmpi/bin/mpicc hello_mpi.cpp -o hello_mpi

Pour soumettre via sge, il faut un script (sge_hello_mpi.sh) :

#!/bin/bash
#
#$ -cwd
#$ -j y
#$ -S /bin/bash
#$ -pe mpirobin 4 #quatre processus en round robin

MPI_DIR=/opt/openmpi/
$MPI_DIR/bin/mpirun -np $NSLOTS ./hello_mpi

Soumettre:

qsub sge_hello_mpi.sh

Ici vous aurez deux fichiers en sortie un sge_hello_mpi.sh.oxxxx et un sge_hello_mpi.sh.poxxxx

Utilisation de boost sur le cluster

Boost provides free peer-reviewed portable C++ source libraries.

We aim to establish "existing practice" and provide reference implementations so that Boost libraries are suitable for eventual standardization. Ten Boost libraries are already included in the C++ Standards Committee's Library Technical Report TR1 and will be included in the upcoming revision of the C++ Standard. More Boost libraries are proposed for the upcoming TR2.

exemple d'utilisation sur le cluster.

#include <;boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>;
#include <algorithm>

int main()
{
    using namespace boost::lambda;
    typedef std::istream_iterator<int>; in;

    std::for_each(
        in(std::cin), in(), std::cout << (_1 * 3) &lt;&lt; " " );
}

enregistrer dans un fichier test_boost.cpp

compiler ainsi :

c++ -I /usr/local/lib/boost_1_46_0 test_boost.cpp -o test_boost