Calcul parallèle et distribué, grilles de calculs

Documents pareils
Introduction à la Programmation Parallèle: MPI

Systèmes parallèles et distribués

Plan de la formation. Calcul parallèle avec MPI. Pourquoi paralléliser? Parallélisation. Présentation, environnement MPI. Communications point à point

MPI-1 2ème partie : Programmation «non bloquante» et communications de groupe

Introduction to Parallel Programming with MPI

Le prototype de la fonction main()

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Programmation système de commandes en C

Cours de C. Petits secrets du C & programmation avancée. Sébastien Paumier

Grid Computing. Mihaela JUGANARU-MATHIEU École Nationale Supérieure des Mines de St Etienne

Programmation système I Les entrées/sorties

Introduction au langage C

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

INFO-F-404 : Techniques avancées de systèmes d exploitation

3IS - Système d'exploitation linux - Programmation système

I. Introduction aux fonctions : les fonctions standards

Cahier des charges. driver WIFI pour chipset Ralink RT2571W. sur hardware ARM7

OS Réseaux et Programmation Système - C5

Brefs rappels sur la pile et le tas (Stack. / Heap) et les pointeurs

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Cours Langage C/C++ Programmation modulaire

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Cours 6 : Tubes anonymes et nommés

Conventions d écriture et outils de mise au point

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Archivage Messagerie Evolution pour usage HTML en utilisant Hypermail

Compression de Données - Algorithme de Huffman Document de Conception

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Arguments d un programme

DNS Server RPC Interface buffer overflow. Céline COLLUMEAU Nicolas BODIN

Cours Programmation Système

Programmation système en C/C++

Les communications collectives. Caractéristiques. Communications dans un groupe de processus. Dans un communicateur donné.

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

Introduction au calcul parallèle avec OpenCL

Généralités sur le Langage Java et éléments syntaxiques.

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Rappels Entrées -Sorties

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

IRL : Simulation distribuée pour les systèmes embarqués

Lier Erlang avec d autres langages de programmation

Les chaînes de caractères

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Programmation en langage C

COMPARAISONDESLANGAGESC, C++, JAVA ET

Runtime. Gestion de la réactivité des communications réseau. François Trahay Runtime, LaBRI sous la direction d'alexandre Denis Université Bordeaux I

Exercices INF5171 : série #3 (Automne 2012)

INF 104 (SELC) Introduction au langage C

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Gestion de la mémoire

Algorithmique et Programmation, IMA

Les processus légers : threads. Système L3, /31

RapidMiner. Data Mining. 1 Introduction. 2 Prise en main. Master Maths Finances 2010/ Présentation. 1.2 Ressources

Cours de C. Allocation dynamique. Sébastien Paumier

Programmation impérative

Le système de gestion des fichiers, les entrées/sorties.

Chapitre 1 : La gestion dynamique de la mémoire

Premiers Pas en Programmation Objet : les Classes et les Objets

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Cours 1: Java et les objets

Le langage C. Séance n 4

Cours 14 Les fichiers

Introduction à la programmation concurrente

Grid Computing. Plan du cours. Plan. Composants d une Grille. Nouredine.Melab@lifl.fr. Besoin d intergiciels robustes

Architecture des ordinateurs

Java Licence Professionnelle CISII,

Recherche dans un tableau

Programmation Réseau SSH et TLS (aka SSL)

Programmation C. Apprendre à développer des programmes simples dans le langage C

Bases de programmation. Cours 5. Structurer les données

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie


UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

Programmation C. J.-F. Lalande. 15 novembre 2012

I00 Éléments d architecture

Génération de code binaire pour application multimedia : une approche au vol

DÉVELOPPEMENT INFONUAGIQUE - meilleures pratiques

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Groupe calcul parallèle

Chapitre 1 : Introduction aux bases de données

Algorithmique & Langage C IUT GEII S1. Notes de cours (première partie) cours_algo_lgc1.17.odp. Licence

Communication par sockets

Chap III : Les tableaux

Initiation. àl algorithmique et à la programmation. en C

Suivant les langages de programmation, modules plus avancés : modules imbriqués modules paramétrés par des modules (foncteurs)

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

Systèmes distribués et virtualisation de ressources

Chapitre 2. Classes et objets

TP2 - Conguration réseau et commandes utiles. 1 Généralités. 2 Conguration de la machine. 2.1 Commande hostname

Dans le chapitre 1, nous associions aux fichiers ouverts des descripteurs de fichiers par lesquels nous accédions aux fichiers.

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février :30 à 20:30

#include <stdio.h> #include <stdlib.h> struct cell { int clef; struct cell *suiv; };

Programmation Structurée en Langage C

Le traitement du temps

Cours d initiation à la programmation en C++ Johann Cuenin

Programmation en C - Sommaire

Transcription:

Calcul parallèle et distribué, grilles de calculs Yann Jullian Université François Rabelais yann.jullian@univ-tours.fr http://www.lmpt.univ-tours.fr/~jullian/ 23 mars 2016

Plan 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut 3 Communications point à point Principe Exemple Types de données de base Remarques

Plan 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce 5 Modes de communications Fonctions Communications bloquantes

Plan Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes 6 Deadlocks Dénition Exemple 7 Types de données dérivés Introduction Extraction contiguë : MPI_Type_contiguous Extraction à pas constant : MPI_Type_vector Extraction à pas variable : MPI_Type_indexed Padding Structure de données MPI_Type_create_struct 8 Communicateurs Partitionner un communicateur 9 Analyse de codes MPI

Plan Debug Méthodologie de debug de code MPI Prolage Mesures temporelles simples MPIP MPE OProle Autres problèmes Opérations otantes Race condition

