8 INF 859 Rvision Paralllisme de donnes Paralllisme

  • Slides: 111
Download presentation
8 INF 859 Révision

8 INF 859 Révision

�Parallélisme de données �Parallélisme de contrôle

�Parallélisme de données �Parallélisme de contrôle

�Multiprocesseur ◦ pthread ◦ Open. MP ◦ cilk �Multi-ordinateur ◦ MPI �GPU ◦ Open.

�Multiprocesseur ◦ pthread ◦ Open. MP ◦ cilk �Multi-ordinateur ◦ MPI �GPU ◦ Open. CL

1. Réseaux d’intercommunication �Utilités ◦ Connecter les processeurs à la mémoire partagée ◦ Connecter

1. Réseaux d’intercommunication �Utilités ◦ Connecter les processeurs à la mémoire partagée ◦ Connecter les processeurs entre eux

Topologie directe �Un commutateur pour chaque processeur �Chaque commutateur est connecté à: ◦ 1

Topologie directe �Un commutateur pour chaque processeur �Chaque commutateur est connecté à: ◦ 1 processeur ◦ Au moins un autre commutateur �En général, le nombre de processeurs est identique au nombre de commutateurs

Topologie indirecte �Le nombre de commutateurs peut être plus grand que le nombre de

Topologie indirecte �Le nombre de commutateurs peut être plus grand que le nombre de processeurs �Certains commutateurs ne sont connectés qu’à d’autres commutateurs.

Évaluation d’une topologie �Diamètre ◦ Distance maximale entre deux noeuds ◦ Borne inférieure sur

Évaluation d’une topologie �Diamètre ◦ Distance maximale entre deux noeuds ◦ Borne inférieure sur le temps de communication �Largeur de coupe ◦ Nombre min d’arêtes à enlever pour diviser le graphe en deux composantes connexes de même taille (à 1 neud près). ◦ Borne supérieure sur le nombre de messages pouvant être envoyés simultanément. �Degré = Nombre d’arêtes adjacentes à un noeud �Longueur des arêtes: �Une longueur constante permet plus facilement d’augmenter le nombre de processeurs.

�Grille 2 d �Tore �Arbre binaire hypercube �Réseau butterfly �Réseau shuffle-exchange

�Grille 2 d �Tore �Arbre binaire hypercube �Réseau butterfly �Réseau shuffle-exchange

5. Taxonomie de Flynn �Flux d’instructions �Flux de données �Simple vs. multiple �Quatre combinaisons

5. Taxonomie de Flynn �Flux d’instructions �Flux de données �Simple vs. multiple �Quatre combinaisons ◦ ◦ SISD SIMD MISD MIMD

SE pour multiprocesseurs(4) Bus � Type 3: Multiprocesseurs symétriques ◦ Tous les processeurs sont

SE pour multiprocesseurs(4) Bus � Type 3: Multiprocesseurs symétriques ◦ Tous les processeurs sont égaux ◦ Une seule copie du SE ◦ Problème: Il faut éviter les conflits. � Deux processeurs voulant utiliser la même page mémoire � Deux processeurs voulant éxécuter le même processus 10

Synchronisation des MPs (1) Solutions matérielles: � Verouiller le bus � Verouiller une adresse

Synchronisation des MPs (1) Solutions matérielles: � Verouiller le bus � Verouiller une adresse mémoire 11

Ordonnancement(1) �Sur monoprocesseur ◦ Quel est le prochain thread à exécuter? �Sur multiprocesseur �On

Ordonnancement(1) �Sur monoprocesseur ◦ Quel est le prochain thread à exécuter? �Sur multiprocesseur �On doit maintenant se poser deux questions plutôt qu’une seule �Quel est le prochain thread a exécuter? �Sur quel processeur? 12

Ordonnancement(2) � Temps partagé ◦ Un ordonnancement à deux niveaux est souvent utilisé �

Ordonnancement(2) � Temps partagé ◦ Un ordonnancement à deux niveaux est souvent utilisé � Un nouveau processus est affecté au processeur ayant la plus petite charge � On tente ensuite d’affecter ce processus au même processeur � D’une certaine façon, chaque processeur possède sa propre collection de processus ◦ Un processus qui détient un verrou pivotant peut difficilement être arrêté à l’expiration de son quantum 13

Ordonnancement(3) � Espace partagé (pas de multiprogrammation) ◦ On tient compte du lien existant

