Vous êtes sur la page 1sur 201

CALCUL PARALLLE

Unit d'enseignement
Calcul Parallle
Anne Acadmique
2014/2015
Parcours
Informatique Master 1
Enseignant
Douw Hallam Vincent (douwevincent@yahoo.fr)
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 1/
Informations gnrales

ORGANISATION DES COURS


Cours Magistral: 12h
Travaux Dirigs : 08h
Travaux Pratiques: 10h
ORGANISATION DES EVALUATIONS
Un Contrle Continu de 2h
Un TPE d'une semaine
Un Examen Final de 3h
Un Examen de Rattrapage de 3h
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr>
Objectifs du cours

Introduction aux architectures parallles


Dvelopper une mthodologie pour la
programmation parallle
Apprcier les performances d'un
programme parallle
Apprendre les outils ncessaires au
dveloppement de programmes parallles

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr>


Plan du cours

Introduction
Les architectures et programmes
parallles
Mise en uvre avec les Pthreads

Mise en uvre avec OpenMP

Mise en uvre avec MPI

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr>


Bibliographie

Ian Foster, Designing and building parallel


programs.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr>


INTRODUCTION

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 6/


Motivations
De 1986 2002, les performances des
microprocesseurs ont augmentes de 50 % en
moyenne.
Ceci implique que les dveloppeurs d'applications
n'ont qu' attendre les prochaines gnrations de
machines pour gagner en performance.
A partir de 2002 cependant, cette croissance est
tombe de 50 % environ 20 %. Ce qui est trs
significatif.
A partir de 2005, la plupart des constructeurs de
machines ont dcid de miser sur les
architectures multicurs
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 7/
Motivations

Ce changement de cap beaucoup d'incidence


sur le monde du logiciel. Ce n'est pas parce que
l'on ajoute des curs de calcul que l'on gagne
automatiquement en performance.
Cette situation nous amne nous poser les trois
questions fondamentales.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 8/


Les questions

Pourquoi s'en proccup ? Les processeurs


actuels ne sont pas t ils pas dj assez rapide
ainsi ? 20 % par an ce n'est pas rien.
Pourquoi les constructeurs de machines ne
continuent ils plus concevoir des puces plus
rapides ? Pourquoi des systmes parallles ?
Pourquoi les multicurs ?
Pourquoi ne peut on pas convertir
automatiquement un programme squentiel en un
programme
2014 - 2015
parallle ?
Vincent Douwe <douwevincent@yahoo.fr> 9/
Pourquoi a t on besoin de plus de performance ?

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 10/


Besoins en performance

L'volution des performances a permis


l'informatique d'tre applique dans la quasi
totalit des domaines de la Science, de l'Internet
et du divertissement.
A cause de l'augmentation des performances, le
nombre de problmes rsoudre augmente
aussi.
De plus, il existe toujours ces grands challenges
qui ont toujours t le domaine d'application
privilegi
2014 - 2015
du calcul parallle.
Vincent Douwe <douwevincent@yahoo.fr> 11/
Les grands challenges

Il s'agit d'un problme fondamental dont la rsolution


a un impact signification sur la science, l'industrie ou
la socit.
La simulation dynamique des fluides (conception
d'avions, arodynamisme, automobile, prvision
mtorologique, prospection ptrolire)
Calcul des structures lectroniques et conception de
nouveaux matriaux
Calcul symbolique (CV, NLP, raisonnement
automatique)
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 12/
Les nouveaux domaines

L'volution des performances a ouvert la porte


l'application de l'informatique dans les domaines
suivants ;
La modlisation du climat. Comprendre les
changements climatiques.
La synthse des protines. L'analyse des molcules
complexes
La recherche mdicale.
La recherche d'nergie
L'analyse des donnes
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 13/
Pourquoi construire des machines parallles ?

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 14/


Les machines parallles

L'volution des performances des machines mono


processeurs a t dirige par l'augmentation de la
densit des transistors dans les circuits intgrs.
Plus l'on a des transistors de petite taille, plus l'on
augmente la vitesse.
Malheureusement, l'augmentation de la vitesse
implique aussi une augmentation de la consommation
lectrique.
La plupart de lnergie est dissipe et l'on a du mal
refroidir les circuits.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 15/
Les machines parallles

Il est donc devenu impossible d'augmenter la vitesse


des puces. Mais paradoxalement, l'on peut encore
continuer produire des puces plus petites.
L'industrie des puces, pour exister, doit contourner
cet obstacle. La solution trouve est d'utiliser le
paralllisme.
Au lieu de produire des puces plus rapides, plus
complexes et monolithiques, l'industrie a dcid de
mettre plusieurs processeurs relativement simples
appels curs dans la mme puce.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 16/
Pourquoi doit on crire des programmes
parallles ?

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 17/


Mismatch

La plupart des programmes crits pour les machines


un seul cur ne peuvent pas exploiter la prsence
des multicurs.
Le programme doivent tre conu pour prendre en
considration ces nouvelles architectures pour tre
efficaces.
En ce qui concerne les traducteurs automatiques de
programmes squentiels en programmes parallles,
la recherche n'a pas vraiment eu des rsultats
satisfaisants dans ce domaine..
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 18/
Comment crit on les programmes parallles ?

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 19/


Les programmes parallles

Il existe plusieurs rponses cette question mais


la plupart de ces rponses impliquent le
partitionnement des tches entre les diffrents
curs de calcul.
Deux approches sont largement utilises ; Le
paralllisme des tches qui consiste distribuer
les tches raliser et le paralllisme des
donnes qui consiste distribuer les donnes aux
diffrents curs.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 20/


ARCHITECTURES ET
PROGRAMMES PARALLES

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 21/


Introduction

Il est tout fait concevable pour des spcialistes


des disciplines autre que l'Informatique d'crire
des programmes parallles.
Cependant, pour crire des programmes
parallles efficaces, il faut avoir une connaissance
de l'architecture relle de la machine.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 22/


Les architectures et
proggrammes
Les architectures et programmes parallles ont
t dfinies partir des architectures et
programmes pour des machines squentielles :
Des machines qui n'excutent qu'une seule tche
la fois.
L'architecture de Von Neumann( 1946) gouverne
le dveloppement machines squentielles.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 23/


L'architecture de Von Neumann

L'architecture classique de Von Neumann est


constitue d'une mmoire centrale, d'une unit de
traitement et d'un ensemble d'interconnexions
entre l'unit de traitement et la mmoire.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 24/


La mmoire centrale

La mmoire centrale est constitue d'un


ensemble de zones capables de garder les
donnes ou les instructions.
Chaque zone consiste d'une adresse.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 25/


L'unit de traitement

L'unit de traitement est constitue d'une unit


logique et d'une unit arithmtique et logique.
L'unit de contrle decide quelle instruction du
programme doit tre excute.
ALU est responsable d'excuter l'instruction.
Les donnes dans l'unit de traitement sont
stockes dans des mmoires trs rapides
appeles registres. Un registre particulier, appel
compteur ordinal, stocke l'adresse de la prochaine
instruction
2014 - 2015 excuter.
Vincent Douwe <douwevincent@yahoo.fr> 26/
L'architecture de Von Neumann

Lorsque les donnes sont transfres de la


mmoire centrale vers l'unit de traitement, l'on dit
que les donnes sont lues de la mmoire.
Lorsque les donnes sont transfres de l'unit
de traitement vers la mmoire centrale, l'on dit
qu'elles sont stockes dans la mmoire.
La sparation de la mmoire centrale et de l'unit
de traitement est souvent appele le goulot
d'tranglement de Von Neumann car c'est
l'interconnexion
2014 - 2015
qui dtermine la vitesse
Vincent Douwe <douwevincent@yahoo.fr> 27/
d'excution des instructions.
Le goulot d'tranglement

Pour limiter le goulot d'tranglement de Von


Neumann, plusieurs solutions ont t adoptes :
Les mmoires caches.
Les mmoires virtuelles
Pipeline (Instruction Level Parallelism)
Le mult threading matriel.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 28/


Les mmoires caches

Les mmoires caches sont des mmoires de


petites tailles places entre l'unit de traitement et
la mmoire centrale.
Ainsi, l'unit de traitement au lieu d'aller
directement dans la mmoire centrale pour lire ou
crire une donne, va d'abord passer par la
mmoire cache.
Lorsque l'unit de traitement crit dans la
mmoire cache et que la valeur dans la mmoire
cache
2014 - 2015
est diffrente de celle en mmoire centrale,29/
Vincent Douwe <douwevincent@yahoo.fr>
l'on parle d'inconsistence.
Les inconsistences

Il existe deux approches pour rsoudre le


problme d'inconsistence des mmoires caches :
Les caches write-through : la donne en mmoire
centrale est immdiatement modifie lorsque la
donne en cache est modifie.
Les caches write-back : les donnes ne sont pas
immdiatement crites en mmoire centrale mais
marques comme sales et seront synchronises
s'il y'a remplacement de la ligne de la cache.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 30/
???

Un processus ?
Un thread ?
Multi tche ?

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 31/


Les architectures parallles

La classification de Flynn est rgulirement


utiliser pour classer les diffrentes architectures.
Elle classe les machines en fonction du nombre
de flux d'instructions et du flux de donnes qui
sont manipuls simultanment.
data S M
instruction
S SISD SIMD