Introduction 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Mémoire partagée 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Mémoire partagée Une unique machine. Tous les c urs de tous les processeurs ont accès à la mémoire. Noeud 0 C0 C1 C0 C1 C2 C3 C2 C3 C0 C1 C0 C1 Memoire C2 C3 C2 C3 Avantage Parallélisation simple (OpenMP par exemple). Inconvénient Nombre de processeurs et mémoire limités au départ. Pas d'extension possible au delà de la capacité de la machine sur laquelle on exécute.

Introduction Mémoire distribuée 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Mémoire distribuée Plusieurs machines connectées en réseaux. Les processeurs d'un n ud n'ont pas accès aux mémoires des autres n uds. Noeud 0 Noeud 1 C0 C1 C0 C1 C0 C1 C0 C1 C2 C3 C2 C3 C2 C3 C2 C3 C0 C1 C0 C1 Memoire C0 C1 C0 C1 Memoire C2 C3 C2 C3 C2 C3 C2 C3 Avantage Reseau On peut étendre le système en ajoutant des n uds.

Introduction Mémoire distribuée Inconvénients Nécessité de transférer la mémoire d'un n ud à l'autre. Le coût de communication réseau peut être élevé si le volume de données à communiquer est important. Le coût d'un transfert réseau sera toujours beaucoup plus important qu'une simple copie mémoire.

Introduction Exemples de clusters 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Exemples de clusters Ada 332 n uds de calculs 4 processeurs Intel E 5 4650 (8 c urs) à 2.7 GHz par n ud 10624 c urs 46 To de RAM 233 Tops théoriques, 192 Tops (linpack) Puissance : 244 kwatt Écacité énergétique : 786 Mops / watt http://www.idris.fr/ada/ada-presentation.html

Introduction Exemples de clusters Turing 6144 n uds de calculs 16 processeurs POWER A2 (1 c ur) à 1.6 GHz par n ud 98304 c urs 96 To de RAM 1258 Tops théoriques, 1073 Tops (linpack) Puissance : 493 kwatt Écacité énergétique : 2176 Mops / watt http://www.idris.fr/turing/turing-presentation.html

Introduction Message Passing Interface 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Message Passing Interface Message Passing Interface (MPI) C'est un ensemble de règles dénissant les communications entre processus, possiblement de n uds diérents. C'est l'outil standard pour les communications dans les clusters. Il en existe plusieurs implémentations dans diérents langages (C, C++ (abandonné avec MPI-3), Fortran) mais peut aussi être appelé depuis Java, Python... Une implémentation fournit un ensemble de fonctions permettant la communication et les échanges de données.

Introduction Message Passing Interface Principe d'un code utilisant MPI. Plusieurs processus sont lancés en parallèle. Chaque processus exécute le programme. Le programme décrit le rôle de chaque processus. La bibliothèque se focalise sur la synchronisation des processus et l'échange de données entre ceux-ci.

Introduction Message Passing Interface Un message MPI est constitué de : un communicateur (essentiellement un ensemble de processus), un identicateur du processus émetteur, le type de la donnée transférée, sa longueur, la donnée elle même, un identicateur du processus récepteur. Tous ces constituants devront être présent à l'appel des fonctions MPI.

Introduction Exemples de domaines d'applications 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Exemples de domaines d'applications Prévisions météorologique, Cryptographie, Modélisation d'explosion nucléaire, Astrophysique, Dynamique des particules (calculs des interactions), Pattern matching (comparaison d'adn, traitement d'images).

Introduction Quelques liens 1 Introduction Mémoire partagée Mémoire distribuée Exemples de clusters Message Passing Interface Exemples de domaines d'applications Quelques liens

Introduction Quelques liens Implémentations open source. MPICH2 : http://www.mpich.org OpenMPI : http://www.open-mpi.org Documentation. http://www.open-mpi.org/doc/v1.10/ http://www.mpi-forum.org/docs/ Machines. http://top500.org/ http://green500.org/ Sources. http://www.idris.fr/data/cours/parallel/mpi/idrismpi.pdf

Environnement 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut

Environnement Premier exemple 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut

Environnement Premier exemple #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); printf("sup.\n"); MPI_Finalize(); } return 0; Tout programme faisant appel à MPI doit : inclure <mpi.h>, initialiser l'environnement avec MPI_Init, désactiver l'environnement avec MPI_Finalize.

Environnement Compilation, exécution 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut

Environnement Compilation, exécution $ mpicc -o source source.c $ mpirun source mpicc n'est en fait qu'un appel élaboré à gcc : mpicc -showme Sans plus de précisions, mpirun exécute source une seule fois sur localhost (équivalent à passer l'option n1). L'option n permet de préciser le nombre de processus par machine. La commande mpirun -n 4 source exécute source quatre fois sur localhost.

Environnement Compilation, exécution L'option host permet de préciser les machines à utiliser. mpirun -host host0,host1 source exécute source une fois sur host0 et une fois sur host1. On peut combiner n et host. Si le nombre de processus donné est supérieur au nombre de machine, on remonte à la première machine. mpirun -n 3 -host host0,host1 source exécute source une fois sur host0, une fois sur host1, puis une autre fois sur host0.

Environnement Compilation, exécution On peut aussi utiliser l'option hostle avec un chier d'entrée. $ cat hosts host0 slots=2 host1 slots=4 mpirun -n 7 -hostle hosts source exécute source deux fois sur host0, quatre fois sur host1, puis une dernière fois sur host0. man mpirun pour plus d'options et plus de détails sur le chier hosts.

Environnement Comparaison avec OpenMP 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut

Environnement Comparaison avec OpenMP OpenMP MPI Une seule instance du programme est exécutée : il n'y a qu'un seul processus. Le processus se divise en plusieurs threads exécutés en parallèle. Les parties parallèles sont délimités par des directives pré-processeurs (#pragma). Plusieurs instances du programme sont exécutées en même temps : plusieurs processus sont créés. Chaque processus exécute l'intégralité du programme, et les processus s'exécutent en parallèle. MPI_Init et MPI_Finalize ne correspondent pas aux début et n de la partie parallélisée.

Environnement Communicateur par défaut 2 Environnement Premier exemple Compilation, exécution Comparaison avec OpenMP Communicateur par défaut

Environnement Communicateur par défaut Les processus lancés par mpirun doivent pouvoir communiquer entre eux. Tous les processus sont reliés par le communicateur par défaut MPI_COMM_WORLD. MPI_COMM_WORLD est créé par MPI_Init et détruit par MPI_Finalize. Chaque processus a un rang qui l'identie dans MPI_COMM_WORLD. C'est grâce à ce rang qu'on eectue le partage des tâches. Toutes les communications entre processus passent par un communicateur.

Environnement Communicateur par défaut #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int world_size; MPI_Comm_size(MPI_COMM_WORLD, &world_size); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); if (wrank!=1) printf("rang %d sur %d.\n", wrank, world_size); } MPI_Finalize(); return 0;

Environnement Communicateur par défaut $ mpirun -n 4 source Rang 2 sur 4. Rang 0 sur 4. Rang 3 sur 4. Chaque processus de rang 1 appelle printf (une seule fois) avec son rang. L'ordre de sortie est indéni.

Communications point à point 3 Communications point à point Principe Exemple Types de données de base Remarques

Communications point à point Principe 3 Communications point à point Principe Exemple Types de données de base Remarques

Communications point à point Principe Une communication dite point à point a lieu entre deux processus : l'émetteur et le récepteur (ou destinataire). L'émetteur et le récepteur sont identiés par leur rang dans le communicateur. L'enveloppe d'un message est constituée : du communicateur (qui doit contenir les deux processus), du rang du processus émetteur, du rang du processus récepteur, de l'étiquette (un identiant) du message. Il faut préciser le type des données communiquées. Il existe plusieurs modes de transfert.

Communications point à point Exemple 3 Communications point à point Principe Exemple Types de données de base Remarques

Communications point à point Exemple int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status); comm : le communicateur. tag : l'identiant du message. dest/source : le rang du processus récepteur/émetteur dans le communicateur comm. datatype : le type des données à envoyer/recevoir. count : le nombre de données de type datatype à envoyer/recevoir. buf : l'adresse du début des données à envoyer/recevoir.

Communications point à point Exemple #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int witness = 0; if (wrank==2) { int modifier = 1; MPI_Send(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD); } else if (wrank==3) MPI_Recv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } printf("rang %d, witness %d.\n", wrank, witness); MPI_Finalize(); return 0;

Communications point à point Exemple $ mpirun -n 4 source Rang 1, witness 0. Rang 0, witness 0. Rang 2, witness 0. Rang 3, witness 1. Pour passer plusieurs valeurs : int witness[] = {0, 0}; if (wrank==2) { int modifier[] = {1, 1}; MPI_Send(modifier, 2, MPI_INT, 3, 28, MPI_COMM_WORLD); } else if (wrank==3) MPI_Recv(witness, 2, MPI_INT, 2, 28, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

Communications point à point Exemple Note. Pour toutes les communications, il faut préciser à la fois un type pour l'émission et un type pour la réception. Le transfert de données se fait grâce à un simple ux d'octets (pas de données sur le type). C'est au programmeur de vérier que les types d'émission et de réception sont les mêmes, ou au moins qu'ils sont compatibles (voir exemples frames 138 et 143). La communication réussira si le nombre d'octets émis est égal au nombre d'octets reçus. Ainsi, on peut par exemple envoyer un tableau de deux int et recevoir un seul long ou même un seul double.

Communications point à point Types de données de base 3 Communications point à point Principe Exemple Types de données de base Remarques

Communications point à point Types de données de base Type MPI Type C Taille des types C (octets) MPI_CHAR char 1 MPI_SHORT short 2 MPI_INT int 4 MPI_LONG long int 8 MPI_UNSIGNED_CHAR unsigned char 1 MPI_UNSIGNED_SHORT unsigned short 2 MPI_UNSIGNED unsigned int 4 MPI_UNSIGNED_LONG unsigned long int 8 MPI_FLOAT float 4 MPI_DOUBLE double 8 MPI_LONG_DOUBLE long double 16 Tous les types MPI_* ont pour taille 8 octets.

Communications point à point Remarques 3 Communications point à point Principe Exemple Types de données de base Remarques

Communications point à point Remarques À la réception d'un message, le rang de l'émetteur et l'étiquette peuvent être des jokers, respectivement MPI_ANY_SOURCE et MPI_ANY_TAG. Le processus récepteur ne sort de l'appel à MPI_Recv que lorsque l'intégralité du message du tag spécié a été reçu. Le processus émetteur, en revanche, peut sortir de l'appel à MPI_Send avant que le message ne soit envoyé (voir frame 107). MPI_STATUS_IGNORE est une constante prédénie qui peut être utilisée à la place de la variable statut. On peut créer et communiquer des structures de données plus complexes (voir frame 150).

Communications collectives 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Notions générales 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Notions générales Les communications collectives permettent de faire en une seule opération une série de communications point à point. Une communication collective concerne toujours tous les processus du communicateur indiqué. Pour chacun des processus, l'appel se termine lorsque la participation de celui-ci à l'opération collective est achevée, au sens des communications point-à-point. On ne dénit jamais les étiquettes explicitement ; le système les gère de manière transparente. Avantage : les communications collectives n'interfèrent jamais avec les communications point à point.

Communications collectives Notions générales Il y a trois types de communications collectives. 1 Synchronisation globale : MPI_Barrier. 2 Transfert de données uniquement : diusion globale de données : MPI_Bcast, diusion sélective de données : MPI_Scatter, MPI_Scatterv, collecte de données réparties : MPI_Gather, MPI_Gatherv, collecte par tous les processus de données réparties : MPI_Allgather, collecte et diusion sélective, par tous les processus, de données réparties : MPI_Alltoall. 3 Transfert et eectue des opérations sur des données : réduction (somme, produit, maximum, minimum, etc.), qu'elles soient d'un type prédéni ou d'un type personnel : MPI_Reduce, réduction avec diusion du résultat (équivalent à un MPI_Reduce suivi d'un MPI_Bcast ) : MPI_Allreduce.

Communications collectives Synchronisation globale : MPI_Barrier 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Synchronisation globale : MPI_Barrier int MPI_Barrier(MPI_Comm comm); P0 P2 Les processus reprennent leurs exécutions. Barrier P1 P3 P0 P1 P2 P3 Processus 3 bloqué en attente des processus 0, 1, 2. Tous les processus ont atteints la barrière. P1 P2 P3 P0 Tous les processus du communicateur doivent appeler la fonction MPI_Barrier. Un processus qui appelle la fonction reste bloqué et doit attendre que tous les autres processus du communicateur l'appellent. Lorsque tous les processus du communicateur ont appelé la fonction, tous reprennent ensemble leurs exécutions.

Communications collectives Synchronisation globale : MPI_Barrier #include <mpi.h> #include <stdio.h> #include <time.h> int main(int argc, char ** argv) { MPI_Init(&argc, &argv); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); if (wrank==0) { FILE* f = fopen("outin", "w"); long int seconds = time(null); fprintf(f, "%ld", seconds); fclose(f); } MPI_Barrier(MPI_COMM_WORLD);

Communications collectives Synchronisation globale : MPI_Barrier long int witness = 0; FILE* f = fopen("outin", "r"); fscanf(f, "%d", &witness); printf("rang %d, witness %ld.\n", wrank, witness); fclose(f); } MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 1, witness 1450259857. Rang 0, witness 1450259857. Rang 2, witness 1450259857. Rang 3, witness 1450259857.