Ordonnancement(3) � Espace partagé (pas de multiprogrammation) ◦ On tient compte du lien existant entre certains processus ou threads ◦ On ordonnance plusieurs threads d’un même processus sur plusieurs processeurs ◦ L’algorithme le plus simple consiste à ordonnancer les processus plutôt que les threads. S’il n’y a pas assez de processeurs disponibles pour tous les threads d’un processus alors on choisit un autre processus. ◦ Cela revient à partitionner les processeurs. Les partitions évoluent avec l’exécution des processus. 14

Ordonnancement(4) Avec multiprogrammation: � Problème de communication entre deux threads ◦ ◦ Deux threads

Ordonnancement(4) Avec multiprogrammation: � Problème de communication entre deux threads ◦ ◦ Deux threads A 0 et A 1 d’un même processus A veulent communiquer Les threads A 0 et B 0 s’exécutent sur le processeur 0 Les threads A 1 et B 1 s’exécutent sur le processeur 1 Le délai de communication peut être inacceptable 15

Multi-ordinateurs �Processeurs fortement couplés qui ne partagent pas de mémoire commune. �Les processeurs communiquent

Multi-ordinateurs �Processeurs fortement couplés qui ne partagent pas de mémoire commune. �Les processeurs communiquent par l’envoie de messages ◦ Transmis sous la forme de paquets �Également connu sous d’autres noms: ◦ Cluster ◦ COW (clusters of workstations) 16

Différentes topologies (a) étoile (b) anneau (c) grille (d) double tore (e) cube (f)

Différentes topologies (a) étoile (b) anneau (c) grille (d) double tore (e) cube (f) hypercube 17

Utilisation de cartes d’interface RAM du module d’interface CPU optionnel Carte d’interface • Les

Utilisation de cartes d’interface RAM du module d’interface CPU optionnel Carte d’interface • Les cartes d’interface possède une mémoire afin de garantir un débit constant dans le réseau. • Certaines possède même un processeur complet gérant la transmission, le multicast, etc. 18

Logiciels de communication au niveau utilisateur �Passage de messages � 2 méthodes: ◦ Appels

Logiciels de communication au niveau utilisateur �Passage de messages � 2 méthodes: ◦ Appels systèmes permettant d’envoyer et de recevoir des messages �Envoyer(adresse, message) �Recevoir(adresse, &message) �L’adresse doit identifier la machine et le processus ◦ On fait passer la communication distante pour un appel de procédure standard. �Remote procedure call (RPC) 19

Appels bloquants et non bloquants (a) Appels systèmes bloquants • Synchrone (b) Appels systèmes

Appels bloquants et non bloquants (a) Appels systèmes bloquants • Synchrone (b) Appels systèmes non bloquants • asynchrone 20

Ordonnancement �Sur un multi-ordinateur chaque ordinateur possède son propre SE ainsi que sa propre

Ordonnancement �Sur un multi-ordinateur chaque ordinateur possède son propre SE ainsi que sa propre table des processus �L’équilibrage de la charge est plus compliqué que pour les multiprocesseurs �Plusieurs algorithme d’ordonnancement existent. 21

Création de processus sur UNIX // Crée une copie exacte du processus appelant pid_t

Création de processus sur UNIX // Crée une copie exacte du processus appelant pid_t fork(void) // Remplace l’image du processus appelant int execv( const char *fichier, char * const argv [] ); 22

Valeur de retour #include <sys/types. h> #include <sys/wait. h> pid_t wait(int *status) pid_t waitpid(

Valeur de retour #include <sys/types. h> #include <sys/wait. h> pid_t wait(int *status) pid_t waitpid( pid_t pid, int *status, int options); 23

Les threads POSIX #include <pthread. h> int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void

Les threads POSIX #include <pthread. h> int pthread_create( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *restrict arg); void pthread_exit(void *value_ptr); int pthread_join(pthread_t thread, void **value_ptr); 24

Sections Critiques (1) L’exclusion mutuelle est une méthode qui permet de s’assurer que si

Sections Critiques (1) L’exclusion mutuelle est une méthode qui permet de s’assurer que si un processus utilise une variable ou un fichier partagé, les autres processus seront exclus de la même activité. Une section critique (ou région critique) est la partie du programme à partir de laquelle on accède à la mémoire partagée. 25

Sections Critiques (2) Quatre conditions pour obtenir l'exclusion mutuelle: 1. 2. 3. 4. Un

Sections Critiques (2) Quatre conditions pour obtenir l'exclusion mutuelle: 1. 2. 3. 4. Un seul processus à la fois dans la section critique Aucune supposition sur le nombre et la vitesse des CPUs Aucun processus hors de la section critique ne peut bloquer un autre processus. Aucun processus ne doit attendre indéfiniment pour entrer en section critique. 26

