• Aucun résultat trouvé

Algorithmes Parallèles et Distribués MPI 3. Aspects avancés de MPI Camille Coti Franck Butelle César Rodríguez

N/A
N/A
Protected

Academic year: 2022

Partager "Algorithmes Parallèles et Distribués MPI 3. Aspects avancés de MPI Camille Coti Franck Butelle César Rodríguez"

Copied!
26
0
0

Texte intégral

(1)

Algorithmes Parallèles et Distribués

MPI 3. Aspects avancés de MPI

Camille Coti Franck Butelle César Rodríguez

LIPN, Université Paris 13

Formation Ingénieurs SupGalilée Info 3 et AIR 3

12/2020

Transparents préparés par Camille Coti, modifiés par César Rodríguez et Franck Butelle

(2)

Plan

1 Décomposition de domaine

2 Création de nouveaux communicateurs : Topologies cartésiennes

3 Création de nouveaux types de données

4 Opérations définies par l’utilisateur

(3)

Décomposition de domaine

Plan

1 Décomposition de domaine Maître-esclave

Découpage en grille Ghost Region

2 Création de nouveaux communicateurs : Topologies cartésiennes

3 Création de nouveaux types de données

4 Opérations définies par l’utilisateur

(4)

Décomposition de domaine Maître-esclave

Maître-esclave

Distribution des données

Le maître distribue le travail aux esclaves

Le maître démultiplexe les données, multiplexe les résultats Les esclaves necommuniquent pasentre eux

Efficacité

Files d’attentes de données et résultats au niveau du maître On retrouve la partie séquentielle de la loi d’Amdahl Communications : maître↔esclaves

Les esclaves ne travaillent que quand ils attendent des données ou qu’ils envoient leurs résultats

Seuls les esclaves participent effectivement au calcul

Possibilité d’un bon speedup à grande échellesi les communications sont rares Peu rentable pour quelques processus

Attention au goulet d’étranglement(bottleneck)au niveau du maître

(5)

Décomposition de domaine Maître-esclave

Schéma du Maître-esclave

Maître

Escl 1 Escl 2 Escl 3 Escl 4 Escl 5

Équilibrage de charge Statique :

Ï Utilisation deMPI_Scatterpour distribuer les données

Ï MPI_Gatherpour récupérer les résultats

Dynamique :

Ï Modepull: les esclaves demandent du travail

Ï Le maître envoie les «chunks» 1 par 1

(6)

Décomposition de domaine Découpage en grille

Découpage en grille

Grille de processus

On découpe les données et on attribue un processus à chaque sous-domaine

Décomposition 1D Découpage en bandes

0 1 2 3

Décomposition 2D

Découpage en rectangles(préférable si très grande taille)

0 1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

(7)

Décomposition de domaine Ghost Region

Ghost region

Frontières entre les sous-domaines

Un algorithme peut avoir besoin des valeurs des points voisins pour calculer la valeur d’un point

Traitement d’images (détection de contours...), automates cellulaires...

Réplication des données situées à la frontière

Chaque processus dispose d’un peu des données des processus voisins Mise à jour à la fin d’une étape de calcul

(8)

Création de nouveaux communicateurs : Topologies cartésiennes

Plan

1 Décomposition de domaine

2 Création de nouveaux communicateurs : Topologies cartésiennes Création

Fonctions utiles Exemples

sous-communicateurs

Communicateurs non cartésiens

3 Création de nouveaux types de données

4 Opérations définies par l’utilisateur

(9)

Création de nouveaux communicateurs : Topologies cartésiennes Création

Création d’une topologie cartésienne

Décomposition en structure géométrique

On transpose un communicateur sur une topologie cartésienne :

intMPI_Cart_create(MPI_Commcomm_old,intndims,const intdims[], const intperiods[],intreorder,MPI_Comm∗comm_cart)

0 1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

En 2D

comm_old: le communicateur de départ ndims: ici 2

dims: nombre de processus dans chaque dimension (ici {4, 4}) periods: si on sort par un côté on revient par l’autre (1=vrai, 0=faux) reorder: autoriser ou non de modifier les rangs des processus

comm_cart: nouveau communicateur

(10)

Création de nouveaux communicateurs : Topologies cartésiennes Fonctions utiles

Fonctions utiles sur le nouveau communicateur

D’autres opérations sur les communicateurs avec topologie cartésienne :

intMPI_Cart_coords(MPI_Commcomm,intrang,intmaxdims,intcoords[]);

