Transformation de programmes

Transcription

Transformation de programmes
TELECOM SUD PARIS
Transformation de programmes
Génération d'un programme multi-GPU
MPI+HMPP à partir d'un programme GPU
avec des directives HMPP
Thean Rémy – Marechal Victor
Encadrant : Frédérique Silber-Chaussumier
21/01/2012
Sommaire
Introduction ................................................................. 3
1 – Contexte du projet ................................................................... 4
a) Objectifs du projet ............................................................................................ 4
b) STEP et son parser OpenMP ............................................................................. 4
c) CAPS HMPP ....................................................................................................... 8
d) HMPP et STEP ................................................................................................... 9
2 – Travaux réalisés .................................................... 10
a) Ecriture d’un parser OpenMP ......................................................................... 10
1) Partie Flex ....................................................................................................................... 10
2) Partie Bison .................................................................................................................... 11
3) Exemple d’exécution du parser OpenMP ...................................................................... 12
b) Etude et prise en main de HMPP ..................................................................... 13
c) Parser HMPP .................................................................................................. 14
1) Ecriture du parser ........................................................................................................... 14
2) Exemple d’exécution du parser HMPP ........................................................................... 15
c) Préparation à l’intégration des deux parsers ................................................... 16
3 - Bilan du projet ........................................................ 19
a) Rendu du projet ............................................................................................. 19
a) Difficultés rencontrés durant le projet ............................................................. 19
a) Temps de travail ............................................................................................. 19
Conclusion .................................................................. 20
2
Introduction
Au sein de Telecom Sudparis, un outil de transformation de programme appelé STEP a
été développé. L’objectif principal de cet outil est de réaliser une parallélisation semiautomatique d’un code source afin de faciliter la parallélisation et ainsi réduire le temps de
calcul d’un programme C ou Fortran. Pour le moment, cet outil peut à partir d’un code C ou
Fortran contenant des instructions OpenMP transformer ce code source en un nouveau code
source parallélisé de manière hybride, c'est-à-dire, contenant à la fois des instructions
OpenMP mais aussi des instructions MPI.
Maintenant, l’équipe en charge de STEP souhaite étendre leur outil pour permettre le
partage des calculs sur la GPU de plusieurs machines. Pour cela, ils font fait le choix d’utiliser
CAPS HMPP, un programme permettant de réaliser un code s’exécutant sur la GPU à partir
d’un code dont on a ajouté des instructions HMPP. C’est là qu’intervient notre projet de fin
d’étude, notre rôle est d’intégrer dans STEP la possibilité de transformer un programme HMPP.
Dans ce document, afin d’expliciter le déroulement de notre projet, nous allons tout
d’abord aborder le contexte et les objectifs du projet, pour nous concentrer sur le travail
réalisé et enfin terminer par un bilan concernant le projet.
3
1 – Contexte du projet
a) Objectifs du projet
L’objectif principal du projet est de pouvoir intégrer dans STEP, une solution similaire à
celle pour OpenMP.
Pour cela, notre projet a été divisé en plusieurs phases :