L'instruction TSL (Test and Set Lock) TSL R, LOCK est une opération atomique équivalente

L'instruction TSL (Test and Set Lock) TSL R, LOCK est une opération atomique équivalente à: R=LOCK=1 enter_region: TSL REGISTER, LOCK | copie lock dans le registre et le définit à 1 CMP REGISTER, #0 | lock était-il à 0 ? JNE enter_region | s'il n’était pas à 0, boucle RET | retourne à l’appelant ; entre en section critique leave_region: MOVE LOCK, #0 RET | stocke un 0 dans lock | retourne à l’appelant 27

Sémaphores sur Solaris #include <semaphore. h> sem_t *sem_open( char* nom, // Le premier caractère

Sémaphores sur Solaris #include <semaphore. h> sem_t *sem_open( char* nom, // Le premier caractère du nom doit être '/' int oflag // O_CREAT ou O_CREAT | O_EXCL int mode // bits de permission int valeur // valeur initiale ); int sem_wait(sem_t *psem) int sem_post(sem_t *psem) int sem_init( // sémaphore sans nom sem_t * psem, int pshare, // Si non nul, peut être partagé avec d'autres processus int valeur // NULL = Attributs par défaut ); 28

Les sémaphores: opérations Up et Down (1) Solution de Dijkstra au problème des wakeup

Les sémaphores: opérations Up et Down (1) Solution de Dijkstra au problème des wakeup perdus. Un sémaphore est une variable partagée entre plusieurs processus et munie de deux nouvelles instruction atomiques: Down(S): if (S==0) sleep S=S-1 Up(S): S=S+1 if (S==1) wakeup() // si des processus sont endormis sur le // sémaphore S alors l’un d’eux sera réveillé 29

Les mutex sont des sémaphore qui ne peuvent prendre que la valeur 0 ou

Les mutex sont des sémaphore qui ne peuvent prendre que la valeur 0 ou 1. Ils servent à réaliser l’exclusion mutuel. 30

Mutex sur Solaris #include <pthread. h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int pthread_ mutex_lock(pthread_mutex_t* pm);

Mutex sur Solaris #include <pthread. h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int pthread_ mutex_lock(pthread_mutex_t* pm); int pthread_mutex_unlock(pthread_mutex_t* pm); int pthread_mutex_init( // mutex dynamique pthread_mutex_t * pm, const pthread_mutexattr_t *mattr // NULL = Attributs par défaut ); 31