Permet d’obtenir lescoordonnéesd’un rang donné

intMPI_Cart_rank(MPI_Commcomm,intcoords[],int∗rang);

fonction inverse de la précédente :

Permet d’obtenir lerangdu processus associé aux coordonnées données Le rang est toujoursrelatifau communicateur !

intMPI_Cart_shift(MPI_Commcomm,intnumdim,intdeplact, int∗rang_src,int∗rang_dst);

Trouver les processusprécédant(rang_src) etsuivant(rang_dest) dans la dimension n°numdimavec un saut dedeplact(qui peut être<0 )

(11)

Création de nouveaux communicateurs : Topologies cartésiennes Exemples

Exemple (1/2)

intmain (intargc,char∗∗argv) { inttaille, rang, nrang, prev, succ;

intnbDims=1;

inttabDims[nbDims], newDims[nbDims];

intperiods[nbDims];

MPI_Comm comm;

MPI_Init(&argc, & argv);

MPI_Comm_size(MPI_COMM_WORLD, &taille);

MPI_Comm_rank(MPI_COMM_WORLD, &rang);

assert (taille >= 4);/∗ termine en cas d’échec du test ∗/

printf ("Je suis %d !\n", rang);

/∗ Une seule dimension, avec presque tous les threads ∗/

tabDims[0] = taille − 2;

periods[0] = 1;

MPI_Cart_create(MPI_COMM_WORLD, nbDims, tabDims, periods, 1, &comm);

/∗ suite diapo suivante ∗/

(12)

Création de nouveaux communicateurs : Topologies cartésiennes Exemples

Exemple (2/2)

/∗ Certains threads n’appartiennent pas au nouveau communicateur ∗/

if(comm ==MPI_COMM_NULL) { printf ("Je suis %d, exclu !\n", rang);

}else{

/∗ Mon rang dans le nouv. communicateur ∗/

MPI_Comm_rank(comm, &nrang);

/∗ récupère mes coordonnées ∗/

MPI_Cart_coords(comm, nrang, nbDims, newDims);

printf ("%d: nouv. rang %d, x=%d\n", rang, nrang, newDims[0]);

MPI_Cart_shift(comm, 0, 1, &prev, &succ);

printf ("%d: nrang %d à dist 1: pre=%d succ=%d\n", rang, nrang, prev, succ);

MPI_Cart_shift(comm, 0, 2, &prev, &succ);

printf ("%d: nrang %d à dist 2: pre=%d succ=%d\n", rang, nrang, prev, succ);

MPI_Comm_free(&comm);/∗ pas sur ceux qui sont exclus ! ∗/

}MPI_Finalize();

return0;

}

(13)

Création de nouveaux communicateurs : Topologies cartésiennes sous-communicateurs

Extraction de sous-communicateurs d’un comm. cartésien

intMPI_Cart_sub(MPI_Commcomm_old,

const intremain_dims[ ],MPI_Comm∗comm_new);

comm_old : le communicateur cartésien de départ

remain_dims: quelles dimensions sont dans le communicateur (1) ou non (0) comm_new : le nouveau communicateur contenant la sous grille dontfait partie le processus appelant.

X Y

Z

Exemple

Sicomm_olda une topologie (X,Y,Z) en 3×4×2 et remain_dimsest{1, 0, 1}, alors

MPI_Cart_sub() crée ? communicateurs avec une topologie en : ?

(14)

Création de nouveaux communicateurs : Topologies cartésiennes sous-communicateurs

Extraction de sous-communicateurs d’un comm. cartésien

intMPI_Cart_sub(MPI_Commcomm_old,

const intremain_dims[ ],MPI_Comm∗comm_new);

comm_old : le communicateur cartésien de départ

remain_dims: quelles dimensions sont dans le communicateur (1) ou non (0) comm_new : le nouveau communicateur contenant la sous grille dontfait partie le processus appelant.

X Y

Z

Exemple

Sicomm_olda une topologie (X,Y,Z) en 3×4×2 et remain_dimsest{1, 0, 1}, alors

MPI_Cart_sub() crée 4 communicateurs avec une topologie en «couche» de dim. 3×2.

(15)

Création de nouveaux communicateurs : Topologies cartésiennes Communicateurs non cartésiens

Communicateurs non cartésiens

On peut créer des sous-communicateurs de communicateurs déjà créés MPI_Comm_create

MPI_Comm_split MPI_Graph_create MPI_Dist_graph_create . . .

(16)

Création de nouveaux types de données

Plan

1 Décomposition de domaine