M MIMD

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 32/


Les machines SISD

Les machines SISD (Single Instruction Single


Data) sont des machines qui excutent une
instruction la fois sur une seule donne.
Elles correspondent aux machines Von Neumann
(machines squentielles).

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 33/


Les machines SIMD

Les machines SIMD (Single Instruction Multiple


Data) sont des machines parallles. Comme son
nom l'indique, elles oprent en appliquant un
instant donn, la mme instruction sur plusieurs
flux de donnes.
De manire abstrait l'on peut considrer une
machine SIMD comme une machine ayant une
seule unit de contrle mais plusieurs units
arithmtiques et logiques. L'instruction est
diffuse aux ALU.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 34/
Les machines SIMD

Les machines SIMD sont bien adaptes pour


parallliser des boucles qui oprent sur de grands
tableaux.
Le paralllisme est obtenu en repartissant les
donnes aux processeurs et chacun applique les
mmes instructions ses donnes (le
paralllisme de donnes).
Une variante des machines SIMD sont les
machines vectorielles (qui oprent sur des
tableaux
2014 - 2015
au lieu des lments).
Vincent Douwe <douwevincent@yahoo.fr> 35/
Les machines MIMD

Les machines MIMD(Multiple Instructions Multiple


Data) sont des machines qui supportent plusieurs
flux d'instructions qui oprent sur des donnes
diffrentes. Les machines MIMD sont constitues
d'une collection d'units de traitement autonomes
chacun ayant son propre unit de contrle et unit
arithmtique et logique.
Contrairement aux SIMD, les MIMD sont des
systmes asynchrones.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 36/


Les machines MIMD
Il existe deux classes de machines MIMD
dpendant de l'organisation de la mmoire :
Les systmes mmoire partage : une
collection de processeurs autonomes connects
la mme mmoire travers un rseau
d'interconnexion.
Les systmes mmoire distribue. Chaque
processeur a sa mmoire prive qui ne peut tre
accde par les autres processus. Les processus
communiquent gnralement en envoyant
explicitement
2014 - 2015 desVincent
messages.
Douwe <douwevincent@yahoo.fr> 37/
Les systmes mmoire
partage
CPU CPU CPU CPU

...

Interconnexion

Mmoire

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 38/


Les systmes mmoire
partage
La plupart des systmes mmoire partage
utilisent un ou plusieurs processeurs multicurs
Dans un systme avec plusieurs curs, les
curs peuvent tre directement connects la
mmoire centrale (UMA) ou chaque cur a une
connexion directe avec un bloc de la mmoire et
les autres blocs mmoires sont accds grce
un matriel spcialis (NUMA).

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 39/


Les systmes mmoire
partage
Les systmes UMA (Uniform Memory Access)
sont faciles programmer parce que le
programmeur n'a pas se soucier des temps
d'accs aux diffrentes locations de la mmoire
centrale.
Les systmes NUMA (NonUniform Memory
Access) ont cet avantage que les processeurs
accedent rapidement aux blocs auxquels ils sont
directement connects. De plus, ils ont la
possibilit d'utiliser des mmoires plus larges.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 40/
Les systmes mmoire
distribue
CPU CPU CPU

Mmoire Mmoire Mmoire

Interconnexion

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 41/


Les systmes distribus

Les systmes distribus les plus rpandus sont


les clusters. Ils sont composs d'un ensemble de
systmes appels des nuds de calcul connects
travers un rseau de communication
conventionnel.
Les grilles de calcul fournissent une infrastructure
qui permet de transformer un large rseau
d'ordinateurs gographiquement distribus en un
systme unifi de mmoire distribu.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 42/


L'interconnexion des rseaux

L'interconnexion des rseaux joue un rle


prpondrant aussi bien dans les systmes
mmoires partages que dans les systmes
mmoires distribues.
Une interconnexion lente va dgrader les
performances du systmes quel que soit la
vitesse d'excution des processeurs.
Nous allons prsenter certaines interconnexions
utilises dans la littrature.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 43/
L'interconnexion des rseaux

Dans les systmes mmoires partages, on


trouve gnralement le bus et le crossbar.
Dans les systmes mmoires distribues l'on
rencontre souvent l'anneau et le tore(toroidal
mesh).
L'on rencontre aussi l'hypercube et les rseaux
Omga.
L'on utilise souvent la latence, la bissection et le
dbit comme mtriques pour mesurer la
performance
2014 - 2015 desVincent
rseaux d'interconnexion.
Douwe <douwevincent@yahoo.fr> 44/
La cohrence des caches

Les mmoires caches sont gres par le


matriel. Le programmeur n'y a pas un contrle
direct.
Un problme crucial survient lorsque l'on utilise
des systmes mmoires partages et que
chaque unit de calcul a une cache prive.
Il peut survenir une situation o la mme valeur
manipule par deux curs est change dans les
deux caches.
On parle de problme
2014 - 2015 de cohrence de cache.
Vincent Douwe <douwevincent@yahoo.fr> 45/
La cohrence des caches
Il existe deux approches pour grer les
problmes de cohrence de cache.
Snooping cache coherence. Lorsqu'une ligne
contenant la valeur x est modifie dans une
cache, les autres caches sont notifies de ce
changement.
Directory based cache coherence. On gre le
problme de cohrence en utilisant une structure
de donnes appele rpertoire Le rpertoire
stocke le statut de chaque ligne de la cache.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 46/
Les programmes parallles

Les machines parallles sont arrives mais


malheureusement le logiciel n'a pas suivi.
l'exception des systmes d'exploitation, des
systmes de gestion des bases de donnes et
des serveurs web, la plupart des autres
applications sont squentielles.
Typiquement, pour avoir un programme parallle,
dans les systmes mmoire partage l'on va
utiliser les threads alors que dans les systmes
mmoire distribue l'on va utiliser les processus.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 47/
Les programmes parallles

D'une manire gnrale, l'on ne va pas utiliser


des programmes diffrents pour les diffrents
threads/processus. L'on va utiliser principalement
les programmes SPMD (Single Program Multiple
Data).
If (Thread / process 0)
do this
else
do that.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 48/
Les programmes parallles

Certains programmes SPMD peuvent tre non


dterministe c'est dire la sortie du programme
change entre les excutions (gnralement du
lordonnancement des threads/processus).
Gnralement, les oprations d'entres/sorties
sont excutes par un seul thread/processus
(bien identifi).

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 49/


Performance

L'on utilise lacclration et lefficacit pour


mesurer la performance des programmes
parallles.
L'acclration est le rapport entre le temps du
meilleur algorithme squentiel sur le temps de
l'algorithme parallle
=

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 50/


Performance

Lefficacit est le rapport entre lacclration et le


nombre de processus.


= =

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 51/


La loi d'Amdahl

Dans les annes 1960, Gene Amdahl a fait une


observation qui est connu sous le nom de loi
d'Amdahl.
Elle stipule que sauf si une programme est
entirement paralllisable, sinon lacclration
sera limite quelque soit le nombre d'units de
calcul que l'on a.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 52/


La conception des programmes
parallles
Il n'existe malheureusement pas une approche
gnrique qui puisse tre utilise pour parallliser
un code squentiel.
Chaque classe de programmes prsentent ses
propres spcificits.
Cependant, Ian Foster propose un ensemble
d'tapes suivre pour la conception des
programmes parallles.
Cette mthodologie semble marcher dans la
pratique pour plusieurs classes de programmes.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 55/
La mthodologie Foster

1.Partitionnement. Diviser le traitement raliser et les


donnes en de petites tches. Il faut mettre l'accent sur les
tches qui peuvent tre excutes en parallle.
2.Communication. Dterminer quelle communication est
ncessaire entre les diffrentes tches.

3.Agrgation. Combiner les tches et les communications


prcdentes en des tches plus larges.

4.Mappage. Assigner les tches composites aux


processus/threads. L'on doit chercher minimiser les
communications.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 56/


MISE EN OEUVRE AVEC LES
PTHREADS

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 57/


Introduction

Un langage de programmation doit supporter trois


aspects de base de la programmation parallle :
Spcifier une excution parallle
Spcifier les communications entre les diffrents
threads
Exprimer la synchronisation entre les threads.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 58/


Introduction

Les pthreads fournissent un mecanisme pour


cration des threads.
Dans ce cours, les pthreads seront utiliss pour
exprimer un paralllisme dans une architecture
mmoire partage.
La communication sera travers des mmoires
partags.
Nous allons introduire des mcanismes de
synchronisation entre threads.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 59/
Introduction

Un processus dsigne un programme en cours


d'excution. En plus de son code d'excution, un
processus possde :
Un bloc mmoire pour la pile
Un bloc mmoire pour le tas
Les descripteurs des ressources utilises par le
processus
Information de scurit
Information sur l'tat
2014 - 2015
du processus
Vincent Douwe <douwevincent@yahoo.fr> 60/
Introduction

Par dfaut, les blocs mmoire d'un processus