Communications collectives Synchronisation globale : MPI_Barrier Sortie possible si on enlève l'appel à MPI_Barrier. $ mpirun -n 4 source Rang 1, witness 1450259857. Rang 3, witness 1450259857. Rang 0, witness 1450259860. Rang 2, witness 1450259860. Dans ce cas, les processus 1 et 3 ont lu le chier avant que celui-ci ne soit modié par le processus 0, et ils récupèrent donc la valeur contenue dans le chier avant l'exécution du programme. Les processus 0 et 2 ont lu le chier après modication, et récupèrent donc la nouvelle valeur.

Communications collectives Synchronisation globale : MPI_Barrier Remarques La fonction MPI_Barrier ne prend pas d'identiant de message en argument. La conséquence est que les processus peuvent appeler des MPI_Barrier diérents (situés à diérents endroits du programme). Ainsi, le code if (wrank==0) MPI_Barrier(MPI_COMM_WORLD); else MPI_Barrier(MPI_COMM_WORLD); aura le même eet que MPI_Barrier(MPI_COMM_WORLD);

Communications collectives Synchronisation globale : MPI_Barrier En interne, MPI_Barrier eectue les étapes suivantes : Chaque processus de rang 0 envoie un message vide au processus de rang 0 et attend une réponse, le processus de rang 0 attend d'avoir reçu des messages de tous les processus (sauf lui même), lorsque le processus 0 a reçu tous les messages, il envoie une réponse (un autre message vide) à tous les processus, leur signalant ainsi que tous les processus ont atteints une barrière, les processus 0 quittent MPI_Barrier à la reception de cette réponse, le processus 0 quitte MPI_Barrier après l'envoi de toutes les réponses. MPI_Barrier est l'unique fonction qui permet d'assurer la synchronisation entre les processus. En particulier, aucune des opérations collectives présentées par la suite n'assure la synchronisation.

Communications collectives Diusion générale : MPI_Bcast 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Diusion générale : MPI_Bcast int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm); count P0 P1 P2 P3 Tous les processus du communicateur doivent appeler la fonction MPI_Bcast. Le processus de rang root est l'unique émetteur, tous sont récepteurs. Après l'appel, les count données de type datatype pointées par buffer sont égales pour tous les processus.

Communications collectives Diusion générale : MPI_Bcast #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(&argc, &argv); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int witness = wrank; MPI_Bcast(&witness, 1, MPI_INT, 2, MPI_COMM_WORLD); } printf("rang %d, witness %d.\n", wrank, witness); MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 1, witness 2. Rang 0, witness 2. Rang 2, witness 2. Rang 3, witness 2.

Communications collectives Diusion sélective : MPI_Scatter 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Diusion sélective : MPI_Scatter int MPI_Scatter( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); P0 P1 P2 P3 Tous les processus du communicateur doivent appeler la fonction MPI_Scatter. Le processus de rang root est l'unique emetteur, tous sont récepteurs. sendcount est le nombre de données émises à un seul processus.

Communications collectives Diusion sélective : MPI_Scatter MPI_Scatter découpe la donnée à envoyer en plusieurs (autant que de processus dans le communicateur) morceaux de taille sendcount. L'ordre des données envoyés correspond à l'ordre des rangs des processus récepteurs : le ième jeu de données est envoyé au processus de rang i. Le nombre total de données émises est sendcount * (nombre de processus dans le communicateur). sendcount*sizeof(sendtype) == recvcount*sizeof(recvtype) #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank);