Etude de STEP, sa structure et son fonctionnement.
Etude et prise en main de HMPP.
Ecriture d’un parser OpenMP afin de remplacer celui de STEP.
Ecriture d’un parser HMPP.
Intégration de ces deux parser dans STEP.
b) STEP et son parser OpenMP
STEP ou est un outil de transformation source à source inscrit dans un projet des écoles
des Mines appelé PIPS. STEP utilisent les modules de PIPS pour ses analyses de structures et
les transformations qu’il réalise sur un code source.
Le principal objectif de STEP de l’outil STEP est de faciliter et accélérer la parallelisation, pour
cela, son rôle est de transformer un code source C ou Fortran écrit avec des instructions
OpenMP en un code source dans le même langage avec des instructions OpenMP + MPI.
Les transformations de codes que réalise STEP a pour but de modifier la manière dont est
exécuté le programme issue d’un code source. Ainsi, un code source produit par STEP, divisera
son calcul qui doit être réalisé en parallèle sur une machine en un calcul en parallèle sur
plusieurs machines. La partie du calcul divisé sur plusieurs machines comprend uniquement les
parties du code entourées pas les instructions parallèles. Les autres opérations non parallèles
sont réalisées par toutes les machines. MPI intervient dans l’objectif d’obtenir un résultat
semblable à une exécution normale du code source, pour cela, après la région parallèle, MPI
est utilisé afin de mettre les différentes variables à jour chaque région parallèle du code. Au
final, chaque machine se retrouvera avec le même résultat qu’une exécution normale du code
aurait donné, cependant, le temps d’exécution du code est réduit.
Le schéma (figure 1) suivant explicite bien la transformation que subit le code source au niveau
de son exécution après avoir été transformé par STEP.
4
Figure 1 – Modèle d’exécution de STEP
Parlons maintenant plus précisément du fonctionnement de STEP. STEP, avant son travail de
transformation, réalise tout d’abord une représentation du code en une représentation dite
intermédiaire (RI). STEP travaillera ensuite sur cette représentation intermédiaire pour
modifier réaliser sa transformation. La transformation que réalise STEP peut se diviser en 3
grandes étapes



Outlining : détecte les sections parallèles et change la structure du code source. Cela a
pour but de hiérarchiser le code.
Analyse des régions : détermine les données à être échangées via MPI ;
Génération du code MPI
Dans le cadre de notre projet, nous nous intéressons plutôt à l’étape consistant de faire une
représentation du code en une représentation intermédiaire (RI). En effet, le parser OpenMP
est appelé afin de pouvoir réaliser cette représentation intermédiaire. Concentrons nous donc
plus sur le détail du parser OpenMP de STEP.
Le parser STEP est un parser écrit totalement en langage Flex. Il est contenu dans un fichier
step_omp.l contenu dans la bibliothèque de STEP. Ce parser est le même pour le langage C et
pour le langage Fortran.
Le rôle du parser OpenMP est de réaliser une analyse d’un code source en C ou Fortran
contenant des instructions (statement) OpenMP/STEP, et selon l’instruction (statement)
détectée fait appel à des fonctions définis dans le même fichier.
A l’entrée du parser, on lui entre une instruction détectés préalablement par STEP grâce à la
fonction pragma_omp_handle().
Le parser détecte ensuite la structure de l’instruction grâce à l’utilisation de machines à états
dés la détection d’un certain mot clé.
5
Les mots clés détectés par l’analyseur peuvent se diviser en 3 grandes catégories + 2 catégories
permettant la gestion des clauses OpenMP.
Ces 3 grandes catégories sont :



Les directives STEP (indique le type de transformation désirée)
Les directives OpenMP
Les clauses OpenMP
STEP ne fait pas la détection de toutes les instructions possible d’OpenMP, seule certaines sont
utiles à STEP pour son travail de transformation. Ainsi, après étude du parser, nous avons pu
déterminer quels étaient les mots que détectait STEP. Nous les avons regroupés dans le
tableau suivant :
Transformation STEP
step
transform_mpi
transform_nompi
transform_hybrid
transform_ignore
Directive openMP
Clauses OpenMP
omp
nowait
parallel
private
do/for
shared
parallel for
reduction
end
barrier
master
single
Figure 2 – Tableau des mots détectés par le parser de STEP
Les deux dernières catégories de mots clés permettent comme dit au dessus d’aider à la
representation des clauses openMP. Ces catégories consistent en :


La gestion d’une liste de variable pour les clauses private , shared et reduction.
La gestion des opérateurs pour la clause reduction.
Ainsi, lorsqu’une clause de type reduction, private ou shared est détecté par l’analyseur, celuici construit une liste avec l’opérateur (si on se trouve dans une réduction), et les variables
passées en paramètre de la clause.
Par l’utilisation des machines à état, STEP fait aussi la detection de la structure des instructions
qui lui sont passé en paramètre. Après l’étude de ces machines à état, on peut se représenter
la structure possible des instructions de la manière suivante :