Variables conditionelles sur Solaris pthread-cond_t cond = PTHREAD_COND_INITIALIZER; int pthread_cond_wait( pthread_cond_t *cond, pthread_mutex_t *mutex

Variables conditionelles sur Solaris pthread-cond_t cond = PTHREAD_COND_INITIALIZER; int pthread_cond_wait( pthread_cond_t *cond, pthread_mutex_t *mutex ); int pthread-cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_init( pthread_cond_t *cond, const pthread_condattr_t *attr ); 32

Les barrières sur Solaris int pthread_barrier_init(pthread_barrier_t * barrier, const pthread_barrierattr_t * attr, unsigned count);

Les barrières sur Solaris int pthread_barrier_init(pthread_barrier_t * barrier, const pthread_barrierattr_t * attr, unsigned count); int pthread_barrier_wait(pthread_barrier_t *barrier); int pthread_barrier_destroy(pthread_barrier_t *barrier); 33

Algorithmes parallèle �Réduction �Scan �Diviser-pour régner �Distribution des données

Algorithmes parallèle �Réduction �Scan �Diviser-pour régner �Distribution des données

Le langage parallèle Cilk Trois nouveaux mots clés: 1. spawn 2. sync 3. Parallel

Le langage parallèle Cilk Trois nouveaux mots clés: 1. spawn 2. sync 3. Parallel Si on enlève ces mots clés, on obtient un programme C standard.

Mesures de performance �Travail (work): temps séquentiel �Durée (span): temps parallèle �TP: temps d’exécution

Mesures de performance �Travail (work): temps séquentiel �Durée (span): temps parallèle �TP: temps d’exécution sur p processeurs �T 1: travail �T∞: durée

Mesures de performance �Loi du travail: TP ≥ T 1/P �Loi de la durée:

Mesures de performance �Loi du travail: TP ≥ T 1/P �Loi de la durée: TP ≥ T∞ �Accélération: T 1/Tp ≤ P �Parallélisme: T 1/T∞ ≥ T 1/Tp

Open. MP n Open. MP: Interface de programmation (API) pour le calcul parallèle sur

Open. MP n Open. MP: Interface de programmation (API) pour le calcul parallèle sur architecture à mémoire partagée. u. Directives pour le compilateur u. Bibliothèque logicielle u. Variables de l’environnement n Open. MP fonctionne avec Fortran, C, ou C++

Parallélisme avec Fork et Join n Initialement un seul thread est actif (maître) n

Parallélisme avec Fork et Join n Initialement un seul thread est actif (maître) n Le maître exécute le code séquentiel. n Fork: Le maître crée ou active des threads additionnels afin d’exécuter du code en parallèle. n Join: À la fin du code parallèle, les threads sont éliminés ou suspendus et le flot de contrôle retourne à l’unique thread maître.

Parallel for #pragma omp parallel for [clause [[, ] clause …] for (i =

Parallel for #pragma omp parallel for [clause [[, ] clause …] for (i = 0; i < N; i++) a[i] = b[i] + c[i]; n Le compilateur doit être en mesure de vérifier si le système d’exécution aura l’information nécessaire à l’ordonnancement des itérations de la boucle. n. Indépendance des itérations n. Nombre d’itérations

Comment le système sait-il combien de threads il faut créer? Variable de l’environnement: OMP_NUM_THREADS

Comment le système sait-il combien de threads il faut créer? Variable de l’environnement: OMP_NUM_THREADS 4 fonctions utiles: n omp_get_num_procs n omp_set_num_threads n omp_get_thread_num

Pragma “critical” n Section critique: portion de code qui ne peut être exécuté que

Pragma “critical” n Section critique: portion de code qui ne peut être exécuté que par un seul thread à la fois. n On met #pragma omp critical devant le bloc de code C.

Réductions n n n Une réduction est l’application d’une opération associative sur les éléments

Réductions n n n Une réduction est l’application d’une opération associative sur les éléments d’un vecteur Les réductions sont si courantes que Open. MP fourni un mécanisme facilitant son application. On peut ajouter une clause de réduction au pragma parallel for On doit spécifier l’opération de réduction et la variable sur laquelle s’applique la réduction Open. MP s’occupe de stocker les résultats partiels dans des variables privées.

Clause “Reduction” n La clause réduction a la syntaxe suivante: reduction (<op> : <variable>)

Clause “Reduction” n La clause réduction a la syntaxe suivante: reduction (<op> : <variable>) Opérateur Valeur initiale + 0 - 0 * 1 & Tous les bits à 1 | Tous les bits à 0 ^ Tous les bits à 0 && 1 || 0 max Maximum possible min Minimum possible

Le pragma “parallel” n Précède un bloc de code devant être exécuté par tous

Le pragma “parallel” n Précède un bloc de code devant être exécuté par tous les threads. #pragma omp parallel n Note: Tous les threads exécutent le même code

Le pragma “for” n Le pragma “parallel” demande à tous les threads d’exécuter tout

Le pragma “for” n Le pragma “parallel” demande à tous les threads d’exécuter tout le code dans le bloc. n Si le bloc contient une boucle for que l’on voudrait diviser entre les threads alors on peut utiliser le pragma “for” #pragma omp for

Le pragma “single” n Dans certaines situation on veut qu’un seul thread exécute une

Le pragma “single” n Dans certaines situation on veut qu’un seul thread exécute une certaine instruction n. Par exemple, un message en sortie n C’est le rôle du pragma “single” n Syntaxe: #pragma omp single

Le pragma “sections” n Apparaît à l’intérieur d’un bloc de code couvert par le

Le pragma “sections” n Apparaît à l’intérieur d’un bloc de code couvert par le pragma “parallel” n Possède la même signification que le pragma “parallel sections” n Ajoute de la flexibilité à la façon d’organiser le parallélisme

Exemple #pragma omp parallel { #pragma omp sections { v = alpha(); #pragma omp

Exemple #pragma omp parallel { #pragma omp sections { v = alpha(); #pragma omp section w = beta(); } #pragma omp sections { x = gamma(v, w); #pragma omp section y = delta(); } } printf ("%6. 2 fn", epsilon(x, y));

La directive « task » #pragma omp task bloc d’instructions Lorsqu’un thread rencontre une

La directive « task » #pragma omp task bloc d’instructions Lorsqu’un thread rencontre une directive task il créé une tâche avec le bloc d’instructions suivant qu’il peut exécuter immédiatement ou reporter à plus tard. Une tâche reportée peut être exécutée par n’importe quel thread du groupe actifs

Le passage de messages

Le passage de messages

Initialisation de MPI_Init (&argc, &argv); �Utiliser avant toute autre fonction MPI �Pas nécessairement la

Initialisation de MPI_Init (&argc, &argv); �Utiliser avant toute autre fonction MPI �Pas nécessairement la première instruction �Permet d’effectuer les réglages nécessaires à l’utilisation de MPI �Analogie: Constructeur en POO

Communicators �Communicator: Groupe de processus ◦ Objet opaque offrant l’environnement nécessaire au passage de

Communicators �Communicator: Groupe de processus ◦ Objet opaque offrant l’environnement nécessaire au passage de messages entre les processus �MPI_COMM_WORLD ◦ Communicator par défaut ◦ Contient tous les processus �Il est possible de créer d’autres communicators

Déterminer le rang d’un processus int MPI_Comm_rank (MPI_COMM_WORLD, &id); �Premier paramètre: Nom du communicator

Déterminer le rang d’un processus int MPI_Comm_rank (MPI_COMM_WORLD, &id); �Premier paramètre: Nom du communicator �Le rang (0, 1, …, p-1) est retourné dans le second paramètre

Terminer l’utilisation de MPI_Finalize(); �Dernier appel MPI �Permet au système de libérer les ressources

Terminer l’utilisation de MPI_Finalize(); �Dernier appel MPI �Permet au système de libérer les ressources MPI �Analogie: Destructeur en POO

Prototype de MPI_Reduce() int MPI_Reduce ( void *operand, /* Adresse du tableau d’entrée*/ void

Prototype de MPI_Reduce() int MPI_Reduce ( void *operand, /* Adresse du tableau d’entrée*/ void *result, /* Adresse du tableau des résultat */ int nbre, /* nombre de réductions à effectuer*/ MPI_Datatype, /* type des éléments*/ MPI_Op operator, /* Opérateur de réduction*/ int root, /* Rang du processus qui reçoit le résultat*/ MPI_Comm comm /* communicator */ )

MPI_Datatype � MPI_CHAR � MPI_DOUBLE � MPI_FLOAT � MPI_INT � MPI_LONG_DOUBLE � MPI_SHORT �

MPI_Datatype � MPI_CHAR � MPI_DOUBLE � MPI_FLOAT � MPI_INT � MPI_LONG_DOUBLE � MPI_SHORT � MPI_UNSIGNED_CHAR � MPI_UNSIGNED_LONG � MPI_UNSIGNED_SHORT

MPI_Op � MPI_BAND � MPI_BOR � MPI_BXOR � MPI_LAND � MPI_LOR � MPI_LXOR �

MPI_Op � MPI_BAND � MPI_BOR � MPI_BXOR � MPI_LAND � MPI_LOR � MPI_LXOR � MPI_MAXLOC � MPI_MINLOC � MPI_PROD � MPI_SUM

Analyse de la performance �MPI_Barrier barrière de synchronization �MPI_Wtick temps en secondes entre 2

Analyse de la performance �MPI_Barrier barrière de synchronization �MPI_Wtick temps en secondes entre 2 tics d’horloge �MPI_Wtime temps en secondes depuis le dernier appel

Partitionnement par bloc �On veut balancer la charge de travail �Chaque processus reçoit n/p

Partitionnement par bloc �On veut balancer la charge de travail �Chaque processus reçoit n/p ou n/p elements �On recherche des expressions simples pour: ◦ Trouver le plus petit et plus grand indice de la partie de tableau d’un processus ◦ Trouver le responsable d’un indice

Option de partitionnement �Entrelacé (cyclique) ◦ Facile de déterminer le « responsable » d’un

Option de partitionnement �Entrelacé (cyclique) ◦ Facile de déterminer le « responsable » d’un indice ◦ Charge de travail non balancée �Par bloc ◦ Balance la charge de travail ◦ Si n n’est pas un multiple de p alors il est plus difficile de trouver le “responsable” d’un indice.

Méthode 1 � r = n mod p �Si r = 0, tous les

Méthode 1 � r = n mod p �Si r = 0, tous les blocs ont la même taille �Sinon ◦ Les premiers r blocs ont une taille n/p ◦ Les p-r blocs suivants ont une taille n/p

Méthode 1: Calculs �Premier élément contrôlé par le processus i �Dernier élément contrôlé par

Méthode 1: Calculs �Premier élément contrôlé par le processus i �Dernier élément contrôlé par le processus i �Processus contrôlant l’élément j

Méthode 2 �On disperse les grands blocs parmi les processus �Premier élément contrôlé par

Méthode 2 �On disperse les grands blocs parmi les processus �Premier élément contrôlé par le processus i �Dernier élément contrôlé par le processus i �Processus contrôlant l’élément j

Function MPI_Bcast int MPI_Bcast ( void *buffer, /* Addr du 1 er élément*/ int

Function MPI_Bcast int MPI_Bcast ( void *buffer, /* Addr du 1 er élément*/ int count, /* # éléments à diffuser*/ MPI_Datatype datatype, /* Type des éléments*/ int root, MPI_Comm comm) /* ID du processus racine*/ /* Communicator */ MPI_Bcast (&k, 1, MPI_INT, 0, MPI_COMM_WORLD);

Function MPI_Send int MPI_Send ( void ) *message, int count, MPI_Datatype datatype, int dest,

Function MPI_Send int MPI_Send ( void ) *message, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm

Function MPI_Recv int MPI_Recv ( void int count, MPI_Datatype datatype, int source, int tag,

Function MPI_Recv int MPI_Recv ( void int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status ) *message, *status

Interblocage �Lorsqu’un processus attend un événement qui ne se produira jamais �Les appels send/receive

Interblocage �Lorsqu’un processus attend un événement qui ne se produira jamais �Les appels send/receive sont une cause importante d’interblocage ◦ Deux processus: Les deux reçoivent avant d’envoyer ◦ Aucun send ne correspond à un receive ◦ Un processus envoie un message à un mauvais destinataire.

MPI_Comm_split int MPI_Comm_split( MPI_Comm comm, /* Communicator à diviser */ int color, /* Indique

MPI_Comm_split int MPI_Comm_split( MPI_Comm comm, /* Communicator à diviser */ int color, /* Indique le sous-groupe */ int key, /* Rang dans le sous-groupe */ MPI_Comm *newcomm /* handle vers le sous-groupe */ ) Note: Lorsque color vaut MPI_UNDEFINED alors la valeur retournée dans newcomm vaut MPI_COMM_NULL

Function MPI_Isend int MPI_Isend ( void *buffer, int cnt, MPI_Datatype dtype, int dest, int

Function MPI_Isend int MPI_Isend ( void *buffer, int cnt, MPI_Datatype dtype, int dest, int tag, MPI_Comm comm, MPI_Request *handle ) Pointeur vers un objet qui identifie l’opération

Function MPI_Irecv int MPI_Irecv ( void *buffer, int cnt, MPI_Datatype dtype, int src, int

Function MPI_Irecv int MPI_Irecv ( void *buffer, int cnt, MPI_Datatype dtype, int src, int tag, MPI_Comm comm, MPI_Request *handle ) Pointeur vers un objet qui identifie l’opération

Function MPI_Wait int MPI_Wait ( MPI_Request *handle, MPI_Status *status )

Function MPI_Wait int MPI_Wait ( MPI_Request *handle, MPI_Status *status )

Function MPI_Probe int MPI_Probe ( int src, int tag, MPI_Comm comm, MPI_Status *status )

Function MPI_Probe int MPI_Probe ( int src, int tag, MPI_Comm comm, MPI_Status *status ) Bloque jusqu’à ce qu’un message soit prêt à recevoir Permet de voir le statut avant de recevoir le message

Function MPI_Get_count int MPI_Get_count ( MPI_Status *status, MPI_Datatype dtype, int *cnt ) Permet de

Function MPI_Get_count int MPI_Get_count ( MPI_Status *status, MPI_Datatype dtype, int *cnt ) Permet de connaître la taille du message

RMA (Remote memory access): permet plus de souplesse dans la communication entre les processus.

RMA (Remote memory access): permet plus de souplesse dans la communication entre les processus. Un processus « origine » indique tous les paramètres de la communication avec un processus « cible » C’est ce que l’on appelle une « communication à sens unique » .

Communication 3 types de communication: �Put �Get �Accumulate Tous ces appels sont non-bloquants

Communication 3 types de communication: �Put �Get �Accumulate Tous ces appels sont non-bloquants

Synchronisation 3 types de synchronisation: �Fence �Start, Complete, Post, Wait �Lock, unlock

Synchronisation 3 types de synchronisation: �Fence �Start, Complete, Post, Wait �Lock, unlock

Création d’une fenêtre MPI_Win_create(void *base, MPI_Aint size, disp_unit, int MPI_Info info, MPI_Comm comm, *win);

Création d’une fenêtre MPI_Win_create(void *base, MPI_Aint size, disp_unit, int MPI_Info info, MPI_Comm comm, *win); MPI_Win

Libérer une fenêtre int MPI_Win_free(MPI_Win *win) Il s’agit aussi d’un appel collectif

Libérer une fenêtre int MPI_Win_free(MPI_Win *win) Il s’agit aussi d’un appel collectif

Allocation de l’espace mémoire int MPI_Alloc_mem(MPI_Aint size, MPI_Info info, void *baseptr) Permet d’informer le

Allocation de l’espace mémoire int MPI_Alloc_mem(MPI_Aint size, MPI_Info info, void *baseptr) Permet d’informer le compilateur que la mémoire sera utilisée en RMA.

Libérer la moimoire int MPI_Free_mem(void *base)

Libérer la moimoire int MPI_Free_mem(void *base)

MPI_Put(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype

MPI_Put(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win)

MPI_Get(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype,

MPI_Get(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Win win)

MPI_Accumulate int MPI_Accumulate(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, target_rank, target_disp, int MPI_Aint target_count, MPI_Datatype

MPI_Accumulate int MPI_Accumulate(void *origin_addr, int origin_count, MPI_Datatype origin_datatype, target_rank, target_disp, int MPI_Aint target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win)

Barrière int MPI_Win_fence(int assert, MPI_Win win) Il s’agit d’un appel collectif qui débute et/ou

Barrière int MPI_Win_fence(int assert, MPI_Win win) Il s’agit d’un appel collectif qui débute et/ou termine une époque.

Début d’une époque d’accès int MPI_Win_start(MPI_Group group, int assert, MPI_Win win) Sur certains système,

Début d’une époque d’accès int MPI_Win_start(MPI_Group group, int assert, MPI_Win win) Sur certains système, l’assertion peut être MPI_MODE_NOCHECK mais 0 est toujours valide. Seul le nœud origine fait cet appel

Fin d’une époque d’accès MPI_Win_complete(MPI_Win win) Seul le nœud origine fait cet appel

Fin d’une époque d’accès MPI_Win_complete(MPI_Win win) Seul le nœud origine fait cet appel

Début d’une époque d’exposition int MPI_Win_post(MPI_Group group, int assert, MPI_Win win) Seul le nœud

Début d’une époque d’exposition int MPI_Win_post(MPI_Group group, int assert, MPI_Win win) Seul le nœud cible fait cet appel

Fin d’une époque d’exposition int MPI_Win_wait(MPI_Win win) Seul le nœud origine fait cet appel

Fin d’une époque d’exposition int MPI_Win_wait(MPI_Win win) Seul le nœud origine fait cet appel

Communicator Deux principale composante: �Groupe: Collection ordonnée de processus �Contexte: permet la gestion des

Communicator Deux principale composante: �Groupe: Collection ordonnée de processus �Contexte: permet la gestion des messages Ex. tags) Permet aussi de créer une topologie

Groupe int MPI_Comm_group(MPI_Comm comm, MPI_Group *group) Retourne le groupe associé à un communicator

Groupe int MPI_Comm_group(MPI_Comm comm, MPI_Group *group) Retourne le groupe associé à un communicator

Créer un nouveau groupe int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup)

Créer un nouveau groupe int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup)

Cible passive int MPI_Win_lock(int lock_type, win) int rank, int assert, MPI_Win Le type est

Cible passive int MPI_Win_lock(int lock_type, win) int rank, int assert, MPI_Win Le type est MPI_LOCK_EXCLUSIVE ou MPI_LOCK_SHARED Cet appel est fait par le processus origine seulement.

Cible passive int MPI_Win_unlock(int rank, MPI_Win win) Cet appel est fait par le processus

Cible passive int MPI_Win_unlock(int rank, MPI_Win win) Cet appel est fait par le processus origine seulement.

Open. CL �API + langage basé sur le C 99 �Conçu pour programmer des

Open. CL �API + langage basé sur le C 99 �Conçu pour programmer des systèmes parallèles hétérogènes: CPU multi-coeur, GPU, etc. �On distingue le processeur hôte des périphériques �Un conteneur spécial (context) sert d’interface entre le processeur hôte et les périphériques �Les données et les tâches (kernels) sont transférés à l’aide d’une file d’attente (command queue)

Un périphérique vu par Open. CL

Un périphérique vu par Open. CL

Espace des indices �En Open. CL, l’espace des indices des processeurs peut avoir 1,

Espace des indices �En Open. CL, l’espace des indices des processeurs peut avoir 1, 2 ou 3 dimensions. �Il y a deux niveaux d’indices: ◦ Un indice global unique pour chaque work -item du périphérique (NDRange) ◦ Un indice local unique pour chaque workitem à l’intérieur d’un même workgroup.

NDRange et Workgroups

NDRange et Workgroups

Connaître son indice � get_global_id(dim): indice globale du work-item appelant selon la dimension dim=0,

Connaître son indice � get_global_id(dim): indice globale du work-item appelant selon la dimension dim=0, 1 ou 2 � get_local_id(dim): indice local du work-item appelant � get_group_id(dim): indice du workgroup auquel appartient le work-item appelant � get_local_size(dim): taille de la dimension dim dans le workgroup du work-item appelant.

Plateformes �Une plateforme est une implémentation de Open. CL spécifique à un manufacturier donné

Plateformes �Une plateforme est une implémentation de Open. CL spécifique à un manufacturier donné �Pour obtenir la liste des plateformes: cl_int cl. Get. Platform. IDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms) �cl. Get. Platform. Info pour obtenir de l’information sur une plateforme donné

Périphériques �Pour chacune des plateformes (ex. NVIDIA), on peut obtenir la liste des périphériques

Périphériques �Pour chacune des plateformes (ex. NVIDIA), on peut obtenir la liste des périphériques associés: cl_int cl. Get. Device. IDs(cl_platform_id platform, cl_device_type, cl_uint num_entries, cl_device_id *devices, cl_uint *num_devices)

Contextes cl_context cl. Create. Context ( const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices,

Contextes cl_context cl. Create. Context ( const cl_context_properties *properties, cl_uint num_devices, const cl_device_id *devices, void (CL_CALLBACK *pfn_notify)( const char *errinfo, const void *private_info, size_t cb, void *user_data), void *user_data, cl_int *errcode_ret)

Création d’une file de commandes cl_command_queue cl. Create. Command. Queue( cl_context, cl_device_id device, cl_command_queue_properties,

Création d’une file de commandes cl_command_queue cl. Create. Command. Queue( cl_context, cl_device_id device, cl_command_queue_properties, cl_int* errcode_ret) Note: Le paramètre « properties » sert, entre autres, à indiquer si les éléments seront pris dans l’ordre.

Création d’un tampon cl_mem cl. Create. Buffer( cl_context, cl_mem_flags, size_t size, void *host_ptr, cl_int

Création d’un tampon cl_mem cl. Create. Buffer( cl_context, cl_mem_flags, size_t size, void *host_ptr, cl_int *errcode_ret) Note: Le paramètre « flags » sert à indiquer si le tampon est en lecture, en écriture ou les deux.

Écrire dans un tampon cl_int cl. Enqueue. Write. Buffer ( cl_command_queue, cl_mem buffer, cl_bool

Écrire dans un tampon cl_int cl. Enqueue. Write. Buffer ( cl_command_queue, cl_mem buffer, cl_bool blocking_write, // CL_TRUE pour appel bloquant size_t offset, size_t cb, const void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)

Lire dans un tampon cl_int cl. Enqueue. Read. Buffer( cl_command_queue, cl_mem buffer, cl_bool blocking_read,

Lire dans un tampon cl_int cl. Enqueue. Read. Buffer( cl_command_queue, cl_mem buffer, cl_bool blocking_read, size_t offset, size_t size, void *ptr, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)

Création d’un objet programme cl_program cl. Create. Program. With. Source ( cl_context, cl_uint count,

Création d’un objet programme cl_program cl. Create. Program. With. Source ( cl_context, cl_uint count, const char **strings, const size_t *lengths, cl_int *errcode_ret)

Compiler un objet programme cl_int cl. Build. Program ( cl_program, cl_uint num_devices, const cl_device_id

Compiler un objet programme cl_int cl. Build. Program ( cl_program, cl_uint num_devices, const cl_device_id *device_list, const char *options, void (CL_CALLBACK *pfn_notify)(cl_program, void *user_data)

Obtenir un kernel cl_kernel cl. Create. Kernel ( cl_program, const char *kernel_name, cl_int *errcode_ret)

Obtenir un kernel cl_kernel cl. Create. Kernel ( cl_program, const char *kernel_name, cl_int *errcode_ret) Note: *kernel_name contient le nom d’une fonction dans le programme source.

Affecter les paramètres cl_int cl. Set. Kernel. Arg ( cl_kernel, cl_uint arg_index, size_t arg_size,

Affecter les paramètres cl_int cl. Set. Kernel. Arg ( cl_kernel, cl_uint arg_index, size_t arg_size, const void *arg_value) Note: Les paramètres demeurent affectés au kernel tant qu’il n’y a pas de modification explicite à l’aide de cl. Set. Kernel. Arg()

Exécuter un kernel cl_int cl. Enqueue. NDRange. Kernel( cl_command_queue, cl_kernel, cl_uint work_dim, const size_t

Exécuter un kernel cl_int cl. Enqueue. NDRange. Kernel( cl_command_queue, cl_kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size, cl_uint num_events_in_wait_list, const cl_event *event_wait_list, cl_event *event)