sont privs. Un autre processus ne peut accder
directement ces zones mmoires sans une
intervention du systme d'exploitation.
Cette situation n'est pas idale dans un
environnement mmoire partage car on
aimerait que certaines variables soient partages.
C'est pour cette raison que l'on va utiliser des
processus plus lgers appels thread.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 61/
Introduction
Un thread, originellement reprsente un fil de
contrle.
Un fil de contrle est juste une squence
d'instruction dans un programme.
Ainsi, un processus peut avoir plusieurs fil de
contrle.
Pthreads dsigne POSIX threads, une
spcification des threads suivant la norme POSIX.
Nous allons utiliser le langage C pour montrer
l'API.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 62/
Introduction

Les threads d'un mme processus ne partagent


pas le mme bloc de code mais la plupart des
autres blocs mmoires sont partag.
Les threads peuvent tre implments comme
bibliothque au niveau utilisateur ou bien
implments niveau noyau (fourni par le systme
d'exploitation).
Les threads POSIX sont implments comme
bibliothque.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 63/
Structure des donnes

Pour manipuler les threads en C, l'on utilise la


structure de donnes pthread_t dfinie dans
pthread.h.
Un lment de pthread_t dsigne un descripteur
du thread.
En gnral, ce type est un type synonyme de int.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 64/


La cration des threads

Pour crer un thread, on utilise l'appel systme pthread_create.


#include <pthread.h>
int pthread_create(pthread_t *thread_id, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Elle permet de dmarrer un nouveau thread pour excuter la
fonction start_routine avec l'argument arg. Si le dmarrage s'est
bien droul, le descripteur du thread est stock dans thread_id,
qui sera utilis pour identifier le thread. Le paramtre attr est un
pointeur vers une structure de donnes qui contient les attributs
utiliser lors du dmarrage du thread. Si cette valeur est NULL,
alors le thread est dmarrer avec les attributs par dfauts.
Si
2014tout
- 2015 se passe bien, Vincent
pthread_create renvoie la valeur 0.
Douwe <douwevincent@yahoo.fr> 65/
La cration des threads

Lorsqu'un thread est dmarr, il se termine si :


Il appelle la fonction pthread_exit() en spcifiant
une valeur de retour;
Il a fini d'excuter les instructions de la fonction
start_routine.
Il est annul grce pthread_cancel().
Un autre thread du mme processus a appel
exit().
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 66/
La cration des threads

La structure de donnes pthread_attr_t peut tre initialise grce


la fonction pthread_attr_init() et dtruite grce
pthread_attr_destroy().
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
Ces fonctions renvoyent 0 si tout se passe bien.
pthread_attr_init initialise la structure avec les valeurs par dfauts.
Une fois la structure initialise, l'on peut utiliser un ensemble de
fonctions pour la modifier.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 67/


La cration des threads

Lorsque le dmarrage du thread choue,


pthread_create() renvoie une valeur diffrente de 0 et le
contenu de thread_id est indfini.
Les codes d'erreurs sont (variable ERRNO):
EAGAIN : pas assez de ressources pour dmarrer le
thread ou la limite du nombre de thread impose par le
systme est atteint.
EINVAL : des attributs invalides dans attr.
EPRM : pas assez de permissions pour dfinir la
politique d'ordonnancement ou pour spcifier certains
attributs
2014 - 2015 dans attr. Vincent Douwe <douwevincent@yahoo.fr> 68/
Modification des attributs
Les fonctions suivantes permettent de modifier un lment de type
pthread_attr_t :
pthread_attr_setaffinity_np
pthread_attr_setdetachstate
pthread_attr_setguardsize
pthread_attr_setinheritsched
pthread_attr_setschedparam
pthread_attr_setschedpolicy
pthread_attr_setscope
pthread_attr_setstack
pthread_attr_setstackaddr
pthread_attr_setstacksize
pthread_getattr_np
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 69/
Arrt des threads

L'on peut mettre fin excution d'un thread grce la fonction


pthread_cancel.
#include <pthread.h>
int pthread_cancel(pthread_t thread_id);
Cette fonction envoie une requte de terminaison au thread dont le
descripteur est thread_id.
La raction du thread en question dpend de deux variables : le
type du thread et sa proprit qui indique s'il peut tre annul.
En cas de succs, cette fonction renvoie la valeur 0.
Le code d'erreur ESRCH indique qu'il n'existe pas de thread ayant
le descripteur thread_id.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 70/
Arrt des threads

L'arrt d'un thread dpend de l'tat et du type.


La proprit qui indique si un thread peut tre arrt est
dtermine par la fonction pthread_setcancelstate(). Elle peut tre
active (par dfaut) ou inactive :
Si elle est inactive, alors une requte d'arrt reste dans une file
d'attente jusqu' ce que le thread change la proprit.
Si elle est active, alors l'arrt dpend du type de thread.
Le type d'un thread est dtermin par la mthode
pthread_setcanceltype(). Le type peut tre asynchrone ou deferred
(par dfaut). Un thread asynchrone peut tre arret tout moment.
Un thread deferred va attendre jusqu' l'atteinte du prochain point
d'arrt.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 71/
Arrt des threads

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
Les diffrentes valeurs de state sont :
PTHREAD_CANCEL_ENABLE : l'arrt est actif
PTHREAD_CANCEL_DISABLE : l'arrt est inactif.
Les valeurs de type sont :
PTHREAD_CANCEL_DEFERRED : le type est deferred.
PTHREAD_CANCEL_ASYNCHRONOUS : le type est
asynchrone.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 72/
Fin d'un thread

Un thread peut mettre fin son excution grce


la fonction pthread_exit.
#include <pthread.h>
void pthread_exit(void *retval);
La valeur retval est renvoye un autre thread du
mme processus qui a appel pthread_join si le
thread courant est joignable.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 73/


Atteindre la fin d'un thread
Pour permettre la synchronisation entre diffrents threads, il est
souvent ncessaire d'attendre la fin de l'excution d'un thread.
Pour cela, l'on utilise la fonction pthread_join.
#include <pthread.h>
int pthread_join(pthread_t thread_id, void **retval);
Cette fonction permet d'attendre la fin de l'excution du thread dont
le descripteur est thread_id. Si le thread en question a dj fini son
excution, alors retourne immdiatement.
Pour que cette fonction marche correctement, il faut que le thread
dont le descripteur est thread_id doit tre joignable.
Si retval n'est pas NULL, alors pthread_join copie la valeur
renvoye par pthread_exit (de thread_id) dans retval. Si le thread a
t- 2015
2014 annul, alors l'on aura la valeur
Vincent Douwe PTHREAD_CANCELED.
<douwevincent@yahoo.fr> 74/
Atteindre la fin d'un thread

Si plusieurs threads essayent de joindre le mme


thread simultanment, alors le rsultat est indfini.
pthread_join renvoie 0 si tout se passe bien.
Les codes d'erreurs sont :
EDEADLK : un deadlock est dtect.
EINVAL : le thread n'est pas joignable
ESRCH : aucun thread n'a le descripteur
thread_id
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 75/
Exemple Hello World
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* start_routine(void *arg);
int main(int argc, char *argv[]){
int i, n;
if(argc > 1){
n = atoi(argv[1]);
pthread_t ids[n];
for(i = 0; i < n; i++){
pthread_create(&ids[i], NULL,start_routine,(void *)&i);
}
}
return 0;
}
void* start_routine(void *arg){
int val = *((int *) arg);
printf("Hello World du thread %d \n", val);
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 76/
}
Compilation des programmes

Une fois le programme crit, il faut le compiler


avec l'option -pthread.
Par exemple si notre programme est dans un
fichier HelloWorld.c alors l'on peut le compiler :
gcc -o hello HelloWorld.c -pthread

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 77/


Problmes de synchronisation
Lorsque plusieurs threads accdent de manire concurrentielle
une ressource, le rsultat est indfini (dpendant de
l'ordonnancement des threads).
Il est souvent ncessaire de ne pas permettre deux threads de
modifier simultanment la mme variable.
Pour cela, l'on va crer des zones que l'on appelle sections
critiques et mettre en place des mcanismes d'exclusion mutuelle.
Il existe plusieurs mcanismes pour raliser l'exclusion mutuelle :
L'attente active ;
Les mutex ;
Les smaphores ;
Les variables conditions.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 78/
L'attente active

Lorsqu'un thread doit modifier une variable, il doit se rassurer


qu'aucun autre thread n'est entrain de modifier la variable.
Une solution simple consiste utiliser une variable qui va dire si
oui ou non la variable est entrain d'tre modifi.
int flag = 0 ;
// entrer en section critique.
while (flag!= 0) ;
flag = 1 ;
section critque
flag = 0 ;
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 79/
L'attente active

Comme vu en systme d'exploitation, l'attente


active n'est pas une bonne solution.
Le thread qui est en attente n'est pas bloqu et
ainsi continue toujours d'utiliser le temps
processeurs.
De plus, ce mcanisme ne garantie pas qu'un
seul thread la fois sera dans la section critique.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 80/


Utilisation des mutex
Mutex est labrviation de mutual exclusion.
Un mutex est un type spcial de variable sur lequel est dfini
quelques oprations :
Dans la spcification pthreads, les mutex sont des variables du
type pthread_mutex_t.
Un mutex doit tre initialis avant d'tre utilis grce la mthode
pthread_mutex_init()
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t * mutex_p, const
pthread_mutexattr_t *attr_p) ;
Permet d'initialiser un mutex et stocker la rfrence dans mutex_p
en
2014 -utilisant
2015 les attributsVincent
attr_p
Douwe;<douwevincent@yahoo.fr> 81/
Utilisant des mutex

Un mutex peut tre dtruit grce la fonction


pthread_mutex_destroy.
Pour entrer dans une section critique, l'on appelle la fonction
pthread_mutex_lock et lorsque l'on sort l'on doit excuter
pthread_mutex_unlock
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex_p) ;
int pthread_mutex_lock(pthread_mutex_t *mutex_p) ;
int pthread_mutex_unlock(pthread_mutex_t *mutex_p) ;
Trs souvent, au lieu d'appeler pthread_mutex_init, l'on utilise la
macro PTHREAD_MUTEX_INITIALIZER
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 82/
Utilisation des smaphores

Les mutex sont intressant lorsque l'on veut qu'un


processus au maximum soit dans la section critique.
Mais, il existe des situations o l'on autorise un
nombre maximum de threads excuter un
traitement. Le cas usuel est le problme du
producteur/consommateur.
Dans ces situations, l'utilisation des smaphores est
plus approprie.
Les smaphores peuvent tre considrs comme des
variables d'un type spcial (synonyme de unsigned
int).
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 83/
Les smaphores