Communications collectives Diusion sélective : MPI_Scatter } int array[] = {wrank, 2*wrank, 3*wrank, 4*wrank}; int witness=0; MPI_Scatter(array, 1, MPI_INT, &witness, 1, MPI_INT, 2, MPI_COMM_WORLD); printf("rang %d, witness %d.\n", wrank, witness); MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 0, witness 2. Rang 1, witness 4. Rang 2, witness 6. Rang 3, witness 8.

Communications collectives Collecte : MPI_Gather 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Collecte : MPI_Gather int MPI_Gather( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); P0 P1 P2 P3 C'est l'opération inverse de MPI_Scatter. root est l'unique récepteur, tous sont émetteurs. sendcount est le nombre de données émises par un seul processus. Les données sont collectées dans l'ordre des rangs des processus. Mêmes contraintes que MPI_Scatter sur les tailles des données.

Communications collectives Collecte : MPI_Gather #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int witness[] = {0, 0, 0, 0}; MPI_Gather(&wrank, 1, MPI_INT, witness, 1, MPI_INT, 2, MPI_COMM_WORLD); printf("rang %d, witness", wrank); for (int i=0; i<4; ++i) printf(" %d", witness[i]); printf(".\n"); } MPI_Finalize(); return 0;

Communications collectives Collecte : MPI_Gather $ mpirun -n 4 source Rang 0, witness 0 0 0 0. Rang 3, witness 0 0 0 0. Rang 1, witness 0 0 0 0. Rang 2, witness 0 1 2 3.

Communications collectives Collecte générale : MPI_Allgather 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Collecte générale : MPI_Allgather int MPI_Allgather( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) P0 P1 P2 P3 Tous les processus sont émetteurs, et tous sont récepteurs. sendcount est le nombre de données émises par un processus, pour un processus. Les données sont collectées dans l'ordre des rangs des processus. Revient à faire MPI_Gather avec le processus 0 comme récepteur, suivi de MPI_Gather avec le processus 1 comme récepteur, et ainsi de suite pour tous les processus.

Communications collectives Collecte générale : MPI_Allgather #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int witness[] = {0, 0, 0, 0}; MPI_Allgather(&wrank, 1, MPI_INT, witness, 1, MPI_INT, MPI_COMM_WORLD); printf("rang %d, witness", wrank); for (int i=0; i<4; ++i) printf(" %d", witness[i]); printf(".\n"); } MPI_Finalize(); return 0;

Communications collectives Collecte générale : MPI_Allgather $ mpirun -n 4 source Rang 0, witness 0 1 2 3. Rang 3, witness 0 1 2 3. Rang 2, witness 0 1 2 3. Rang 1, witness 0 1 2 3.

Communications collectives Diusion : MPI_Scatterv 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Diusion : MPI_Scatterv int MPI_Scatterv( const void *sendbuf, const int sendcounts[], const int displs[], MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) P0 P1 P2 indices 0 1 3 4 P3 Même fonctionnement et propriétés que MPI_Scatter, mais on peut régler le nombre et l'emplacement des données émises avec les arguments sendcounts et displs (displacements / osets). Les deux arguments sendcounts et displs ne servent que pour le processus émetteur. La taille sendcounts et displs est le nombre de processus dans le communicateur.

Communications collectives Diusion : MPI_Scatterv P0 P1 P2 indices 0 1 3 4 P3 Seulement pour P2 : P0 P1 P2 P3 recvcount 1 2 1 2 sendbuf de taille 1 + 2 + 1 + 2 = 6, sendcounts = {1, 2, 1, 2} displs = {0, 1, 3, 4}.

Communications collectives Diusion : MPI_Scatterv #include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { MPI_Init(NULL, NULL); int world_size, wrank; MPI_Comm_size(MPI_COMM_WORLD, &world_size); MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int recvbuf[] = {wrank, wrank}; int recvcount = (wrank%2) + 1; int *sendbuf, *sendcounts, *displs; int total = 6; if (wrank==2) { sendcounts = (int*) calloc(world_size, sizeof(int)); for (int i=0; i<world_size; ++i) sendcounts[i]= (i%2) + 1;

Communications collectives Diusion : MPI_Scatterv displs = (int*) calloc(world_size, sizeof(int)); displs[0] = 0; for (int i=1; i<world_size; ++i) displs[i] = displs[i-1] + sendcounts[i-1]; } sendbuf = (int*) calloc(total, sizeof(int)); for (int i=0; i<total; ++i) sendbuf[i] = 28+i; MPI_Scatterv(sendbuf, sendcounts, displs, MPI_INT, recvbuf, recvcount, MPI_INT, 2, MPI_COMM_WORLD); printf("rang %d, recvbuf %d %d.\n", wrank, recvbuf[0], recvbuf[1]); if (wrank==2) { free(sendcounts); free(displs); free(sendbuf); }

Communications collectives Diusion : MPI_Scatterv } MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 0, recvbuf 28 0. Rang 1, recvbuf 29 30. Rang 2, recvbuf 31 2. Rang 3, recvbuf 32 33.

Communications collectives Collecte : MPI_Gatherv 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Collecte : MPI_Gatherv int MPI_Gatherv( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm) P0 P1 P2 indices 0 1 3 4 P3 Même fonctionnement et propriétés que MPI_Gather, mais on peut régler le nombre et l'emplacement des données reçues avec les arguments recvcounts et displs (displacements / osets). Les deux arguments recvcounts et displs ne servent que pour le processus récepteur. La taille recvcounts et displs est le nombre de processus dans le communicateur.