2 Création de nouveaux communicateurs : Topologies cartésiennes

3 Création de nouveaux types de données Schéma de fonctionnement

Bloc d’éléments contigus Bloc d’éléments non contigus Structures de données

4 Opérations définies par l’utilisateur

(17)

Création de nouveaux types de données Schéma de fonctionnement

Principe de fonctionnement

On définit le datatype (voir diapos suivantes)

Ï MPI_Type_contiguous,MPI_Type_vector,MPI_Type_indexed,MPI_Type_struct On l’enregistre(commit) "Obligatoire

Ï MPI_Type_commit(MPI_Datatype∗type) On peut récupérer sa taille en octets

Ï MPI_Type_size(MPI_Datatypetype,int∗ size) On le libère à la fin

Ï MPI_Type_free(MPI_Datatype∗type)

Extrait des types de base

MPI_CHAR MPI_SHORT MPI_INT

MPI_LONG MPI_UNSIGNED MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE MPI_BYTE MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED_LONG

(18)

Création de nouveaux types de données Bloc d’éléments contigus

Bloc d’éléments contigus

Création d’un block d’éléments :

int MPI_Type_contiguous(intcount,MPI_Datatypeoldtype, MPI_Datatype∗newtype );

NB :oldtypepeut être un type complexe.

oldtype

oldtype

oldtype

oldtype

VECTOR

(19)

Création de nouveaux types de données Bloc d’éléments non contigus

Bloc d’éléments non contigus

Vecteur de données

int MPI_Type_vector(intnbblocs,int longbloc , int pas,

MPI_Datatypeoldtype,MPI_Datatype∗newtype );

On lienbblocsblocs delongblocéléments séparés par un paspasd’éléments.

Exemple :nbblocs=3, longbloc=2, pas=5

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 ...

Quelles cases du tableaubuff sont envoyées ? intbuff[128];

MPI_Datatypedt;

intnbblocs=2, longbloc=2, pas=4;

MPI_Type_vector(nbblocs, longbloc, pas,MPI_INT, &dt);

MPI_Type_commit(&dt);

MPI_Send(buff, 2, dt, vois,tag,comm);//? ?

0 1 2 3 4 5 6 7 8 9 10 11 ...

(20)

Création de nouveaux types de données Bloc d’éléments non contigus

Bloc d’éléments non contigus

Vecteur de données

int MPI_Type_vector(intnbblocs,int longbloc , int pas,

MPI_Datatypeoldtype,MPI_Datatype∗newtype );

On lienbblocsblocs delongblocéléments séparés par un paspasd’éléments.

Exemple :nbblocs=3, longbloc=2, pas=5

00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 ...

Quelles cases du tableaubuff sont envoyées ? intbuff[128];

MPI_Datatypedt;

intnbblocs=2, longbloc=2, pas=4;

MPI_Type_vector(nbblocs, longbloc, pas,MPI_INT, &dt);

MPI_Type_commit(&dt);

MPI_Send(buff, 2, dt, vois,tag,comm);//

? ?

0 1 2 3 4 5 6 7 8 9 10 11 ...

(21)

Création de nouveaux types de données Bloc d’éléments non contigus

Recalculer la taille d’un bloc

Spécialement utile pour les blocs d’éléments non contigus

"Problème : Envoi de plusieurs blocs d’éléments non contigus

Les blocs d’éléments non contigus sont a priori inutilisables pour scatter, gather,...

Solution :

int MPI_Type_create_resized(MPI_Datatypeoldtype,MPI_Aintlb,MPI_Aintext, MPI_Datatype∗newtype)

Création d’un nouveau type identique à oldtype, sauf pour le calcul des offset : borne inf : lb(souvent 0) et borne sup :lb+ext(typiquement le premier sous élément d’un bloc d’éléments non contigus).

A la place du MPI_Send précédent

MPI_Type_create_resized(dt, 0, longbloc∗sizeof(int), &typeReduit);

MPI_Type_commit(&typeReduit);

MPI_Send(buff, 2, typeReduit, vois, tag, comm);

(22)

Création de nouveaux types de données Structures de données

Cas des struct

MPI n’a pas accès aux structures déclarées par le programmeur, il faut tout lui expliquer ! On donne les éléments, leur nombre et l’offset auquel ils sont positionnés :

intMPI_Type_create_struct(int count ,

int array_of_block_lengths[] ,

MPI_Aint array_of_displacements[] ,

MPI_Datatype array_of_types[] ,

MPI_Datatype *newtype );