Pour la partie concernant les directives STEP
transform_mpi
transform_nompi
step
transform_hybrid
transform_ignore
6

Pour la partie concernant les directives et les clauses OpenMP
private
parallel
shared
reduction
private
do/for
reduction
nowait
private
omp
parallel for
reduction
single
master
barrier
private
parallel
do/for
nowait
parallel for
end
single
nowait
master
barrier
Légende :
Mots ouvrant une machine à état
Mots n’ouvrant pas de machine à état
Figure 3 - Representation de la structure des machines à Etats
7
Comprendre cette représentation de la structure des instructions analysées par le parser est
important dans notre projet pour l’écriture de notre parser OpenMP en flex/bison.
c) CAPS HMPP
HMPP (pour Hybrid Multicore Parallel Programming) est un SDK créé par la société
CAPS. Son but est de permettre le développement d’applications GPU.
HMPP permet de définir des régions de code qui seront exécutées sur un GPU. Ces régions
sont appelées codelet et sont écrites en introduisant dans le code des directives HMPP. On
ajoute avant le prototype de la fonction une directive HMPP permettant de définir les
arguments en entré ou sortie et différentes options (CUDA, OpenCL…). Cette fonction sera
ensuite appelée dans le programme en rajoutant la directive HMPP callsite avant de faire
l’appel de la fonction en elle-même.
Figure 4 - Exemple d’utilisation HMPP avec definition du codelet et appel dans le main
Les directives HMPP permettent aussi de guider en détail la façon dont le GPU sera utilisé.
Il est ainsi possible de définir le moment ou les données seront transférées vers le GPU et la
nature du codelet (asynchrone, synchrone…). HMPP est capable de réaliser la fonction sur GPU
de manière automatique sur un codelet mais dans certains cas il peut être préférable de
donner des indications. Il existe ainsi des directives HMPPCG qui permettent de définir les
détails de la mise en place de la fonction sur le GPU. On peut préciser les variables partagées
ou privées, placer des barrier à la manière d’OpenMP, indiquer le nombre de cellules utilisées
ou réaliser des opérations sur les boucles.
Figure 5 – Ici la première boucle for est parallélisé alors que la seconde ne l’est pas. Sans les
directives HMPPCG les deux boucles auraient étés parallélisées.
8
d) HMPP et STEP
La finalité de ce projet est d’intégrer un parser HMPP à l’outil STEP. Celui-ci sera écrit en
Flex/Bison.
Intégrer un analyseur HMPP à STEP pourrait permettre de détecter les directives HMPP
dans un code et de rajouter des directives MPI pour permettre d’utiliser les GPU de plusieurs
hôtes en parallèle pour exécuter un programme.
Programme
principal
Appel du codelet
MPI sur 4 hôtes
GPU 1
GPU 2
GPU 3
GPU 4
Fin du codelet
Programme
principal
Figure 6 – Exemple d’exécution d’un programme HMPP+MPI
Sur la figure ci-dessus le programme est exécuté normalement jusqu’à l’appel du
codelet. Une fois à l’intérieur, une fonction MPI est appelée ce qui permet de repartir la boucle
du codelet sur plusieurs hôtes. Nous obtenons ainsi l’exécution de l’application reparties sur
les GPU de 4 hôtes.
Un tel outil permettrait de générer des programmes multi-hôtes multi-GPU automatiquement.
9
2 – Travaux réalisés
a) Ecriture du parser OpenMP
Le premier travail qui nous a été confié fut de produire un parser OpenMP qui aura la
possibilité de remplacer celui déjà présent dans STEP. Au départ, nous étions un peu parti à
l’aveugle, c'est-à-dire que nous avions écrit une première version du parser qui pouvait
détecter un maximum de mot clé d’OpenMP. Cependant, après avoir étudié de plus près le
parser OpenMP de STEP, nous avons réalisé des modifications et notre parser maintenant est
plus proche du parser de STEP. Ainsi, nous avons donc codé une seconde version du parser
OpenMP, plus proche que celui de STEP avec les spécifications suivantes :




