Vous êtes sur la page 1sur 4

Master CHPS -

Environnements et
Modèles de
Programmation Parallèle.
(CHPS0832 2021-2022)

TP1
Programmation par tâches
OpenMP
adrien.roussel@cea.fr
cedric.chevalier@cea.fr

Les objectifs de ce TD sont :


— Mise en pratique du modèle de programmation par tâches,
— Manipulation avec OpenMP.

I Calcul de π par Monte Carlo


1 Définition de la méthode
Le calcul de π est un problème fréquemment étudié pour l’apprentissage du
parallélisme. L’une des méthodes les plus courantes est la méthode approchée de
type Monte Carlo.
On construit un carré de côté c = 1 et de centre O. En ce même centre, nous
traçons un cercle de rayon r = 1. Pour comprendre la procédure d’approximation
de π, nous avons besoin de connaitre l’aire de ce cercle via la formule A = πr2 .
Dans notre cas, nous obtenons A = π.
y y
× × × × × ××
×× × ××
×
××××
× ×× ××
×× ×
× ×
××
×× ×× ×
××
×
× × ××
××
× × ×× ×
× × ×
××
×× × × ×
× ×
x ××
××
××× ××
×
× × ×
×××
××××
× × ×× ×× ××
××
× ××
×× ××
××
××× ×× ×
×× ×
× × ×××

×
××
× ×× ×
× ×× ×× ××
×
× × ××××
××× ×××× x
× ××

Figure 1 – Distribution aléatoire de


points dans un carré unitaire. Figure 2 – Quart de cercle servant
de cible pour le calcul de π

Figure 3 – Calcul d’approximation de π par la méthode de Monte Carlo

La méthode de Monte Carlo consiste à lancer un nombre infini de fléchettes


manière aléatoire en direction de la cible (cf Figure 2). Le nombre de fléchettes P
se trouvant dans le cercle tend donc vers l’aire du quart de cercle, soit π/4.
En pratique, P se calcule également de la manière suivante :
nb fléchettes dans le cercle
P = .
nb total de fléchettes

1
On se retrouve donc avec l’approximation de π telle que :
nb fléchettes dans le cercle
π ≃4× .
nb total de fléchettes
Pour avoir l’approximation de π, on compte alors le nombre de fléchettes se
trouvant dans le quart de cercle de la cible. Un point a de coordonnées (x, y)
se trouve à l’intérieur du quart de cercle si la distance qui le sépare de l’origine
O(0, 0) est inférieure ou égale à 1, soit x2 + y 2 ≤ 1 (cf. théorème de Pythagore).

2 Exercice
Q.1: A l’aide de la description du problème dans la section précédente, du
programme séquentiel présent dans le fichier Pi_MT/pi_seq.c, écrire un pro-
gramme parallèle à base de tâches OpenMP 3.0 où chaque thread lance un nombre
N _T ASKS_P ER_T HREAD de tâches exécutant chacune
N _T RIALS_P ER_T ASK.
NB : On peut aussi imaginer que N _T RIALS_P ER_T ASK est un nombre
aléatoire servant à créer du déséquilibre entre thread.

II Sparse Matrix Vector kernel (SpMV)


A l’instar des matrices denses, une matrice creuse est une matrice contenant
un nombre important de valeurs nulles. Pour limiter l’empreinte mémoire liée
au stockage de la matrice, seules les valeurs non nulles sont stockées. Différents
formats existent pour arriver à ce résultat.
Dans le cadre de cet exercice, nous nous focalisons sur le format Compressed
Sparse Row (CSR). Considérons une matrice creuse de taille N × N , elle est alors
stockée sous forme de trois vecteurs :
— values : stocke l’ensemble des valeurs non nulles ligne par ligne de la matrice,
de taille NNZ.
— JA, un tableau d’entiers qui enregistre l’indice de colonne de chaque valeur,
il est de taille NNZ.
— IA, un tableau d’entiers qui contient les pointeurs vers le début de chaque
ligne dans les tableaux values et JA. La taille de ce vecteur est de N + 1
éléments.
La signature du format CSR est donnée dans la portion de code suivante :
 