Communications collectives Collecte : MPI_Gatherv P0 P1 P2 indices 0 1 3 4 P3 Seulement pour P2 : P0 P1 P2 P3 sendcount 1 2 1 2 recvbuf de taille 1 + 2 + 1 + 2 = 6, recvcounts = {1, 2, 1, 2} displs = {0, 1, 3, 4}.

Communications collectives Collecte : MPI_Gatherv #include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int world_size, wrank; MPI_Comm_size(MPI_COMM_WORLD, &world_size); MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int sendbuf[] = {wrank, wrank}; int sendcount = (wrank%2) + 1; int *recvbuf, *recvcounts, *displs; int total = 6; if (wrank==2) { recvcounts = (int*) calloc(world_size, sizeof(int)); for (int i=0; i<world_size; ++i) recvcounts[i]= (i%2) + 1;

Communications collectives Collecte : MPI_Gatherv displs = (int*) calloc(world_size, sizeof(int)); displs[0] = 0; for (int i=1; i<world_size; ++i) displs[i] = displs[i-1] + recvcounts[i-1]; } recvbuf = (int*) calloc(total, sizeof(int)); MPI_Gatherv(sendbuf, sendcount, MPI_INT, recvbuf, recvcounts, displs, MPI_INT, 2, MPI_COMM_WORLD); if (wrank==2) { for (int i=0; i<total; ++i) printf("%d ", recvbuf[i]); printf("\n"); } free(recvcounts); free(displs); free(recvbuf);

Communications collectives Collecte : MPI_Gatherv } MPI_Finalize(); return 0; $ mpirun -n 4 source 0 1 1 2 3 3.

Communications collectives Collectes et diusions sélectives : MPI_Alltoall 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Collectes et diusions sélectives : MPI_Alltoall int MPI_Alltoall( const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) P0 a b c d a a a a P1 a b c d b b b b P2 a b c d c c c c P3 a b c d d d d d Correspond à un MPI_Allgather où la donnée envoyée dépend du processus récepteur. Le ième processus envoie le jème jeu de données au jème processus qui le place dans à la ième place.

Communications collectives Collectes et diusions sélectives : MPI_Alltoall #include <math.h> #include <mpi.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int world_size, wrank; MPI_Comm_size(MPI_COMM_WORLD, &world_size); MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int power = pow(10, wrank+1); int sendbuf[] = {power, power+1, power+2, power+3}; int recvbuf[] = {0, 0, 0, 0}; MPI_Alltoall(sendbuf, 1, MPI_INT, recvbuf, 1, MPI_INT, MPI_COMM_WORLD);

Communications collectives Collectes et diusions sélectives : MPI_Alltoall printf("rang %d, recvbuf", wrank); for (int i=0; i<world_size; ++i) printf(" %d", recvbuf[i]); printf(".\n"); } MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 0, recvbuf 10 100 1000 10000. Rang 1, recvbuf 11 101 1001 10001. Rang 2, recvbuf 12 102 1002 10002. Rang 3, recvbuf 13 103 1003 10003.

Communications collectives Réductions réparties : MPI_Reduce 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Réductions réparties : MPI_Reduce Une réduction est une opération appliquée à un ensemble d'éléments pour en obtenir une seule valeur. Par exemple, somme/maximum d'éléments venant de plusieurs processus. int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); P0 1 somme P0 1 maximum P1 10 P1 10 P2 100 1111 P2 100 1000 P3 1000 P3 1000 L'argument op permet de choisir l'opération de réduction. Voir frame 93 pour la liste des opérations prédénies.

Communications collectives Réductions réparties : MPI_Reduce Si chaque processus envoie un tableau, la fonction de réduction est appliquée pour chaque indice. P0 1 2 somme P0 1 2 maximum P1 10 20 P1 10 20 P2 100 200 1111 2222 P2 100 200 1000 2000 P3 1000 2000 P3 1000 2000 Les fonctions MPI_Op_create et MPI_Op_free permettent de dénir des opérations de réductions personnelles.

Communications collectives Réductions réparties : MPI_Reduce Principales opérations de réduction prédénies. Nom MPI_SUM MPI_PROD MPI_MAX MPI_MIN MPI_MAXLOC MPI_MINLOC MPI_LAND MPI_LOR MPI_LXOR Opération Somme des éléments Produit des éléments Maximum des éléments Minimum des éléments Maximum + indice (voir exemple) Minimum + indice (voir exemple) ET logique OU logique OU exclusif logique

Communications collectives Réductions réparties : MPI_Reduce, MPI_SUM 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Réductions réparties : MPI_Reduce, MPI_SUM #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); int seeds[] = {wrank, 2*wrank}; int sums[] = {0, 0}; MPI_Reduce(&seeds, &sums, 2, MPI_INT, MPI_SUM, 2, MPI_COMM_WORLD); } printf("rang %d, sums %d %d.\n", wrank, sums[0], sums[1]); MPI_Finalize(); return 0;

Communications collectives Réductions réparties : MPI_Reduce, MPI_SUM $ mpirun -n 4 source Rang 1, sums 0 0. Rang 0, sums 0 0. Rang 2, sums 6 12. Rang 3, sums 0 0.

Communications collectives Réductions réparties : MPI_Reduce, MPI_MAXLOC 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Réductions réparties : MPI_Reduce, MPI_MAXLOC #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); struct { double val; int rank; } in, out; in.val = 10*wrank; in.rank = wrank; MPI_Reduce(&in, &out, 1, MPI_DOUBLE_INT, MPI_MAXLOC, 2, MPI_COMM_WORLD); } printf("rang %d, out %f %d.\n", wrank, out.val, out.rank); MPI_Finalize(); return 0;