Utilisation de flex ET de bison.
Pouvoir reconnaitre les mêmes instructions que STEP.
Utilisation de moins de machine à état que possible et laisser toute la détection de la
structure d’une instruction à Bison.
Si une instruction est de type non reconnus au départ par STEP, alors cette instruction
est recopiée.
Spécifions plus précisément comment ont été construit notre code flex et bison.
1) Partie FLEX
La partie flex du parser a pour rôle de faire une analyse syntaxique d’une chaine de
caractère placé en entrée. Afin de le construire, nous nous sommes beaucoup inspirés des
mots clés détectés par le parser de STEP et nous les avons juste repris dans la partie flex (voir
le tableau dans la partie 1-b).
Cependant, contrairement au parser Flex, nous avons définis ce qu’était qu’une variable, une
chaine de caractère composé de lettre majuscule ou minuscule et de chiffres. Cette définition
de variable nous sera utile dans le bison lorsque nous souhaiterons définir les variables en
arguments des clauses share, private et réduction.
D’autre part, nous utilisons que deux machines à état et laissons la detection de la structure de
l’instruction à Bison. Ces machines à état sont commencées à la détection du mot clé
« omp » ou « step », cela a pour but de reconnaitre juste les directives openMP ou STEP et
d’empêcher des mauvaises détections pour certains mots clés utilisés dans d’autres contextes
(exemple : FOR).
Ces machines a état nous assurent donc que les mots qui suivent vont être liés à une directive
openMP ou STEP, en effet, les directives openMP commencent toutes par « !$ omp » dans le
cadre du fortran et « #pragma omp » dans le cadre du C et il en ai de même pour step
( #pragma step et !$step ).
10
Ces machines à état se ferment lorsque l’on détecte un « \n », en effet, STEP ferme la plupart
de ses machines à états à la détection de ce « \n ». Nous avons juste repris cela dans notre
flex et ainsi, nous ne faisons pas attention aux instructions openMP présent sur deux lignes.
2) Partie BISON
La partie bison du parser OpenMP que nous avons codé a pour rôle principal de faire
l’analyse de la structure de l’instruction qu’on lui rentre en paramètre. Comme pour la partie
flex, nous nous sommes grandement inspirés de STEP pour la construction du fichier bison. En
effet, nous avons utilisés les structures possibles des instructions analysées par STEP (voir
Figure3) et la syntaxe openMP pour construire les grammaires de notre bison.
Nous les avons décidés de séparer la structure d’un programme en 4 grands groupes distincts
(voir figure X). Trois de ses groupes sont tout d’abord les même que ceux définis lors de
l’analyse du parser openMP de STEP dans la partie 1, c'est-à-dire, les instructions STEP
(STEPSTATEMENT dans le fichier bison), les directives openMP (DIRECTIVES dans le fichier
bison) et enfin les clauses openMP (CLAUSES dans le fichier bison).
PROGRAM
:
| PROGRAM WORDCODE
| PROGRAM CLAUSES
| PROGRAM DIRECTIVES
| PROGRAM STEPSTATEMENT
| PROGRAM '\n'
;
Figure 7 – Structure d’un programme pour Bison
A cela s’ajoute une grammaire appelée WORDCODE qui permet dans le cas l’analyseur lexical
détecte un mot clé qui ne fait en rien partie d’une instruction de juste le recopier et de ne pas
le traiter. Cela concerne surtout les mots clés ouvrant les machines à états, « omp » et « step »,
et des symboles telles que « + » « , » …
Cette grammaire WORDCODE contient le moins de structure syntaxique que possible afin
d’éviter le maximum d’erreur de type décalage réduction que nous avions eu avant
l’implémentation des machines à état.
Nous avons ensuite défini une grammaire correspondant aux variables contenus dans les
clauses openMP shared, private et reduction, cela afin de pouvoir faire l’utilisation des listes
comme défini dans STEP. Celle-ci est définie de la manière suivante :
GRPVARIABLE
: GRPVARIABLE Symbole Variable
| Variable
;
Figure 8 - Définition des variables dans Bison
11
Cette définition permet l’utilisation des fonctions de STEP qui permettent la gestion des listes.
En effet, dans STEP, les variables passés en arguments d’une clause openMP tel que private ou
shared sont inclus dans une liste de variable utilisés lors de l’ajout de la clause dans la
Représentation Intermédiaire.
Afin de pouvoir tester notre parser OpenMP, nous avons placé une macro DEBUG qui si elle est
passé à 1 permet d’observer la détection des différentes directives, clauses que le parseur
rencontre en les remplaçant par « <nom directive/clause> ».
3) Exemple d’exécution du parser OpenMP
Voici un exemple d’exécution de notre parser openMP avec le mode DEBUG.
Comme dit auparavant, lorsqu’il rencontre une instruction connu le parser affiche un <Nom>
à la place (voir les mots en bleu). S’il rencontre une instruction inconnue, il la recopie sans y
faire attention (voir les bouts en rouge).
Code de base
Code après passage dans le parser
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
#include <stdlib.h>
#include <stdio.h>
#include <.omp h>
int main(void)
{
int i;
int sum=0;
#pragma omp parallel private (sum)
reduction(+:sum)
{
#pragma omp for
for (i=0;i<5;i++) {
sum += i;
}
#pragma omp task
{
sum +=i;
}
int main(void)
<Debut Block>
int i;
int sum=0;
#pragma <Parallel> <private> <reduction>
<Debut Block>
#pragma <For>
for (i=0;i<5;i++) <Debut Block>
sum += i;
<Fin Block>
#pragma omp task
<Debut Block>
sum +=i;
<Fin Block>
}
printf("%d", sum);
return 0;
}
<Fin Block>
printf("%d", sum);
return 0;
<Fin Block>
Figure 9 – Exemple d’execution du parser OpenMP
A cette étape du projet, le parser openMP ne fait que d’analyser les différentes instructions
openMP qu’on lui met en entrée. L’utilisation de cette analyse ne sera faite qu’un peu plus
tard, lorsque l’on essayera de faire l’intégration de ce parser openMP dans STEP.
12
b) Etude et prise en main de HMPP
Deux postes avec licence HMPP ont été mis à disposition pour pouvoir expérimenter le
SDK. Une documentation nous a aussi été fournie. Une série d’exemples labs était présent sur
les postes et ont permis de prendre en main HMPP en expérimentant directement sur des
parties de code.
Avant de réaliser le parser HMPP il était nécessaire d’identifier les fonctions qui seraient
utiles dans le cadre du projet multi-hôtes. Il a été définit que ces fonctions seraient des
directives HMPPCG. En effet l’appel de codelet se fait sur chaque hôte et ne nécessite pas de
traitement particulier. Avec les directives HMPPCG ont obtient un langage qui se rapproche
d’OpenMP.
Nous avons cherché une correspondance entre les directives OpenMP et HMPP pour
trouver un point d’approche semblable lors de l’intégration du parser à STEP. En effet si nous
avons des fonctions effectuant la même action sur du matériel différent (CPU pour OpenMP et
GPU pour HMPP) il est possible de la repartir sur plusieurs hôtes de manière semblable avec
MPI.
Nous sommes parvenus au tableau de correspondance suivant :
Directive OpenMP
Directive HMPP
omp parallel for
hmppcg parallel
hmppcg gridify
*** shared
*** global
*** private
*** private
*** reduction
*** reduce
omp barrier
hmppcg grid barrier
omp master
hmppcg noparallel
Figure 10 – Tableau de correspondance OpenMP-HMPP
13
c) Parser HMPP
1) Ecriture du parser
Le parser HMPP a été écrit en s’appuyant sur ce qui a été réalisé dans le parser OpenMP.
Son écriture a donc été relativement rapide, avec des noms de directives à remplacer.
Il permet de détecter les directives pertinentes dans le cadre d’une implémentation de
fonctions MPI ultérieurement.
Les directives suivantes ont étés choisies pour être intégrées dans le parser
private
parallel
global
reduce
private
gridify
hmppcg
global
reduce
noparallel
barrier
grid
unguarded
Figure 11 – Directives HMPP utilisées dans le parser
Parallel et Gridify fonctionnent de manière similaire a Parallel for pour OpenMP. Ces
directives permettent de définir la manière dont la boucle est parallélisée en précisant les
réductions ainsi que les variables partagées et privées.
NoParallel permet de préciser que la boucle sera exécutée sur le CPU et non le GPU.
Grid Barrier est similaire à la fonction Barrier d’OpenMP et permet de synchroniser tous les
threads actifs. Unguarded permet d’effectuer la fonction inverse.
14
On peut imaginer le scénario suivant :