1 typedef struct
2 {
3 int m_nrows , m_nnz ;
4 double * m_values ;
5 int * m_ja ;
6 int * m_ia ;
7 } CSRMatrix_t ;
 

Exemple : Prenons en exemple la matrice suivante,


 
a 0 0 b
0 c 0 0
Am,n =
 
0 d e 0

f 0 g h

2
aura la représentation suivante :
h i
m_values = a b c d e f g h

h i
m_ja = 0 3 1 1 2 0 2 3

h i
m_ia = 0 2 3 5 8
Astuce : pour trouver le nombre d’éléments que contient une ligne, il suffit de
faire l’opération suivante : nb_rows[i] = m_ia[i + 1] − m_ia[i].

Le code présent dans le répertoire SpMV contient les fonctions d’allocation et


d’initialisation d’une matrice creuse au format CSR. Complétez les fichiers corres-
pondants pour répondre aux questions.

Q.2: Le fichier CSRMatrix.c contient le squelette de la fonction mult_CSR(CSR_Matrix_t*,


double const*, double) qui effectue le produit entre une matrice creuse et un
vecteur. Remplissez cette fonction avec l’opération séquentielle correspondante.

Q.3: Proposez une parallélisation par tâches de l’algorithme précédent en uti-


lisant la norme OpenMP 4.0 et en faisant en sorte que chaque tâche effectue un
SpMV sur un sous-ensemble de lignes de la matrice.

Q.4: Quels sont les avantages apportent la parallélisation par tâches d’un tel
algorithme ?

III Parcours d’un arbre – Depth First Search method


Le fichier Tree-traversal/tree-traverse.c initialise un arbre binaire aléa-
toire. Le but de cet exercice est de calculer la profondeur de l’arbre à l’aide d’un
algorithme de type Depth First Search, c’est à dire de parcourir l’arbre en allant
le plus en profondeur possible, et de faire du backtrack une fois que l’on a atteint
une feuille.

Q.5: Remplissez la fonction int inorderTraverse_Task(struct node*) qui


permet de calculer la profondeur d’un arbre en séquentiel.

Q.6: Paralléliser la fonction précédente en utilisant les tâches OpenMP

Q.7: A l’aide d’une clause sur la génération des tâches explicites, limitez la
génération de tâches pour s’arrêter à une profondeur maximale de 5 (par exemple).
Il existe deux manières possibles de faire.

Q.8: Si vous en avez mis, retirez tous les points de synchronisation type taskwait
et utilisez la directive taskgroup pour synchroniser implicitement vos tâches et
leurs descendantes.

3
IV Stencil
Cette partie se concentre sur un simple code appelé stencil_seq.c qui créé
une maille 1D remplie avec des valeurs aléatoires. A travers plusieurs itérations, ce
code va appliquer une sorte de traitement de flou sur chaque côté de la maille, et
ensuite une opération simple sur chacun des cellues. L’objectif est de paralléliser
ce code avec des tâches OpenMP avec et sans dépendances.

Q.9: Compilez le fichier à l’aide du Makefile fourni. Exécuter ce code requière


2 arguments :
1. La taille de la maille (i.e. le nombre de cellules),
2. La graine pour la génération de nombre pseudo aléatoires,
Exemple :
$ ./stencil_seq
Usage: ./stencil_seq N seed
$ ./stencil_seq 100 10

Q.10: Changez le code source pour ajouter du parallélisme de tâches avec OpenMP
(avec et sans dépendances). Dans ce but, il est possible de créer une région pa-
rallel avec une directive single à l’intérieur. Cette directive exécutera la boucle
principle. Par conséquent, les tâches peuvent être créées facilement à l’intérieur de
cette directive.
Attention à l’ordonnancement : il est nécessaire de mettre quelques points de syn-
chronisations (taskwait).

Vous aimerez peut-être aussi