Les smaphores sont dfinis dans la bibliothque <semaphore.h>


L'on peut initialiser un smaphore grce sem_init(), dtruire
grce sem_destroy(), dcrmenter le smaphore grce
sem_wait(), incrmenter grce sem_post.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
Lorsque l'on effectue un sem_wait sur un smaphore dont la
valeur
2014 - 2015
est 0, l'on est bloqu.
Vincent Douwe <douwevincent@yahoo.fr> 84/
Les smaphores
Puisque la fonction sem_wait peut tre bloquante, l'API fournit
d'autres fonctions qui permettent de tester la valeur du smaphore
avant d'appeler sem_wait.
#include <semaphore.h>
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec
*abs_timeout);
sem_trywait est comme sem_wait la diffrence que si l'on ne
peut pas dcrementer le smaphore, elle renvoie une erreur
(EAGAIN) au lieu de bloquer l'appelant.
sem_timedwait() est comme sem_wait() la diffrence que
abs_timeout spcifie le temps maximal pendant lequel le thread
doit- 2015
2014 rester bloquer. Vincent Douwe <douwevincent@yahoo.fr> 85/
Les smaphores

La structure de donnes est dfinie comme suit :


struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds [0 .. 999999999] */
};
L'on peut aussi accder la valeur courante d'un smaphore
grce la fonction sem_getvalue().
#include <semaphore.h>
int sem_getvalue(sem_t *sem, int *sval);
La valeur du smaphore sem est copi dans sval.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 86/
Les barrires de synchronisation

Il arrive trs souvent que l'on a besoin que tous


les threads atteignent un niveau (une barrire)
avant de continuer leur excution.
L'on peut facilement implmenter une barrire en
utilisant un mutex et l'attente active.
L'on peut mme utiliser les smaphores pour
raliser les barrires.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 87/


La barrires avec mutex + attente