Communications collectives Réductions réparties : MPI_Reduce, MPI_MAXLOC $ mpirun -n 4 source Rang 0, out 0.000000 0. Rang 3, out 0.000000 0. Rang 2, out 30.000000 3. Rang 1, out 0.000000 0. Utile pour savoir d'où vient le maximum. Il existe d'autres types de paires MPI : MPI_FLOAT_INT, MPI_LONG_INT, MPI_DOUBLE_INT, MPI_SHORT_INT, MPI_2INT, MPI_LONG_DOUBLE_INT.

Communications collectives Réductions réparties : MPI_Allreduce 4 Communications collectives Notions générales Synchronisation globale : MPI_Barrier Diusion générale : MPI_Bcast Diusion sélective : MPI_Scatter Collecte : MPI_Gather Collecte générale : MPI_Allgather Diusion : MPI_Scatterv Collecte : MPI_Gatherv Collectes et diusions sélectives : MPI_Alltoall Réductions réparties : MPI_Reduce Réductions réparties : MPI_Reduce, MPI_SUM Réductions réparties : MPI_Reduce, MPI_MAXLOC Réductions réparties : MPI_Allreduce

Communications collectives Réductions réparties : MPI_Allreduce int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); P0 1 2 somme 1111 2222 P1 10 20 1111 2222 P2 100 200 1111 2222 P3 1000 2000 1111 2222 Tous les processus calculent la réduction, et obtiennent donc le même résultat. #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank);

Communications collectives Réductions réparties : MPI_Allreduce int seeds[] = {wrank, 2*wrank}; int sums[] = {0, 0}; MPI_Allreduce(&seeds, &sums, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD); } printf("rang %d, sums %d %d.\n", wrank, sums[0], sums[1]); MPI_Finalize(); return 0; $ mpirun -n 4 source Rang 1, sums 6 12. Rang 0, sums 6 12. Rang 2, sums 6 12. Rang 3, sums 6 12.

Modes de communications 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Fonctions 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Fonctions Bloquant Non bloquant Envoi standard MPI_Send MPI_Isend Envoi en mode buerisé MPI_Bsend MPI_Ibsend Envoi en mode synchrone MPI_Ssend MPI_Issend Envoi en mode ready MPI_Rsend MPI_Irsend Réception MPI_Recv MPI_Irecv Le mode utilisé par un envoi standard est décidé par MPI lors de chaque appel. Les fonctions MPI_Send, MPI_Bsend, MPI_Ssend, MPI_Rsend ont toutes le même prototype (voir frame 40) et sont interchangeables dans l'exemple frame 41. Les fonctions MPI_Isend, MPI_Ibsend, MPI_Issend, MPI_Irsend ont toutes le même prototype (voir frame 117) et sont interchangeables dans l'exemple frame 117.

Modes de communications Communications bloquantes 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Communications bloquantes On parle d'un appel bloquant lorsque l'espace mémoire servant à la communication (données + enveloppe) peut être réutilisé immédiatement après la sortie de l'appel. Par réutilisé, on veut dire : pour l'émetteur, les éléments du pointeur sur les données à envoyer peuvent être modiés, et le pointeur lui-même peut être libérer sans que cela inue sur la communication (typiquement, la fonction MPI a copié les données à transférer dans un buer temporaire, voir par exemple frame 110), pour le récepteur, le pointeur sur les données à recevoir contient l'intégralité des données transmises et les éléments peuvent être lus.

Modes de communications Communications bloquantes Confusion sur le terme bloquant (malheureusement standard) pour l'émetteur. Le terme s'applique à l'espace mémoire contenant les données à transmettre, pas à la communication. Le terme ne signie pas que l'émetteur attend la n de la communication pour sortir de la fonction MPI. L'émetteur peut même sortir de la fonction MPI avant que la transmission de données n'ait démarrée (voir frame 110). Pas de confusion pour le récepteur. Lorsque l'appel à la fonction MPI d'une réception bloquante termine, la communication est eectivement terminée.

Modes de communications Envoi bloquant, mode buerisé 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Envoi bloquant, mode buerisé Lors d'un envoi en mode buerisé, le message et l'enveloppe sont copiés à un autre endroit de la mémoire du processus émetteur. Fonction associée : MPI_Bsend. L'appel à MPI_Bsend peut se faire même si le processus récepteur n'est pas encore en attente du message (il n'a pas atteint la fonction de réception). L'appel à MPI_Bsend peut se terminer même si la totalité du message n'a pas été reçu, ou même si le processus récepteur n'a pas atteint la fonction de réception. Si le processus récepteur est en attente du message lors de l'appel à MPI_Bsend, le buer peut être omis.

Modes de communications Envoi bloquant, mode synchrone 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Envoi bloquant, mode synchrone Lors d'un envoi en mode synchrone, le processus émetteur doit attendre que la fonction de réception se termine. Fonction associée : MPI_Ssend. L'appel à MPI_Ssend peut se faire même si le processus récepteur n'est pas encore en attente du message (il n'a pas atteint la fonction de réception). C'est un bon moyen de synchroniser les deux processus. Dans le cas d'une réception non bloquante (et uniquement dans ce cas), la fonction de réception, et donc l'appel à MPI_Ssend, peuvent se terminer sans que le message soit complètement transmis.

Modes de communications Envoi bloquant, mode ready 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Envoi bloquant, mode ready Un envoi en mode ready n'est correct que si le processus récepteur est déjà en attente du message. Fonction associée : MPI_Rsend. Permet d'omettre certaines opérations de communications, mais nécessite d'ordonnancer les processus. Le comportement adopté lorsque le processus récepteur n'est pas en attente du message est indéni. Très peu utilisé car très risqué.

Modes de communications Communications non bloquantes 5 Modes de communications Fonctions Communications bloquantes Envoi bloquant, mode buerisé Envoi bloquant, mode synchrone Envoi bloquant, mode ready Communications non bloquantes

