Parallélisme et Répartition Master Info Françoise Baude Université de Nice Sophia-Antipolis UFR Sciences Département Informatique baude@unice.fr web du cours : deptinfo.unice.fr/~baude Septembre 2009 Chapitre 1 : Introduction générale Chapitre 2 : Paradigmes de programmation parallèle Chapitre 3 : Modèle algorithmique parallèle PRAM 1 Retour sur les différents modèles/paradigmes On crée n threads concurrentes et ayant un code séquentiel pas obligatoirement identique (c est le même sur cet ex.!), ces n threads pouvant aller à leur propre rythme dans leur exécution On crée n threads parallèles ayant le même code, et que l on synchronise, avant de recommencer une 2eme fois Ces 2 modèles sont exprimables en utilisant OpenMP! Les classifications quelles qu elles soient ont toujours leurs limites! La source de parallélisme la plus importante a néanmoins toujours été celle issue de l exploitation de plein de processeurs en même temps Donc, ces processeurs ont (quasi) la même chose à faire (un programmeur n est pas capable d exprimer un grand nombre d algorithmes tous différents à la fois!) 2 1
L intérêt d un modèle algorithmique Pour s affranchir des langages parallèles Selon qu ils vont favoriser tel ou tel type de paradigme parallèle Au contraire, pour se concentrer sur l algorithmique sous-jacente Afin d obtenir la complexité intrinsèque d une résolution en parallèle d un problème donné Même si la mise en œuvre pratique d un algorithme peut engendrer des surcouts supplémentaires => L algorithmique selon modèle PRAM permet ainsi d établir des mesures de complexité *dépendantes du nbr proc. * ex: borne inf: On ne pourra pas faire plus rapide en parallèle!! Est-ce que cet algo // est optimal comparé à complexité pour résoudre le même problème en séquentiel? 3 Plan 1. Le modèle algorithmique parallèle PRAM 2. Quelques premiers algorithmes PRAM 3. Une suite à l étude d OpenMP 4 2
L algorithmique et modèle PRAM Une machine PRAM (Parallel Random Access Machine) est une machine abstraite (comme l est une RAM) Un nombre (non borné) de processeurs parallèles Une mémoire globale, partagée Une suite d instructions a exécuter Un seul pointeur d instruction => exécution synchrone, en SIMD => synchronisations (barrière) supplémentaires inutiles (il y a déjà une barrière implicite entre chaque instruction //!!) 5 Variantes de PRAMs pour l accès mémoire globale Mais, il y a plusieurs processeurs (synchrones) Donc, il faut définir en + des règles pour les accès «concurrents» sur même @) EREW (exclusive read, exclusive write) : Interdiction de lire ou d écrire sur une même @ par + d 1 proc CREW (concurrent read exclusive write) Lecture d une même @ par +eurs procs. autorisée CRCW (concurrent read, concurrent write) Mode arbitraire (un seul write d 1 proc arbitraire- réussit) Mode consistant (tous les writes réussissent si compatibles, par ex. si tous les procs. écrivent même val.) Mode association (une combinaison de toutes les valeurs a écrire est faite avant d écrire le résultat de cette combinaison) 6 3
Simulation de PRAMs Surcout d émulation d une variante de PRAM à une autre Bien connus => complexité d un algorithme dans une variante donnée est transposable facilement dans le cadre d une autre variante Ex: calcul en temps O(1) sur une CRCW devient un calcul en temps O(log p) sur une p-crew 7 Eléments du langage algorithmique Pseudo-langage simple Boucles, tableaux, tests Toutes les var. sont partagées par défaut Instruction de boucle Pour chaque (proc d identité) i (en parallèle) faire x[i] = y[i] FinPour les lectures des y[i] sont exécutées en //, puis les écritures des x[i] 8 4
Exemple: calcul du maximum (v1) On recherche max_i(t(i)) On utilise une machine ayant n 2 procs. Chaque proc accède à T[i] et T[j] On utilise un tableau de booléens auxiliaire m(i) Complexité : temps O(1) sur une CRCW arbitraire (suffit!) et en O(log n) sur une EREW ou CREW 9 Exemple: calcul du maximum (v2) si n=2 m, si le tableau A est de taille 2n, et si on veut calculer le maximum des n éléments de A en position A[n], A[n+1],...,A[2n-1], on obtient le résultat dans A[1] après exécution de l'algorithme suivant: Pour (k=m-1; k>=0; k--) Pour chaque j from 2^k to 2^(k+1)-1 en parallele A[j] = max(a[2j],a[2j+1]); k=2 k=1 k=0 0 8 15 4 - - - - 3 7 8 7 2 P2 P3 - - 7 8 3 7 8 7 P1 1-8 7 8 3 7 8 7 1 3 5 7 4 8 7 2 P4 P5 P6 P7 1 3 5 7 4 8 7 2 Complexité en temps: m=o(log n) sur une EREW Procs. nécessaires: au max n/2 Optimal?? Comparé au O(n) seq.? 10 5
Remarques Parcours d un arbre logarithmique Mais on recompose le problème de «bas en haut» (feuilles->racine) Pas un divide and conquer Dans lequel on a 2 fois moins de données qu il reste à traiter à chaque étape du parcours Comment obtenir une quantité de travail similaire à la complexité séquentielle Réduire le nombre de ressources «processeurs» Sans pour autant augmenter la complexité en temps Au lieu de n proc, n/log n. Au lieu de log n time // -> log (n/logn) => O(logn) Rajouter temps de travail alloué à chaque proc, séquentiellement : O(logn) 11 Temps // log (2^4) = 4 O(log (n)) WORK = O(log n) * O(n) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 procs O(n) 2^4 Temps // Traitement sous-arbre en sequentiel O(4) Temps // O(4) log (2^4 / 4) = 2 log (n / logn) WORK = O(log (n)) * O(n/log n) = O(n) Donc optimal par rapport au travail seq. = O(n) procs 2^4 / 4 = 4 n / logn 12 6
Calcul des préfixes en parallèle Pattern très très utile (ex. td, tour Euler, tri radix, ) Appelé aussi SCAN Principe: Une suite de valeurs/données (x1,x2,.xn) Dans un tableau en mémoire, ou en liste chainée Nous étudierons les 2 cas Calculer (y1,y2,,yn) tel que yk = x1 op x2 op op x(k-1) op xk OP est une opération binaire associative Cas courant : OP est une somme Somme préfixe (prefix sum) But: trouver un algo // en temps O(log n) Si possible en quantité de travail effectuée au total O(n) Calcul séquentiel: cf exo «sp»du TD2, parcours cumulatif dans l ordre 13 Parallel prefix (v1) Fondé sur des parcours de l arbre logarithmique Selon le principe récursif OP(x1,x2, x (n/2)) s accumule sur (x (n/2), xn) OP(x1,x2, x (n/4)) s accum. sur (x (n/4)+1, x(n/2)) OP(x (n/2)+1, x(3n/4) s accum. sur (x (3n/4)+1, xn) 14 7
Code EREW PRAM de Dekel et Sahni, Optimal On donne ici la version de [Desprez], sur OP=somme La taille de la collection est 2^m, stockée dans la deuxième moitié du tableau A. Le résultat sera disponible dans la deuxième moitié d un tableau B Les premières moitiés de A et B servent de stockage intermédiaire (et utile pour l algo!) 3 phases: 1. «montée» selon l arbre logarithmique de bas en haut Pour l=m-1 à 0 faire (en séquentiel) Pour j=2^l à 2^(l+1) -1 faire_en_parallele a[j]= a[2.j] + a[2.j +1] finpour finpour Complexité : temps O(log n) = O(m) sur une EREW, utilisant n/2 proc. Peut être rendu optimal en travail effectué 15 2. «descente» des valeurs accumulées par son frère gauche et remontées jusqu au niveau père. Selon qu on est un nœud coté gauche, on fait juste descendre cette valeur reçue du père [vers ses fils] Selon qu on est un nœud coté droit, on accumule cette valeur reçue du père, à celle qui est accumulée par son fils gauche(=mon frère); [cette somme est ensuite propagée vers son fils droit (=moi)] b[1]=0 Pour l=1 à m faire (en séquentiel) Pour j=2^l à 2^(l+1) -1 faire_en_parallele si pair(j) b[j] = b[j/2] // j est 1 nœud gauche, récupère valeur du père si impair(j) b[j] = b[(j-1) / 2)] + a[j-1] // j est 1 nœud droit, on + (père) & (fils g) finpour finpour Complexité : temps O(log n) = O(m) sur une EREW, utilisant n/2 proc. (maxi. 2 accès concurrents en lecture, EREW suffit) Peut être rendu optimal en travail effectué 16 8
3. Finaliser le calcul de la deuxième moitié de B, en additionnant les valeurs de la deuxième moitie de A, une à une En // additionner sa propre valeur à la somme préfixe Pour j=2^m à 2^(m+1) - 1 faire_en_parallele b[j]= b[j] + a[j] finpour Complexité : temps O(1) sur une EREW, utilisant n/2 proc. Peut être rendu optimal en travail effectue Total: O(log n) utilisant O(n), Ou O(log (n / log (n)) + log(n)) en utilisant O(n/log n) proc 17 Faisons dérouler v1 A=(8, 9, 10, 11, 12, 13, 14, 15) 18 9
Calcul préfixe (v2) Basé sur une liste chainée -> aucun élément ne sait son rang dans la liste Parcours en suivant les pointeurs Principe du recursive doubling: Pour chaque proc., la distance vers laquelle on envoie ses informations double à chaque étape parallèle Il faut donc O(log longueur liste) pour que toute information soit parvenue aux autres 19 Principe du v2 Code EREW PRAM en O(logn), mais pas optimal en travail Cette valeur est le résultat de l accumulation des valeurs de l élément 1 jusqu à 3 inclus 20 10
Code de v2 i ]] 21 Calcul prefixe (v3) Basé sur un «simple» diviser pour paralléliser Selon le principe de récurrence yi = y i si i<= n/2 yi = y (n/2) OP y i si i> n/2 22 11
Faisons dérouler v3 A=(1,2,3,4,5,6,7,8) 23 Remarques Nécessite une CREW PRAM A chaque fusion de 2 sous-problèmes : Lecture de y (n/2), en parallèle par tous les proc. s occupant des indices > n/2 Passer outre: arriver à dupliquer, dans un tableau de longueur (n/2), la valeur y (n/2) autant de fois qu elle aura besoin d être lue Exercice 1 du TD Complexité // en temps : O(logn) A chaque étape, au plus n/2 proc. impliqués On peut facilement réduire ce nombre d un facteur O(log n) 24 12
3. Suite étude d OpenMP Sur les portées des variables, globales et privées Sur les 2 work-sharing constructs: sections, orphaning Sur les manières de guider l affectation des tours de boucle «for» sur les threads Sur le parallélisme «nested» (imbriqué) géré à partir de la version 3 25 26 13
27 28 14
29 30 15
31 32 16
33 34 17
35 36 18
37 38 19
39 20