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( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_split( MPI_COMM_WORLD, rank == 0, 0, &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, &size );
for (j=1; j<=2; j++) {
for (i=1; i<size; i++) {
MPI_Recv( &buf, nbvals, MPI_INT, i, 0, master_comm, &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, &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( &buf, nbvals , MPI_INT, 0, 0, master_comm );
for ( i = 0; i < nbvals; i++) buf[i] = buf[i]*buf[i];
MPI_Send( &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) << " " );
}
enregistrer dans un fichier test_boost.cpp
compiler ainsi :
c++ -I /usr/local/lib/boost_1_46_0 test_boost.cpp -o test_boost