count: nombre de champs dans la structure (taille des tableauxarray_of_...) array_of_block_lengths: nombre d’éléments dans le champ (pour les tableaux) array_of_displacements: permet à MPI de faire la (dé)sérialisation

array_of_types: idem, nécessaire pour la (dé)sérialisation newtype: le nom du nouveau type de données

Sources d’erreurs : types des vecteurs et déplacements dans la structure

(23)

Création de nouveaux types de données Structures de données

Création de type structuré — exemple

typedef struct{

inti; // bloc de 1 INT à l’adresse 0 doubled1;// bloc de 1 DOUBLE à l’adr. 8 doubled2;// bloc de 1 DOUBLE à l’adr. 16 charstr[5];// bloc de 5 CHAR à 2 l’adr. 24 } my_struct;

intlongblocs[4] = { 1, 1, 1, 5 };

MPI_Aintpositions[4] = {

offsetof (my_struct, i), // #include <stddef.h>

offsetof (my_struct, d1), offsetof (my_struct, d2), offsetof (my_struct, str) };

MPI_Datatypetypes[4] = {MPI_INT,MPI_DOUBLE,MPI_DOUBLE,MPI_CHAR};

MPI_Type_create_struct(4, longblocs, positions, types, &dt);

MPI_Type_commit(&dt);

(24)

Opérations définies par l’utilisateur

Plan

1 Décomposition de domaine

2 Création de nouveaux communicateurs : Topologies cartésiennes

3 Création de nouveaux types de données

4 Opérations définies par l’utilisateur Création d’opération de réduction Exemple

(25)

Opérations définies par l’utilisateur Création d’opération de réduction

Définition d’opérations de réduction

Syntaxe

Définition d’unenouvelle opérationà utiliser avec les opérations de réduction : intMPI_Op_create(MPI_User_function ∗function,intcommute,MPI_Op∗op);

La fonctionfunctiondoit avoir le prototype suivant :

voidMPI_User_function (void∗invec,void∗inoutvec,int∗len,MPI_Datatype∗dt);

La fonction doit être associative.

Elle peut être commutative (commute=1) ou pas

(26)

Opérations définies par l’utilisateur Exemple

Exemple d’implémentation de MPI_PROD avec des nombres complexes typedef struct{

doublereal,imag;

} Complex;

/∗ la fonction de l’utilisateur ∗/

voidmyProd(void∗inTab,void∗inoutTab,int∗len,MPI_Datatype∗dptr ) { Complex c; Complex ∗in = (Complex ∗) inTab;

Complex ∗inout = (Complex ∗) inoutTab;

for(inti=0; i< ∗len; ++i) {

c.real = inout−>real ∗ in−>real − inout−>imag∗in−>imag;

c.imag = inout−>real ∗ in−>imag + inout−>imag∗in−>real;

∗inout = c;

in++; inout++;

} }

intmain (intargc,char∗argv[]) { // ... declarations

MPI_Opmyop;

/∗ construction du type complexe pour MPI : 2 réels∗/

MPI_Type_contiguous(2,MPI_DOUBLE, &mpicomplex);

MPI_Type_commit(&mpicomplex);

/∗ creation de l’operateur ∗/

MPI_Op_create(myProd, 1, &myop);

//... initialisations

MPI_Reduce(sendBuf, recvBuf, 2, mpicomplex, myop, 0,MPI_COMM_WORLD);

//...

}

Références

Documents relatifs

3. Tout intervalle [a, b] ne rencontrant pas A ne contient qu’un nombre fini des u n. grande) valeur d’adh´ erence. de la suite (u

For a long time Mira variables, OH/IR- and Carbon- stars were the most frequently studied Asymptotic Giant Branch (AGB) objects.. The Semiregular (types SRa and SRb) and the

Parallélisme au niveau matériel Processeur super-scalaire.

1962 premier ordinateur multiprocs (4) mais système non parallèle 1964 premier ordi double cœur et premier ordinateur à structure parallèle.. 1965 premier

Algorithmes distribués classiques (1ère partie) Éveil distribué par inondation.

Tout mesg envoyé à un site est placé dans sa file d’attente.. L’ordonnanceur du réseau permet aux

Si on a un algo d’élection alors on a un algo d’AC (en ajoutant 2m messages et D unités de temps). AC −→ élection (en ajoutant n − 1 messages et h unités de temps, où h est

pire des cas atteint pour un anneau avec identités en ordre décroissant et tous initiateurs... Donc 3n −