/ Shared and initialized by the void Thread_work(. . .) {


main thread / ...
int counter; / Initialize to 0 / / Barrier /
int thread_count;
pthread_mutex_t barrier_mutex; pthread_mutex_lock(&barrier_mute
... x);
counter++;

pthread_mutex_unlock(&barrier_m
utex);
while (counter < thread_count);
...
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 88/
Barrires avec les smaphores

/ Shared variables / void Thread_work(...) {


int counter; / Initialize to 0 / ...
/ Barrier /
sem_t count_sem; / Initialize to 1 /
sem_wait(&count_sem);
sem_t barrier_sem; / Initialize to 0 / if (counter == thread_count1) {
... counter = 0;
sem_post(&count sem);
for (j = 0; j < thread_count1; j++)
sem_post(&barrier_sem);
} else {
counter++;
sem_post(&count_sem);
sem_wait(&barrier_sem);
}
...
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 89/
Les barrires avec les variables
condition
Une meilleure approche pour l'implmentation des
barrires avec pthreads est l'utilisation des variables
condition.
Une variable condition est un objet qui permet un
thread de suspendre son excution jusqu' ce qu'un
vnement ou condition survienne.
Lorsque l'vnement ou la condition survient, un
autre thread peut signaler au thread suspendu de se
rveiller
Une variable condition est toujours associ un
mutex.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 90/
Barrires avec les variables
conditions
Typiquement, l'on a un code similaire :
Verrouiller mutex;
Si condition survient
Envoyer signaux aux threads
sinon {
Dverrouiller mutex
bloquer
}
dverrouiller mutex;
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 91/
Barrires avec les variables
condition
Les variables condition ont le type pthread_cond_t.
L'on bloque un thread bloqu grce la fonction
pthread_cond_signal et l'on dbloque tous les threads
grce pthread_cond_broadcast. pthread_cond_wait
permet de verrouiller le mutex associ et suspendre le
thread.
Int pthread_cond_signal(pthread_cond_t * cond_var) ;
Int pthread_cond_broadcast(pthread_cond_t * cond_var) ;
Int pthread_cond_wait(pthread_cond_t *cond_var,
pthread_mutex_t *mutex_p) ;

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 92/


Les barrires avec les variables
condition
L'effet de pthread_cond_wait est similaire au code
suivant :
pthread_mutex_unlock(&mutex_p);
wait_on_signal(&cond_var);
pthread_mutex_lock(&mutex_p);

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 93/


Les barrires avec les variables
condition
/ Shared / void Thread_work(. . .) {
int counter = 0; ...
/ Barrier /
pthread mutex t mutex;
pthread_mutex_lock(&mutex);
pthread cond t cond var;
counter++;
... if (counter == thread_count) {
counter = 0;
pthread_cond_broadcast(&cond_var);
} else {
while (pthread_cond_wait(&cond_var,
&mutex) != 0);
}
pthread_mutex_unlock(&mutex);
...
2014 - 2015 }
Vincent Douwe <douwevincent@yahoo.fr> 94/
Les variables condition

Tout comme les smaphores et les mutex, les


variables conditions peuvent tre initialises et
dtruites.
int pthread_cond_init(pthread_cond_t * cond_p,
const pthread_condattr_t *cond_attr) ;
int pthread_cond_destroy(pthread_cond_t *cond_p) ;

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 95/


Exercices

La multiplication d'une matrice et d'un vecteur/


Le calcul de la valeur approche de PI grce la
formule
1 1 1
1
= 4 1 + +. . . 1 +. . .
3 5 7 2n + 1

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 96/


MISE EN OEUVRE AVEC
OPENMP

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 97/


Introduction
OpenMP est une API pour l'criture des applications
pour des architectures parallles mmoire
partage.
Il est constitu d'un ensemble de directives pour le
compilateur et d'un ensemble de fonctions.
Avec OpenMP, il est relativement ais de crer des
applications multithreades.
OpenMP est standardis depuis plus de 20 ans.
Il est support par les vendeurs de matriels,
dveloppeurs d'applications et de vendeurs d'outils
de- 2015
2014 dveloppement.
Vincent Douwe <douwevincent@yahoo.fr> 98/
Introduction

OpenMP est une API pour l'criture des


programmes multithreads.
Cette API est constitue d'un ensemble de
directives pour le compilateur et d'un ensemble de
routines.
OpenMP simplifie grandement l'criture des
programmes multithreads en C, C++ et Fortran.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 99/


Architecture de OpenMP
Applications

Directives, Environment
OpenMP library
Compiler variable

OpenMP runtime library

OS/System support for shared memory and threading

Proc1 Proc2 Proc3 ... ProcN

Shared address space

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 100/


Les lments de syntaxe

La plupart des lments de OpenMP sont les


directives adresses au compilateur.
Les directives en C se prsentent sous la forme
#pragma omp
Les prototypes des fonctions et les structures de
donnes utilises sont dfinis dans la bibliothque
<omp>
La plupart des lments de OpenMP s'appliquent
des blocs structurs c'est dire un ensemble
d'instructions
2014 - 2015 entre
Vincent{...}
Douwe <douwevincent@yahoo.fr> 101/
Installation de OpenMP

La plupart des distributions Linux viennent avec


OpenMP install.
Si OpenMP n'est install sur votre machine et que
vous utilisez une variante debian, il suffit
d'excution sudo apt-get install libgomp1 pour
l'installer.
Pour activer OpenMP lors de la compilation, il faut
invoquer gcc avec l'option -fopenmp.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 102/


Modle d'excution

OpenMP permet au dveloppeur de parallliser


leurs codes de faon progressive.
L'on commence avec un code squentiel que l'on
va parallliser de manire incrmentale.
OpenMP implmente un modle appel fork/join.
L'on commence l'excution du programme avec
un seul thread et lorsque l'on rencontre une zone
paralllisation (dfinie grce aux directives), l'on
cre un ensemble de threads a qui l'on va
attribuer
2014 - 2015 des tches.
Vincent Douwe <douwevincent@yahoo.fr> 103/
Le modle fork/join
Thread maitre

Rgions parallles

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 104/


Les directives OpenMP

Comme soulign au dbut, l'on utilise OpenMP


grce un ensemble de directives adresses au
compilateur.
Les directives en C se prsentent sous la forme
suivante dans le code source:
#pragma omp construct [clause[clause]...]
Lorsque l'on compile un code contenu les
directives OpenMP avec un compilateur ne
supportant pas OpenMP, ces directives sont
simplement
2014 - 2015 ignors.
Vincent Douwe <douwevincent@yahoo.fr> 105/
La cration des threads
La seule faon de crer les threads avec OpenMP
est d'utiliser le construct parallel.
#pragma omp parallel
{
bloc
}
Lorsque l'on rencontre cette directive dans un
programme, le compilateur va gnrer un
ensemble de threads et chaque thread va
excuter
2014 - 2015 les codes
Vincentdans le bloc.
Douwe <douwevincent@yahoo.fr> 106/
La cration des threads

Lorsque l'on rencontre la directive #pragma omp


parallel, l'on se retrouve avec deux types de
variables :
Les variables dclares extrieur du bloc sont
dclares dans le tas et sont visibles tous les
threads. Ces variables sont partages par tous les
threads.
Les variables dclares l'intrieur du bloc sont
dclares dans la pile et sont prives chaque
thread.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 107/
La cration des threads

L'on peut contrler le nombre de threads crs


grce la clause num_thread(nombre) au niveau
de la directive.
#pragma omp num_thread(4) permet de crer un
groupe de quatre threads.
Cette directive supporte un ensemble de clauses
qui seront prsentes dans la suite du cours.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 108/


La cration des threads

Lorsque le compilateur rencontre un code comme


#pragma omp parallel num_thread(4)
{
foo();
}
Il va gnrer un code qui ressemble au code
suivant.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 109/


La cration des threads
void thunk(){
foo();
}
pthread_t tid[4];
int i ;
for(i=1 ; i<4 ; i++)
pthread_create(&tid[i], NULL, thunk(),NULL) ;
thunk() ;
for(i=1 ; i<4 ; i++)
pthread_join(tid[4], NULL) ;
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 110/
Le programme HelloWorld
#include <stdio.h>
#include <omp.h>
int main(void){
#pragma omp parallel num_thread(4)
{
int ID = omp_get_thread_num() ;
printf("Hello (%d)", ID) ;
printf("World (%d) \n", ID) ;
}
return 0 ;
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 111/
Exercice

crire le programme pour le calcul de PI en


utilisant uniquement la directive #pragma omp
parallel.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 112/


Synchronisation

Lorsque l'on doit grer l'accs des threads une


variable partage, il faut synchroniser l'accs
cette variable.Avec OpenMP, il existe deux
catgories :
Les barrires de synchronisation
L'exclusion mutuelle.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 113/


Les barrires de synchronisation
L'on introduit les barrires de synchronisation
grce la directive #pragma omp barrier.
#pragma omp parallel
{
int id = omp_get_thread_num() ;
A[id] = big_calc1(id) ;
#pragma omp barrier
B[id] = big_calc2(A,id) ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 114/
L'exclusion mutuelle
Il existe un ensemble de directives pour raliser l'exclusion
mutuelle. La forme la plus courante est l'utilisation de la
directive #pragma omp critical.
float res ;
#pragma omp parallel
{
float B ; int i, id ;
Id = omp_get_thread_num() ;
for(i = id ; i < N ; i+= num_threads){
B = big_job(i) ;
#pragma omp critical
res += consume(B) ;
2014}- 2015 Vincent Douwe <douwevincent@yahoo.fr> 115/

}
Exclusion mutuelle
L'on peut galement raliser l'exclusion mutuelle
en utilisant la directive #pragma omp atomic.
Cette directive permet de raliser une opration
(binaire) de manire atomique.
#pragma omp parallel
{
double tmp, B ;
B = DOIT() ;
tmp = big_ugly(B) ;
#pragma omp atomic
X += tmp ;
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 116/
}
Le partage de tches

Jusqu' present, nous avons prsent les


directives pour la cration des threads mais il
revient au programmeur de repartir les tches
ces threads.
L'on peut donc se retrouver avec des bouts de
codes rptitifs.
Pour simplifier les choses, OpenMP introduit la
directive #pragma omp for pour la rpartition des
tches.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 117/
Le partage des tches

int i ; int i ;
for(i =0 ; i<N ; i++){ #pragma omp parallel

c[i] = a[i] + b[i] ; {


int id = omp_get_thread_num() ;
}
int chunk = N / num_threads ;
int start = i * chunk ;
int end = (i+1)*chunk;
for(i =start ; i<end ; i++)
c[i] = a[i] + b[i] ;

2014 - 2015
}
Vincent Douwe <douwevincent@yahoo.fr> 118/
Le partage des tches
Avec le code prsent dans le slide prcdent,
l'on se rend compte que l'on doit utiliser un code
similaire pour chaque rgion parallle
En utilisant la directive #pragma omp for, l'on a
bout de code suivant
#pragma omp parallel
{
#pragma omp for
for(i =0 ; i<N ; i++)
c[i] = a[i] + b[i] ;
} - 2015
2014 Vincent Douwe <douwevincent@yahoo.fr> 119/
Le partage des tches

Il existe plusieurs stratgie pour la rpartition des


tches et laquelle sera choisie par le
compilateur ?
Le choix de la stratgie est gouvern par la clause
schedule.
schedule (static [,chunk]).Le partage se fait au
moment de la compilation et l'on procde une
rpartition bloc cyclique entre les threads et
chaque bloc a pour taille chunk.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 120/
Le partage des tches

schedule (dynamic [,chunk]). La rpartition se fait


l'excution. L'on va crer des blocs de taille
chunk dans une queue et les threads vont se voir
allouer des blocs en fonction de leur vitesse
d'excution.
schedule (guided [,chunk]). Les threads vont se
voir allouer dynamiquement des blocs de taille
grande et diminuer pour atteindre chunk.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 121/


Le partage des tches

schedule (runtime). La stratgie et la taille sont


dfinies par la variable d'environnement
OMP_SCHEDULE (ou de fonction l'excution)
schedule(auto). Tout est laiss la charge du
compilateur.
OpenMP rend la variable utilise dans la bouclle
for prive chaque thread.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 122/


Le partage des tches

L'on se retrouve la plupart du temps combiner la


directive #pragma omp parallel avec la directive
#pragma omp for.
OpenMP nous donne la possibilit de combiner
ces deux directives pour obtenir #pragma omp
parallel for

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 123/


Le partage des tches

double res[MAX] ; double res[MAX] ;


int i ; int i ;
#pragma omp parallel #pragma omp parallel for
{ {
#pragma omp for for(i=0 ; i<MAX ; i++)
for(i=0 ; i<MAX ; i++) res[i] = huge(i) ;
res[i] = huge(i) ; }
}

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 124/


Le partage des tches

Pour obtenir un meilleur partage des tches, il faut


liminer les dpendances entre les itrations de la
boucle.
L'on procde comme suit :
Rechercher les boucles qui ralisent un calcul
intensif
Modifier ces itrations pour liminer les
dpendances entre les itrations
Mettre la directive #pragma omp for.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 125/
Le partage des tches

int i, j, A[MAX] ; int i, A[MAX] ;


j=5; for(i=0 ; i <MAX ; i++){
for(i=0 ; i <MAX ; i++){ int j = 2* i + 5 ;
j += 2 ; A[i] = big(j) ;
A[i] = big(j) ; }
}

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 126/


La rduction
La rduction permet de transformer un ensemble
de valeurs en une seule valeur.
Il s'agit essentiellement des itrations qui ont des
dpendances.
Exemple : calcul de la moyenne.
double ave = 0.0, A[MAX] ;
int i ;
for(i = 0 ; i < MAX ; i++)
ave += A[i] ;
ave
2014 /= MAX ;
- 2015 Vincent Douwe <douwevincent@yahoo.fr> 127/
La rduction

OpenMP introduit une clause reduction aux


directives #pragma omp for ou #pragma omp
parallel pour ces genres de cas.
reduction (op:list)
Une copie locale de chaque variable dans la liste
sera cre pour chaque thread et initialise
dpendant le l'opration :
0 pour +
1 pour *
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 128/
Les oprations de rductions
Oprateur Type de donnes Valeur initiale
+ Entier, rel 0
* Entier, rel 1
- Entier, rel 0
& Entier Tous les bits 1
| Entier 0
^ Entier 0
&& Entier 1
|| Entier 0
min Entier,rel Plus grande valeurs
max Entier, rel Plus petite valeur
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 129/
La rduction

double ave = 0.0, A[MAX] ;


int i ;
#pragma omp parallel for reduction(+:ave)
for(i = 0 ; i <MAX ; i++)
ave += A[i] ;
ave /= MAX;

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 130/


La clause nowait

En gnral, la fin des directives OpenMP, il


existe une barrire implicite. Tous les threads
doivent atteindre le mme niveau avant de
continuer.
La clause nowait permet cependant de supprimer
cette barrire implicite.
nowait ne s'applique cependant pas la directive
#pragma omp parallel et il n'existe pas de moyen
de supprimer cette barrire implicite.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 131/
La clause nowait
#pragma omp parallel shared(A,B,C) private(id)
{
id = omp_get_thread_num() ;
A[id] = big_calc(id) ;
#pragma omp barrier
#pragma omp for
for(i = 0 ; i <N ; i++)
c[i] = big_calc3(i,A) ;
#pragma omp for nowait
for(i = 0 ; i <N;i++)
B[i] = big_calc2(C,i) ;
A[id] = big_calc4(id) ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 132/
La directive master
Cette directive indique ce seul le thread maitre
doit excuter ce bloc de code.
Il n'y a pas de barrire implicite la fin de cette
directive.
#pragma omp parallel
{
do_many_things() ;
#pragma omp master
exchange_boundaries() ;
#pragma omp barrier
do_many_other_things() ;
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 133/
}
La directive single

Cette directive indique ce bloc de code doit tre


excut par un seul thread.
Il y'a une barrire la fin de cette directive.
#pragma omp parallel
{
do_many_things() ;
#pragma omp single
exchange_boundaries() ;
do_many_other_things() ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 134/
Les sections

Il est souvent ncessaire de considrer des blocs


de code comme des tches qui peuvent tre
excutes de manire parallle.
Pour cela, l'on va englober ces blocs de code
dans des sections et chaque bloc indpendant
(une tche) dans une section.
Le bloc l'intrieur d'une section sera excut par
un seul thread.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 135/


Les sections

#pragma omp parallel


{
#pragma omp sections
{
#pragma omp section
x_calculation() ;
#pragma omp section
y_calculation() ;
#pragma omp section
z_calculation() ;
}
} - 2015
2014 Vincent Douwe <douwevincent@yahoo.fr> 136/
Les verrous
Il s'agit des routines de bas niveau pour la
synchronisation dans les programmes
concurrents.
Nous avons les routines suivantes pour la gestion
des verrous avec OpenMP (variable de type
lock_t).
omp_init_lock() pour initialiser les verrous;
omp_set_lock() pour acquerir le verrou;
omp_unset_lock() pour relacher un verrou;
omp_destroy_lock() pour dtruire un verrous;
omp_test_lock()
2014 - 2015 teste si le<douwevincent@yahoo.fr>
Vincent Douwe verrou est disponible ; 137/
Les verrous
#pragma omp parallel for
for(i = 0 ; i <NBUCKETS ; i++){
omp_init_lock(&hist_locks[i]) ; hist[i] = 0 ;
}
#pragma omp parallel for
for(i = 0 ; i < NVALS ; i++){
ival = (int) sample(ar[i]) ;
omp_set_lock(&hist_locks[ival]) ;
hist[ival]++ ;
omp_unset_lock(&hist_locks[ival]) ;
}
for(i = 0 ; i < NBUCKETS ; i++)
2014 omp_destroy_lock(&hist_locks[i])
- 2015 ;
Vincent Douwe <douwevincent@yahoo.fr> 138/
Les fonctions disponibles
Il est possible de raliser certaines oprations lors
de l'excution.
C'est pour cette raison que OpenMP dfinit un
ensemble de fonctions qui peuvent tre appeles
lors de l'excution.
omp_set_num_threads() modifie le nombre de
threads.
omp_get_num_threads() renvoie le nombre de
threads.
omp_get_thread_num() renvoie le numro d'un
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 139/
thread.
Les fonctions disponibles

omp_get_max_threads() renvoie le nombre


maximum de threads que l'on peut avoir.
omp_in_parallel renvoie si le code est dans une
rgion parallle
omp_set_dynamic faut il activer le mode
dynamique
omp_get_dynamic le mode dynamique est il
activ
omp_num_procs renvoie le nombre de
processeurs.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 140/
Les fonctions disponibles
#include <omp.h>
void main(void){
int num_threads ;
omp_set_dynamic(0) ;
omp_set_num_threads(omp_num_procs()) ;
#pragma omp parallel
{
int id = omp_get_thread_num() ;
#pragma omp single
num_threads = omp_get_num_threads() ;
do_lots_of_stuff(id, num_threads) ;
}
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 141/
Variables d'environnement

Un ensemble de variables d'environnement


peuvent modifier le comportement des
programmes OpenMP.
OMP_NUM_THREADS dfinit le nombre de
threads crer par dfaut
OMP_STACKSIZE la quantit de mmoire
supplmentaire la pile de chaque thread
OMP_WAIT_POLICY(ACTIVE|PASSIVE). Que
faire lorsqu'un thread doit attendre : attente active
ou- 2015
2014 l'endormir. Vincent Douwe <douwevincent@yahoo.fr> 142/
Variables d'environnement

OMP_PROC_BIND(TRUE|FALSE). Faut il
associer un thread un processeur particulier.
OMP_SCHEDULE : utile lorsque l'on dfinit le
mode de partage des tches runtime.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 143/


La gestion des donnes

L'on est dans un environnement mmoire


partage et OpenMP adopte un certain nombre de
rgles qui dpendent des deux
situations suivantes:
Si une donne se trouve au niveau du tas, alors
elle est partage par tous les threads.
Si une donne se trouve sur la pile, alors la
donne est prive au thread.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 144/


La gestion des donnes
double A[10] ;
int main(void){
int index[10] ;
#pragma omp parallel
work(index) ;
printf("%d \n", index[0]) ;
}
extern double A[10] ;
void work(int *index){
double temp[10] ;
static int count ;
.
} - 2015
2014 Vincent Douwe <douwevincent@yahoo.fr> 145/
La gestion des donnes

Il arrive des situations o les rgles par dfaut ne


correspondent pas nos attentes. OpenMP nous
donne la possibilit de changer la porte des
variables grce un ensemble de clauses :
shared(list) : change la porte partage
private(list) : change la porte prive
firstprivate(list) :
lastprivate(list) :
default(private|shared|none)
2014 - 2015
:
Vincent Douwe <douwevincent@yahoo.fr> 146/
La gestion des donnes
Dans la rgion parallle, la clause private permet
de changer la porte d'une liste de variable
prive. Ainsi des copies des variables sont cres
pour chaque thread et ces variables ne sont pas
initialises.
void wrong(){
int tmp = 0 ;
#pragma omp parallel for private(tmp)
for(int j = 0 ; j < 1000 ; j++)
tmp += j ;
printf("%d \n" , tmp)
2014 - 2015 ; <douwevincent@yahoo.fr>
Vincent Douwe 147/

}
La gestion des donnes

La clause private cre des copies prives des


variables sans les initialises mais firstprivate
permet d'initialiser ces variables aux valeurs des
variables globales.
int incr = 0 ;
#pragma omp parallel for firstprivate(incr)
for(i = 0 ; i <= MAX ; i++){
if(i % 2 == 0)
incr++ ;
A[i] = incr ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 148/
La gestion des donnes
Lorsque l'on sort d'une rgion parallle, les
valeurs des variables prives sont perdues. La
clause lastprivate permet de stocker la valeur de
la dernire itration de la variable dans la variable
globale.
void sq2(int n, double *lastterm){
double x ; int i ;
#pragma omp parallel for lastprivate(x)
for(i = 0 ; i < n ; i++){
x = a[i] *a[i] + b[i] * b[i] ;
b[i] = sqrt(x) ;
}
*lastterm = x ;
} - 2015
2014 Vincent Douwe <douwevincent@yahoo.fr> 149/
La gestion des donnes
En gnral, une variable ne doit pas apparatre
dans plusieurs clauses. Cependant, il est autoris
d'avoir les combinaisons :
firstprivate et lastprivate
private et lastprivate
int A = 1, B = 1, C = 1 ;
#pragma omp parallel private(B) firstprivate(C)
Quelle est la porte des variables A, B et C
Quelles sont les valeurs l'intrieur et la fin de
la2014rgion
- 2015 parallle.Vincent Douwe <douwevincent@yahoo.fr> 150/
Problme compliqu

Comment peut on faire pour parallliser le code


suivant qui permet de traverser une liste
chane ?
p = head ;
while(p){
process(p) ;
p = p-> next ;
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 151/
Problme compliqu

Pour rpondre la question prcdente en


utilisant uniquement les notions vues jusqu'alors,
il faut vraiment faire preuve de crativit.
Le problme vient du fait que OpenMP n'a pas t
conu pour rpondre ce genre de question.
OpenMP 3.0 offre une solution lgante ce
genre de problme en utilisant la notion de
tche(task).

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 152/


Les tches

Une tche reprsente une unit de travail


indpendante.
Une tche est compose :
du code excuter
de l'environnement des donnes
d'un ensemble de variables de contrle interne
(ICV).
Une fois une tche cre, le systme va dcider
de son excution.Vincent Douwe <douwevincent@yahoo.fr>
2014 - 2015 153/
Les tches
Pour dfinir les tches, il faut utiliser la directive
#pragma omp task.
#pragma omp parallel
{
#pragma omp task
foo() ;
#pragma omp barrier
#pragma omp single
{
#pragma omp task
bar() ;
}
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 154/
Les tches

Comment calculer le ieme terme de Fibonnacci


int fib(int n){
int x, y ;
if (n < 2) return n ;
#pragma omp task
x = fib(n -1) ;
#pragma omp task
y = fib(n -2)
#pragma omp taskwait
return x + y ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 155/
Notre problme compliqu

#pragma omp parallel


{
#pragma omp single
{
node * p = head ;
while(p){
#pragma omp task firstprivate(p)
process(p) ;
p = p->next ;
}
}
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 156/
}
Acknowledgement

Cette section est une transcription du cours sur


OpenMP dispens par Tim Mattson disponible sur
youtube.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 157/


Les routines OpenMP

OpenMP dfinit un ensemble de fonctions :


void omp_set_num_threads (int) permet de
spcifier le nombre de threads.
int omp_get_num_threads (void) permet de
connatre le nombre de threads.
int omp_get_max_threads (void) permet de
renvoyer le nombre maximum de threads
int omp_get_thread_num (void) permet de
renvoyer le numro d'un thread dans l'quipe
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 181/
Les routines OpenMP
int omp_get_num_procs (void) renvoie le nombre de
processeurs disponibles.
void omp_set_dynamic (int) contrler l'allocation
dynamique des threads
int omp_get_dynamic (void) teste si l'on a une
allocation dynamique des threads
int omp_in_parallel (void) teste si l'on est dans une
rgion parallle
void omp_set_nested (int) active/dsactive le
paralllisme imbriqu
int omp_get_nested (void) teste si le paralllisme
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 182/
imbriqu est activ.
Les routines OpenMP
void omp_init_lock(omp_lock_t*) alloue et
initialise un verrou
void omp_destroy_lock(omp_lock_t*) desalloue
et dtruit un verrou
void omp_set_lock(omp_lock_t*) acquiert un
verrou
void omp_unset_lock(omp_lock_t*) libre un
verrou
int omp_test_lock(omp_lock_t*) teste si l'on peut
acqurir
2014 - 2015 un verrou.
Vincent Douwe <douwevincent@yahoo.fr> 183/
MISE EN OEUVRE AVEC MPI

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 189/


Introduction

MPI(Message Passing Interface) est une API qui


permet la programmation parallle sur des
architectures mmoire distribus.
MPI fournit une ensemble de fonctions pour
permettre la communication entre divers
processus qui s'excute dans des espaces
d'adressage distinct.
Les fonctions fournies par MPI sont disponibles
dans la bibliothque mpi.h.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 190/
Introduction

Les programmes crit en MPI sont en gnral des


programmes SPMD c'est dire les diffrents
processus vont tous excuter le mme code mais
en fonction d'un certain nombre de conditions.
Les diffrents processus d'un groupe sont
numrots partir de 0.
MPI offre des fonctions qui permettent chaque
processus de connatre son numro (rang) dans
le groupe.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 191/
Initialisation

Avant d'utiliser les fonctions MPI, il faut d'abord


l'initialiser grce la fonction MPI_Init.
#include <mpi.h>
int MPI_Init(int *argc, char ***argv)
Elle permet d'initialiser l'environnement
d'excution MPI.
argc pointe sur le nombre d'arguments en ligne de
commande.
argv
2014 - 2015
pointe sur leVincent
pointeur des arguments.
Douwe <douwevincent@yahoo.fr> 192/
Destruction de l'environnement

L'initialisation de l'environnement MPI rserve un


certain nombre de ressources.
Une fois que l'on a fini dappeler les oprations
MPI, il faut librer ces ressources. On fait appel
la fonction MPI_Finalize.
#include <mpi.h>
int MPI_Finalize()
Aprs l'appel cette fonction, l'on ne doit plus
appeler d'autres fonctions MPI.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 193/
Les communicateurs

Les processus MPI peuvent tre regroup dans


des ensembles appels communicateur.
L'une des tche que ralise MPI_Init est de dfinir
le communicateur qui contient tous les processus
qui sont dmarrs.
Ce communicateur est appel
MPI_COMM_WORLD.
Les communicateurs sont du type MPI_Comm.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 194/


Les communicateurs

Il est possible de connatre le nombre de


processus dans un communicateur.
#include <mpi.h>
int MPI_Comm_size(MPI_Comm comm, int *size)
Le le nombre de processus sera gard dans size.
L'on peut aussi connatre le rang d'un processus
dans un communicateur.
#include <mpi.h>
int MPI_Comm_rank(MPI_Comm comm, int *rank)
Le rang est stock
2014 - 2015
dans la variable rank.
Vincent Douwe <douwevincent@yahoo.fr> 195/
La communication

MPI offre divers mcanismes de communication


entre les processus.
Il existe des primitives de communication
individuelle et des primitives de communication
collective.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 196/


Envoi d'un message
L'envoi d'un message un processus est ralis
grce la fonction MPI_Send.
#include <mpi.h>
int MPI_Send(void *buf, int count, MPI_Datatype datatype, int
dest, int tag, MPI_Comm comm)
Cette fonction permet d'envoyer le message
point par buf au processus dont le numro est
dest dans le communicateur comm.
L'on souhaite envoyer count valeurs de type
datatype. Le tag permet d'identifier un message
parmi
2014 - 2015 les messages envoys
Vincent Douwe par le processus. 197/
<douwevincent@yahoo.fr>
La rception des messages
La rception des messages est ralise grce la
fonction MPI_Recv.
#include <mpi.h>
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int
source, int tag, MPI_Comm comm, MPI_Status *status)
Elle permet de recevoir un message envoy par le
processus dont le numro est source dans le
communicateur comm et le tag est tag.
Le message qui contient count valeur de type datatype
sera stock l'adresse buf.
status contient des informations sur le statut du
message.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 198/
La rception d'un message

Pour qu'un processus reoive un message il faut :


Si l'on utilise le mme communicateur
Le tag d'envoi correspond au tag de rception
Les destinations et sources concident.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 199/


Les valeurs gnriques

Pour recevoir un message, il faut connatre le


processus qui envoie le message et le tag utilis
lors de l'envoi.
Il existe des situations o l'on veut recevoir un
message de n'importe quel processus avec
n'importe quel tag. Pour cela, nous allons utiliser
certaines valeurs gnriques.
MPI_ANY_SOURCE dsigne n'importe quelle
source
MPI_ANY_TAG Vincent
2014 - 2015 dsigne n'importe quel tag.
Douwe <douwevincent@yahoo.fr> 200/
Le statut d'un message

En utilisant les sources et tags gnriques, un


rcepteur peut ne pas savoir d'o provient un
message.
Le statut du message est la pour lui donner les
informations suivantes :
Lmetteur du message status.MPI_SOURCE
Le tag du message status.MPI_TAG
La quantit de donnes transmises grce la
mthode MPI_Get_count
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 201/
Le statut d'un message

#include <mpi.h>
int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int
*count)
datatype indique le type de la donnes
status indique le statut du message de reception
Si tout se passe bien, la taille du message est
stocke dans count.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 202/


Les types de donnes
Type MPI Type C
MPI_CHAR signed char
MPI_SHORT signed short int
MPI_INT signed int
MPI_LONG signed long int
MPI_LONG_LONG signed long long int
MPI_UNSIGNED_CHAR unsigned char
MPI_UNSIGNED_SHORT unsigned short int
MPI_UNSIGNED unsigned int
MPI_UNSIGNED_LONG unsigned long int
MPI_FLOAT float
MPI_DOUBLE double
MPI_LONG_DOUBLE long double
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 203/
MPI_BYTE
Exemple la mthode du trapze

L'on veut calculer la surface d'un rgion (intgrale


d'une fonction) l'aide de la mthode des
trapzes. Pour cela, l'on va diviser la surface
totale en de petites surfaces que l'on va assimiler
des trapzes.

0 a b

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 204/


Exemple la mthode du trapze

1 +1
. = .
=0

= +
avec


Si est petit, alors

+1 1 +
.
2

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 205/


Exemple la mthode du trapze

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 206/


La gestion des entres / sorties

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 207/


La communication collective

Les fonctions MPI_Send et MPI_Recv permettent


deux processus de communiquer. Que ce passe
t il lorsqu'il faut que plusieurs processus
communiquent ?
L'on peut faire appel aux fonction MPI_Send et
MPI_Recv plusieurs fois.
MPI fournit des abstractions de haut niveau qui
permettent des ensembles de processus
communiquer.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 208/
MPI_Reduce
Il arrive souvent que l'on ait besoin de faire une rduction. La
fonction MPI_Reduce est utilise pour raliser la rduction.
#include <mpi.h>
int MPI_Reduce(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)
sendbuf dsigne l'adresse de la donne sur laquelle faire la
rduction.
datatype indique le type de la donne
count indique le nombre de valeurs dans sendbuf.
op est l'opration de rduction
root indique le numro du processus qui fait la rduction dans le
communicateur.
recvbuf
2014 - 2015 indique l'endroit oDouwe
Vincent sera stock le rsultat
<douwevincent@yahoo.fr> 209/
MPI_Reduce
Opration Signification
MPI_MAX Maximum
MPI_MIN Minimum
MPI_SUM Somme
MPI_PROD Produit
MPI_LAND Le ET logique
MPI_BAND Le ET bit bit
MPI_LOR Le OU logique
MPI_BOR Le OU bit bit
MPI_LXOR Le XOR logique
MPI_BXOR Le XOR bit bit
MPI_MAXLOC Le maximum et sa position
MPI_MINLOC Le minimum et sa position
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 210/
MPI_Allreduce

Il arrive souvent que l'on a besoin de faire une rduction et de


renvoyer le rsultat tous les processus. La fonction
MPI_Allreduce ralise cette opration.
#include <mpi.h>
int MPI_Allreduce(void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
Les paramtres de cette fonction sont identiques aux paramtres
de la fonction MPI_Reduce.
Le rsultat de la rduction sera stock dans la variable recvbuf de
chaque processus.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 211/


La diffusion

Il arrive que l'on a besoin de diffuser un message tous les


processus. Au lieu de procder multiples appels des fonctions
MPI_Send et MPI_Recv, l'on peut utiliser MPI_Bcast.
#include <mpi.h>
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int
root, MPI_Comm comm)
Le processus qui a le rang root dans le communicateur comm
envoie le message point par buffer tous les autres processus du
groupe.
Le contenu de la variable buffer du processus root est transmise
tous les autres processus.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 212/


La fonction scatter

Il arrive trs souvent que l'on veuilles partager une donnes tous
les processus d'un groupe. On utilise pour cela la fonction
MPI_Scatter.
#include <mpi.h>
int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int
root, MPI_Comm comm)
Le processus de rang root dans le communicateur comm partage
la donne pointe par sendbuf aux autres processus du groupe.
Chaque processus va recevoir les donnes dans la variable
pointe par recvbuf.
L'on envoie sendcount valeurs chaque processus.
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 213/
La fonction gather

Il arrive aussi souvent que l'on ait besoin de rcuprer un


ensemble de valeurs des diffrents processus. Pour cela, on utilise
la fonction MPI_Gather. C'est un peu l'inverse de MPI_Scatter
#include <mpi.h>
int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int
root, MPI_Comm comm)
Le processus de rang root dans le communicateur comm reoit les
valeurs des diffrents processus et les stocke partir de recvbuf.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 214/


La fonction Allgather

Il arrive que tout le monde a besoin des donnes de tous le


monde. Pour cela, on utilise la fonction MPI_Allgather.
#include <mpi.h>
int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype
sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype,
MPI_Comm comm)
Elle permet tout le monde de partager les donnes pointes par
sendbuf avec les autres processus du groupe de communication.
Cette mthode fonctionne comme si tous les processus
excutaient MPI_Gather avec des root allant de 0 n 1.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 215/


Les appels non bloquants

Les appels aux fonctions MPI_Send et MPI_Recv sont


gnralement bloquant. L'on va atteindre l'excution de cette
fonction avant de continuer.
Il existe des variantes non bloquantes
#include <mpi.h>
int MPI_Isend(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)
Les paramtres sont les mmes que pour les variantes non
bloquantes l'exception du paramtre request qui donne les
informations
2014 - 2015 sur la requte.
Vincent Douwe <douwevincent@yahoo.fr> 216/
Les types drivs

Il est souvent ncessaire de transmettre plusieurs


donnes d'autres processus.
La dmarche standard consiste faire appel aux
oprations MPI_Send et MPI_Recv pour chaque
valeur que l'on veut transmettre.
Cette approche peut ne pas tre efficiente car elle
peut impliquer l'tablissement d'une connexion
plusieurs fois.
MPI offre la possibilit de crer des types composs
et d'utiliser ces types lors des oprations d'envoi et
rception
2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 217/
Les types drivs

La fonction gnrique qui permet de crer de nouveaux types est


MPI_Type_create_struct.
#include <mpi.h>
int MPI_Type_create_struct(int count, int array_of_blocklengths[],
MPI_Aint array_of_displacements[], MPI_Datatype
array_of_types[],MPI_Datatype *newtype)
Elle permet de crer un nouveau type compos qui a count
composante.
Pour chaque composante, il faut spcifier le nombre de blocs
occups, les dplacements par rapport l'origine et le type.
Le nouveau type est dans la variable pointe par newtype.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 218/


Les types drivs

Pour utiliser MPI_Type_struct_create, l'on doit avoir les


diffrents dplacements par rapport l'origine. La fonction
MPI_Get_address permet de renvoyer l'adresse d'une zone
mmoire.
#include <mpi.h>
int MPI_Get_address(void *location, MPI_Aint *address)

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 219/


Les types drivs

Supposons que l'on dcide envoyer deux doubles


et un int aux autres processus.
struct data{
double min ;
double max ;
int nombre ;
};
L'on peut construire un type driv pour une
variable
2014 - 2015 de ce type.
Vincent Douwe <douwevincent@yahoo.fr> 220/
Les types drivs
void build_Type(struct data data, MPI_Datatype *type){
int blocklengths[3] = {1,1,1} ;
MPI_Datatype types[3] = {MPI_DOUBLE, MPI_DOUBLE, MPI_INT} ;
MPI_Aint min_address, max_address, nombre_address ;
MPI_Aint deplacements[3] = {0} ;
MPI_Get_address(&data.min, &min_address) ;
MPI_Get_address(&data.max, &max_address) ;
MPI_Get_address(&data.nombre, &min_nombre) ;
deplacements[1] = max_address ;
deplacements[2] = nombre_address ;
MPI_Type_create_struct(3,blocklengths, deplacements, types, type) ;
MPI_Type_commit(type) ;
}2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 221/
Les types drivs

L'utilisation de MPI_Type_struct_create est assez gnrique. Il


existe des situations o l'on peut facilement dduire les diffrents
paramtres de cette fonction. Lorsque les donnes que l'on veut
transmettre sont des tableaux, il est judicieux d'utiliser la fonction
MPI_Type_contiguous.
#include <mpi.h>
int MPI_Type_contiguous(int count, MPI_Datatype oldtype,
MPI_Datatype *newtype)
Elle permet de crer un nouveau type pour count lments de
mme type.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 222/


Les types drivs

Il arrive souvent que l'on ne veuilles pas envoyer tout le tableau


mais seulement un ensemble d'lments qui sont quidistants. La
fonction MPI_Type_vector permet de crer des types dans ces
circonstances.
#include <mpi.h>
int MPI_Type_vector(int count, int blocklength, int stride,
MPI_Datatype oldtype, MPI_Datatype *newtype)
Les lments ont le mme type oldtype. Count dsigne le nombre
de blocs. Chaque bloc contient blocklength lments et les blocs
sont spars de stride lments.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 223/


Les types drivs

La fonction MPI_Type_indexed permet de crer un nouveau type


pour les lments dont les blocs sont dex index bien dfini.
#include <mpi.h>
int MPI_Type_indexed(int count, int *array_of_blocklengths, int
*array_of_displacements, MPI_Datatype oldtype, MPI_Datatype
*newtype)
count dsigne le nombre de blocs
array_of_blocklengths dsigne le nombre d'lments par blocs
array_of_displacements dsigne les dplacements de chaque bloc
(qui est un multiple de la taille de l'ancien type).

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 224/


Les types drivs

Il arrive souvent que l'on ait envie d'avoir les lments d'un type
donne comme des lments contigus en mmoire. La fonction
MPI_Pack ralise cette opration.
#include <mpi.h>
int MPI_Pack(void *inbuf, int incount, MPI_Datatype datatype, void
*outbuf, int outsize, int *position, MPI_Comm comm)
inbuf dsigne o sont les donnes
incount dsigne le nombre d'lments
outbuf dsigne o seront les donnes
outsize dsigne la taille de outbuf
comm
2014 - 2015
est le communicateur utiliser.
Vincent Douwe <douwevincent@yahoo.fr> 225/
Les types drivs
int position, i, j, a[2];
char buff[1000];
....
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
if (myrank == 0){
position = 0;
MPI_Pack(&i, 1, MPI_INT, buff, 1000, &position,
MPI_COMM_WORLD);
MPI_Pack(&j, 1, MPI_INT, buff, 1000, &position,
MPI_COMM_WORLD);
MPI_Send( buff, position, MPI_PACKED, 1, 0,
MPI_COMM_WORLD);
} else /* RECEIVER CODE */
2014 - MPI_Recv(
2015 a, 2, MPI_INT, 0,<douwevincent@yahoo.fr>
Vincent Douwe 0, MPI_COMM_WORLD) 226/
Les types drivs

La fonction MPI_Unpack permet de des-empaqueter les donnes


d'une type donnes dans une zone contigu de la mmoire.
#include <mpi.h>
int MPI_Unpack(void *inbuf, int insize, int *position, void *outbuf, int
outcount, MPI_Datatype datatype, MPI_Comm comm)
Les donnes pointes par inbuf sont des-empaquets dans outbuf
en utilisant le communicateur comm.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 227/


Compilation et excution

Pour utiliser MPI, il faut l'installer. Il existe


plusieurs implmentations :
OpenMPI
MPICH
Pour ce cours, nous allons particulirement utiliser
openmpi.
sudo apt-get install openmpi-dev

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 228/


Excution et compilation

Les fonctions MPI sont disponibles dans la


bibliothque mpi.h
L'on compile les programmes MPI avec mpicc qui
est wrapper au dessus du compilateur c (gcc).
Pour l'excution, l'on fait appel mpirun (ou
mpiexec)
L'option -np permet de spcifier le nombre de
processus crer.

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 229/


Le programme HelloWorld

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 230/


La mthode des trapzes

2014 - 2015 Vincent Douwe <douwevincent@yahoo.fr> 231/