Détection de parallel ou gridify : Répartition sur plusieurs hôtes de la boucle à venir.

Détection de noparallel : Arrêt du MPI, la boucle est réalisée sur le CPU d’un seul hôte.

Détection de barrier et unguarded : Similaire a OpenMP pour barrier.
On obtient ainsi un parser détectant un ensemble de fonctions a première vue limitée mais
pertinentes dans la finalité du projet.
2) Exemple d’exécution du parser HMPP
Codelet de base
void diffNormReduce(const int m, const int
n, const int spani, const int spanj, double
table[m][n], double tableOut[m][n], double
diffNorm[1])
{
int i,j;
double diffsum = 0.0;
/* Fill the data as specified */
#pragma hmppcg gridify, reduce (+:diffsum)
for (i=spani; i < m - spani; i++)
for (j=spanj; j < n - spanj; j++) {
double diff = tableOut[i][j] - table[i][j];
double diffmul = diff*diff;
diffsum += diffmul;
table[i][j] = tableOut[i][j];
}
Codelet après passage dans le parser
void diffNormReduce(const int m, const int
n, const int spani, const int spanj, double
table[m][n], double tableOut[m][n], double
diffNorm[1])
<Debut Block>
int i,j;
double diffsum = 0.0;
/* Fill the data as specified */
#pragma <Gridify> <reduce>
for (i=spani; i < m - spani; i++)
for (j=spanj; j < n - spanj; j++) <Debut
Block>
double diff = tableOut[i][j] - table[i][j];
double diffmul = diff*diff;
diffsum += diffmul;
table[i][j] = tableOut[i][j];
<Fin Block>
diffNorm[0] = diffsum;
}
diffNorm[0] = diffsum;
<Fin Block>
Figure 12 – Exemples d’exécution du parser HMPP
15
d) Préparation à l’intégration des deux parsers
Le but principal du projet était bien sur d’intégrer les deux parsers dans STEP. Cependant,
cette intégration n’est pas une tâche facile. En effet, la structure de STEP en fait que modifier
le modifier afin d’intégrer juste quelques fichiers ne se résume pas à juste ajouter les fichiers
et à modifier un makefile. Les dépendances entre les fichiers sont si importantes qu’il est
difficile de savoir où exactement sont appelés les fonctions du parser. Ainsi, avec le temps qu’il
restait au projet, nous avons décidé de faire une préparation à l’intégration en ajoutant les
prototypes des fonctions dont fait appel le parser OpenMP de STEP.
NOTRE PARSER
STEP
Au niveau tout d’abord du parser OpenMP nous avons rajouté des appels de fonctions au
niveau du fichier Bison tels qu’il a été réalisé au niveau de STEP. En voici un exemple :
{parallel_loop} {
yy_push_state(parallel_loop);
pips_debug(2,"begin state %s %d\n", yytext, YYSTATE);
directive_block_begin(STEP_PARALLEL_DO, yytext);
}
FOR
: Omp Parallel For
{ if (DEBUG)
printf("<Parallel for>");
directive_block_begin(STEP_PARALLEL_DO, "parallel for");}
Figure 13 – Exemple comparaison STEP et notre parser
D’autre part, afin de pouvoir tester l’appel de ces fonctions, nous avons réalisé des fausses
fonctions qui font juste un affichage indiquant que la fonction a été appelée. Seul une des
fonctions s’est inspirée de l’originale car elle est l’une des fonctions les plus appelé et elle n’est
pas trop dépendantes des structures et des fonctions hors du parser. Cette fonction est
directive_block_begin () qui est appelé dès qu’une instruction est repérée.
16
Voici un exemple d’exécution de ce nouveau code avec les nouvelles fausses fonctions. Nous
avons pris le même exemple que pour l’exemple de notre parser OpenMP.
Code de base
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
int main(void)
{
int i;
int sum=0;
#pragma omp parallel private (sum)
reduction(+:sum)
{
#pragma omp for
for (i=0;i<5;i++) {
sum += i;
}
#pragma omp task
{
sum +=i;
}
}
printf("%d", sum);
return 0;
}
Retour après passage dans le parser openMP
#include <stdlib.h>
#include <stdio.h>
#include <.omp h>
int main(void)
{
int i;
int sum=0;
#pragma <Parallel>
--appel de la fonction directive_block_begin avec le type = 0 et un
s=parallel---appel de la fonction add_step_directive---appel de la fonction reset_step_transform-<Début de la liste>
<Ajout de l'élément "sum" dans la liste>
--appel de la fonction init_current_list-<private>
--appel de la fonction add_clause_private---appel de la fonction reset_current_list-<Début de la liste>
<Ajout de l'élément "sum" dans la liste>
--appel de la fonction init_current_list-<reduction>
--appel de la fonction set_current_op---appel de la fonction add_clause_reduction---appel de la fonction reset_current_list---appel de la fonction reset_current_op-{
#pragma <For>
--appel de la fonction directive_block_begin avec le type = 1 et un s=for---appel de la fonction add_step_directive---appel de la fonction reset_step_transform-for (i=0;i<5;i++) {
sum += i;
}
#pragma omp task
{
sum +=i;
}
}
printf("%d", sum);
return 0;
}
Figure 14 – Exemple d’exécution du parser OpenMP après ajout des fausses fonctions.
17
L’intégration du parser HMPP s’est fait sur le modèle du parser OpenMP. Nous avons
rajouté de fausses fonctions qui permettent d’afficher des informations propres à l’action qui
serait effectuée.
Les fonctions de base n’étant pas écrites pour HMPP, les fonctions OpenMP ont étés
utilisées dans le parser HMPP pour tester l’intégration. Il est nécessaire d’écrire dans STEP des
fonctions propres à HMPP pour l’intégration finale.
L’exemple suivant permet de voir le résultat du parser sur un codelet :
Code de base
Retour après passage dans le parser openMP
void simpleJacobi(const int m, const int
n, const int spani, const int spanj,
double table[m][n], double
tableOut[m][n])
void simpleJacobi(const int m, const int n, const int spani, const
int spanj, double table[m][n], double tableOut[m][n])
<Debut Block>
int i,j,k;
#pragma <Parallel>
--appel de la fonction directive_block_begin avec le type = 0 et
un s=parallel---appel de la fonction add_step_directive---appel de la fonction reset_step_transform-,
<D�but de la liste>
<Ajout de l'�l�ment "i" dans la liste>
--appel de la fonction init_current_list-<private>
--appel de la fonction add_clause_private---appel de la fonction reset_current_list--
{
int i,j,k;
#pragma hmppcg parallel, private(i)
for (i=spani; i < m - spani; i++)
#pragma hmppcg noparallel
for (j=spanj; j < n - spanj; j++) {
double neighbor =cos(table[ispani][j]) +sin(table[i][j-spanj])
+sin(table[i][j+spanj])
+cos(table[i+spani][j]) ;
tableOut[i][j] = neighbor/3;
}
#pragma hmppcg grid barrier
}
for (i=spani; i < m - spani; i++)
#pragma <Noparallel>
for (j=spanj; j < n - spanj; j++) <Debut Block>
double neighbor =cos(table[i-spani][j]) +sin(table[i][j-spanj])
+sin(table[i][j+spanj]) +cos(table[i+spani][j]) ;
tableOut[i][j] = neighbor/3;
<Fin Block>
#pragma <Omp Grid Barrier>
--appel de la fonction directive_statement avec le type = 5 et un
s=barrier-<Fin Block>
Figure 15– Exemple d’exécution du parser HMPP après ajout des fausses fonctions.
18
3 – Bilan du projet
a) Rendu final du projet
Au terme de ce projet, voici les différents rendus du projet :