Modes de communications Communications non bloquantes Un appel non bloquant démarre l'émission ou la réception d'un message puis termine immédiatement (le programme continue son exécution). Permet de continuer les calculs pendant que la communication s'eectue. Tout appel non bloquant nécessite l'appel à la fonction MPI_Wait (ou une de ses déclinaisons) pour terminer correctement l'appel. Dans le cas d'un envoi non bloquant, la mémoire contenant le message ne doit pas être réutilisée (mais peut être lue) avant l'appel à MPI_Wait. Dans le cas d'une réception non bloquante, la mémoire destinée à recevoir le message ne doit pas être lue avant l'appel à MPI_Wait. Un envoi non bloquant peut être couplé à une réception bloquante et inversement.

Modes de communications Communications non bloquantes int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); int MPI_Wait(MPI_Request *request, MPI_Status *status) #include <mpi.h> #include <stdio.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank);

Modes de communications Communications non bloquantes int witness = 0; MPI_Request request; if (wrank==2) { int modifier = 1; MPI_Isend(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD, &request); // Computations. MPI_Wait(&request, MPI_STATUS_IGNORE); } else if (wrank==3) { MPI_Irecv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD, &request); // Other computations. MPI_Wait(&request, MPI_STATUS_IGNORE); } } printf("rang %d, witness %d.\n", wrank, witness); MPI_Finalize(); return 0;

Modes de communications Communications non bloquantes $ mpirun -n 4 source Rang 0, witness 0. Rang 2, witness 0. Rang 3, witness 1. Rang 1, witness 0. L'argument de type MPI_Request est un identiant de l'appel non bloquant. Il faut en allouer un par appel non bloquant.

Deadlocks 6 Deadlocks Dénition Exemple

Deadlocks Dénition 6 Deadlocks Dénition Exemple

Deadlocks Dénition On est en situation de deadlock lorsqu'un processus attend indéniment une action d'un autre processus. Note. Peut arriver lors de communications bloquantes, ou lors d'appel à MPI_Wait. Ils peuvent être provoqués par : un appel à MPI_Recv sans émission correspondante, soit parce qu'il n'y a simplement pas d'émission, soit à cause d'une erreur dans l'enveloppe de l'émission (un tag ou un processus émetteur incorrect), (le plus souvent) un ordonnancement incorrect des émissions / réceptions. Puisque le mode utilisé par MPI_Send n'est décidé qu'à l'appel de la fonction, certains programmes ne provoqueront pas systématiquement un deadlock, même si l'ordonnancement des émissions / réceptions est incorrect.

Deadlocks Exemple 6 Deadlocks Dénition Exemple

Deadlocks Exemple #include <mpi.h> int main(int argc, char** argv) { MPI_Init(NULL, NULL); int wrank; MPI_Comm_rank(MPI_COMM_WORLD, &wrank); if (wrank==0) { int send0 = 10, recv0; MPI_Send(&send0, 1, MPI_INT, 1, 28, MPI_COMM_WORLD); MPI_Recv(&recv0, 1, MPI_INT, 1, 42, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (wrank==1) { int send1 = 11, recv1; MPI_Send(&send1, 1, MPI_INT, 0, 42, MPI_COMM_WORLD); MPI_Recv(&recv1, 1, MPI_INT, 0, 28, MPI_COMM_WORLD, MPI_STATUS_IGNORE); }

Deadlocks Exemple } MPI_Finalize(); return 0; Si les deux appels à MPI_Send se font en mode synchrone, il y aura un deadlock. Si un des appels se fait en mode buerisé, il n'y aura pas de deadlock.

Deadlocks Exemple Le même programme avec des MPI_Ssend a place des MPI_Send provoquera systématiquement un deadlock. Une des manières de s'assurer que l'ordonnancement des communications est correct est d'utiliser des MPI_Ssend partout (mais le programme sera un peu plus lent). Une bonne règle d'écriture de programme MPI est de mettre des MPI_Ssend partout dans un premier temps, puis de les remplacer par des MPI_Send lorsqu'on est sûr que toutes les communications s'eectuent correctement.

Types de données dérivés 7 Types de données dérivés Introduction Extraction contiguë : MPI_Type_contiguous Extraction à pas constant : MPI_Type_vector Extraction à pas variable : MPI_Type_indexed Padding Structure de données MPI_Type_create_struct

Types de données dérivés Introduction 7 Types de données dérivés Introduction Extraction contiguë : MPI_Type_contiguous Extraction à pas constant : MPI_Type_vector Extraction à pas variable : MPI_Type_indexed Padding Structure de données MPI_Type_create_struct

Types de données dérivés Introduction Il est possible de créer ses propres types de données MPI. Le type créé sera de type MPI_Datatype. Tout type créé destiné à être utilisé pour une communication doit être enregistré à l'aide de la fonction MPI_Type_commit. int MPI_Type_commit(MPI_Datatype *datatype) Tout type créé avec un MPI_Type_commit doit être libéré par un MPI_Type_free (surtout si on veut réutiliser le nom). int MPI_Type_free(MPI_Datatype *datatype) Deux sortes de types peuvent être créés : extraction de données d'un tableau (MPI_Type_vector, MPI_Type_indexed), des types utilisés pour faire passer les structures qu'on dénit (MPI_Type_create_struct).

Types de données dérivés Extraction contiguë : MPI_Type_contiguous 7 Types de données dérivés Introduction Extraction contiguë : MPI_Type_contiguous Extraction à pas constant : MPI_Type_vector Extraction à pas variable : MPI_Type_indexed Padding Structure de données MPI_Type_create_struct

Types de données dérivés Extraction contiguë : MPI_Type_contiguous int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) count Le nombre total d'éléments de type oldtype contenu dans * newtype est count.