Un parser OpenMP prêt à être intégré dans STEP.
Une documentation sur le parser openMP de STEP.
Un parser HMPP prêt à être intégré dans STEP.
Un poster décrivant le projet.
Une fiche résumée du projet.
Nous aurions aimé réaliser l’intégration des deux parsers dans STEP par nous même,
cependant nous n’en n’avions pas eu le temps. En effet, cela nous demanderai d’étudier plus
en détail la manière dont est construit STEP en terme de module.
b) Difficultés rencontrées
Plusieurs difficultés se sont soulevées durant le projet. La première concerne la
compréhension et la prise en main de l’outil STEP. En effet, la taille de l’outil le rend difficile à
modifier à sa guise, ainsi, lors des tests de STEP afin de comprendre le fonctionnement du
parser, il nous a pris du temps à comprendre à partir de quel répertoire il nous fallait
recompiler le programme.
D’autre part, l’intégration de notre parser OpenMP n’a pas pu être possible de notre coté pour
ce même problème, nous n’avons pas trouvé le fichier où était mis les dépendances de fichier.
Ainsi, si nous supprimions le fichier step_omp.l pour mettre nos deux fichiers flex et bison,
modifions le makefile dans le même répertoire, nous avions un problème de dépendance que
nous n’avons pas réussi à résoudre. C’est pourquoi nous avons plutôt décidé de préparer
l’intégration plutôt que d’intégrer nous même, cependant nous n’avons donc pas pu faire de
réel test de nos parser.
La seconde concerne la prise en main du langage HMPP qui n’est pas évidente de premier
abord. En effet il a été nécessaire de différencier les directives pertinentes dans le cadre de
notre projet des directives générales.
c) Temps de travail passé sur le projet
La majorité du projet a été l’étude de la documentation et de code venant de STEP et HMPP et
la prise en main des deux en réalisant un grand nombre de test. La partie codage de parser n’a
pas été la partie la plus difficile et la partie qui nous a pris le plus de temps.
19
Voici un tableau qui résume le temps de travail que nous avons passé sur le projet :
Révison Flex/Bison
Etude de STEP
Construction de la doc STEP
Codage parser OpenMP
Etude + prise en main de HMPP
Codage parser HMPP
Préparation à l’intégration
Reunion
Rapport
Slides
Poster + Fiche
Total
Rémy Thean
3
20
10
25
5
0
7
6
18
3
2
Victor Maréchal
3
15
2
5
30
10
4
6
10
5
4
193
20
Conclusion
Ce projet fut très intéressant. Il nous a permis de revoir des notions vues en ASR et
d’affirmer nos connaissances sur celles-ci en particulier les technologies permettant d’établir
un analyseur syntaxique (Flex, Bison) et les langages de programmation haute performance
(MPI, OpenMP).
Le projet nous a aussi permis de découvrir de nouveaux outils. HMPP est assez intéressant
dans sa façon de fonctionner, sans changer fondamentalement le code original. STEP est un
outil prometteur, permettant d’automatiser l’optimisation de code.
Nous avons eus quelques difficultés sur ce projet, en particulier sur la compréhension de la
structure de STEP. L’aide d’Alain Muller et de Rachid Abel nous a été très utile pour
comprendre le fonctionnement de l’analyseur de STEP.
Nous sommes parvenus à écrire un parser qui reconnait des directives HMPP et qui peut
être aisément modifié pour inclure d’autres directives. Nous espérons que nos deux parsers
soient intégrés dans STEP.
21