An gprof-like profiler tools essential for all ones profiling there programs. myproof uses the gcc version 4.5 or higher allowing to use plugins. This project has been developed to validate the "advanced compilation module" during the HPC'MSc.
1. myproof
projet de compilation
Aur`le Mah´o, Caner Candan
e e
M2 MIHP
aurele.maheo@gmail.com, caner@candan.fr
6 mars 2011
passes
report params
init
summary
myproof
gcc plugin
profiler end
pragmas
measure
error
Figure 1 – Hierarchy of main features
1
3. 1 INTRODUCTION 3
1 Introduction
myproof est un logiciel de profiling, ` la mani`re de gprof 1 , regroupant toutes les ´tapes
a e e
n´cessaire ` l’instrumentation et ` la mesure d’une application cible. Il se diff´rencie, tout de
e a a e
mˆme, de ce dernier en apportant une interface modulable. En effet, il devient possible avec
e
myproof d’integrer ais´ment, par exemple, sa propre “pass” 2 ou encore un nouveau “pragma” 3 .
e
Pour cela, myproof fournit des structures de donn´es compl`tes comme “les fonctions”, “les blocs
e e
de base”, “les boucles” mais aussi “les chemins” entre blocs de base.
1.1 Hierarchie des fonctionnalit´s principales
e
Nous pr´sentons, en figure 1, les fonctionnalit´s principales de notre logiciel de profiling. En
e e
partant de la racine du projet, nous avons 3 sous-noeuds qui sont respectivement “gcc plugin”,
“profiler” et “report”. “gcc plugin” est le repertoire contenant le plugin. Il permet de charger
a
` chaud les fonctionnalit´s de “myproof” durant la phase de compilation de gcc. “profiler”
e
contient l’outil de profiling. “report” est le repertoire contenant ce jolie rapport. Nous verrons
plus en d´tail, par la suite, les fonctionnalit´s de “gcc plugin”.
e e
1.2 CMake
Il est important de noter que compte tenu des nombreuses parties que regroupe ce pro-
jet, il nous a sembl´ plus approri´ d’utiliser CMake. Plus exactement il nous permet de lier
e e
toutes les parties de notre projet et cr´e des liens de d´pendances entre elles durant les phases
e e
de compilation, toute en s’abstrayant des contraires de portabilit´ li´es aux divergences des OS 4 .
e e
Il est ainsi possible de compiler l’ensemble du projet, voir figure 2 ou juste une petite partie,
voir figure 3.
cd $MYPROOF; ./build_gcc_linux_release
Figure 2 – Compile the whole project
cd $MYPROOF/plugin; ./build_gcc_linux_release
Figure 3 – Compile only one part
Le r´sultat de la compilation se trouve selon le script de compilation execut´, dans le
e e
r´pertoire “release”, “debug” ou “build”.
e
1.3 Le plugin GCC
Pour ce qui concerne les diff´rentes phases d’instrumentation, nous avons choisi de d´velopper
e e
un plugin, ce qui permet d’enrichir les fonctionnalit´s de GCC sans pour autant avoir ` le re-
e a
compiler.
1. GNU gprof : http://www.cs.utah.edu/dept/old/texinfo/as/gprof_toc.html
2. une passe gcc
3. #pragma directive
4. Syst`mes d’exploitation
e
4. 2 LES DIRECTIVES PRAGMA 4
2 Les directives pragma
Qui n’a jamais r´v´ de percer le myst`re de “OpenMP” et de ses directives si joliment faites.
e e e
2.1 Modularit´
e
Comme introduit pr´c´dement les directives pragma font partie des fonctionnalit´s modu-
e e e
lable. Il est tr`s facile de cr´er une nouvelle directive dans le projet.
e e
2.2 Respect du sujet
Il a ´t´ demand´ dans le sujet de respecter deux styles de d´claration des pragmas que nous
ee e e
citons en figure 4 et 5.
pragma instrumente foo
Figure 4 – Style 1
pragma instrumente (fct1, fct2)
Figure 5 – Style 2
2.3 Fichiers de test
Un ensemble de fichiers dans les r´pertoires “test” du projet ont ´t´ cr´es afin d’assurer le
e ee e
fonctionnement des fonctionnalit´s demand´es.
e e
2.4 Gestion d’erreur
Une gestion d’erreur est egalement garantie au cas o` les styles cit´s pr´cedement ne sont
u e e
pas respect´s. Cela se traduit par un message d’erreur du compilateur.
e
5. 3 INSTRUMENTATION STATIQUE 5
3 Instrumentation statique
3.1 La probl´matique
e
La probl´matique de cette partie ´tait de dresser un profil statique du code consid´r´, c’est-
e e ee
a
`-dire obtenir une trace des acc`s m´moire ` la compilation. Un exemple est illustr´ en figure
e e a e
6.
fonction toto
3 load
2 * N load
1 * N store
2 load
3 * M load
3 * M store
Figure 6 – R´sultat obtenu par l’instrumentation statique
e
3.2 Acc`s m´moire
e e
Ces acc`s m´moire se traduisent par les instructions load et store ex´cut´es. Nous consid´rons
e e e e e
qu’une instruction load est d´tect´e lorsque le contenu d’un tableau est affect´e ` une variable,
e e e a
un store lorsqu’un tableau r´cup`re la valeur d’une variable.
e e
3.3 Blocs de base et boucles
L’id´e ´tait donc de parcourir les blocs de base composant chaque fonction du code. La
e e
principale difficult´ de cette phase de profiling consistait ` d´tecter les ´ventuelles boucles
e a e e
pr´sentes au sein d’une fonction, puis traiter les blocs de base, en ´vitant les redondances.
e e
3.4 Parsing des boucles et blocs de base
Cette op´ration a ´t´ effectu´e en deux passes : le parsing des boucles pass_loop, puis celui
e ee e
des blocs de base courants pass_bb.
Dans les 2 passes, l’instrumentation se d´roule de la fa¸on suivante :
e c
– La fonction principale de la passe parcourt tous les blocs de base ` l’aide de la macro
a
FOR_EACH_BB. Puis, elle utilise un it´rateur pour analyser les “statements”, c’est-`-dire
e a
les lignes du bloc de base courant. Ceci est fait grˆce ` la fonction read_stmt().
a a
– La fonction read_stmt() qui est appel´e permet de savoir si le statement correspond ` un
e a
appel de fonction, un retour, une condition, ou plus simplement une affectation 5 . C’est
ce dernier cas qui nous int´resse.
e
– Ensuite, nous avons besoin de savoir de quel cˆt´ de l’´galit´ nous sommes. La fonction
oe e e
read_stmt() nous donne ´galement la position de l’op´rande (` droite ou ` gauche de
e e a a
5. voir “GIMPLE ASSIGN” dans gimple
6. 3 INSTRUMENTATION STATIQUE 6
l’´galit´). La fonction read_operand(), quant ` elle, d´termine le type rencontr´, en l’oc-
e e a e e
curence, celui qui nous int´resse
e 6 . Un exemple de code est fournit en figure 7.
– Lorsque ce cas est rencontr´, on incr´mente le compteur de loads si l’op´rande est ` droite
e e e a
de l’´galit´, et le compteur de stores si l’op´rande se trouve ` gauche.
e e e a
case INDIRECT_REF:
/* pointer & dereferencing */
if ( store == true ) { basicblock->nstore++; }
else { basicblock->nload++; }
break;
Figure 7 – Exemple de code d’incrementation des compteurs de load et store
3.5 La passe des boucles
La premi`re passe pass_loop d´tecte les ´ventuelles boucles pr´sentes dans la fonction ins-
e e e e
trument´e, en la parcourant. Elle stocke dans une structure les blocs de base contenus dans
e
lesdites boucles.
La d´tection des boucles est possible grˆce au code pr´sent´ en figure 8, au sein de la fonction
e a e e
pass_loop().
if ( cfun->x_current_loops != NULL )
{
read_loop( cfun->x_current_loops->tree_root, function );
}
Figure 8 – Appel de la fonction read loop
La fonction read_loop() permet de connaˆ ıtre les bornes des boucles rencontr´es dans la
e
fonction, et ainsi de multiplier le nombre des op´rations ´ventuelles load et store par le nombre
e e
d’it´rations de la boucle. Les blocs de base contenant ces boucles sont ´cart´es du traitement
e e e
classique des blocs, afin d’´viter des redondances.
e
3.6 La passe des blocs de base
La seconde passe passe_bb, quant ` elle, reparcourt les blocs de base de la fonction, et
a
v´rifie pour chaque bloc consid´r´ s’il a d´j` ´t´ trait´ dans la passe pr´c´dente. Dans ce cas,
e ee eaee e e e
elle passe au bloc de base suivant. Dans le cas contraire, elle analyse chaque statement du bloc.
3.7 Localisation des passes
Au niveau de l’enregistrement de la passe pass_loop, nous avons chang´ le param`tre “mud-
e e
flap2” d´di´ au parcours GIMPLE, par “parloops”.
e e
6. voir “INDIRECT REF” dans gimple
7. 3 INSTRUMENTATION STATIQUE 7
3.8 Param`tres d’optimisation
e
Enfin, pour prendre en compte les boucles du code ` compiler, les options d’optimisation
a
“-O1” ou “-O2” de gcc doivent ˆtre utilis´es.
e e
3.9 Graphe CFG
Nous vous pr´sentions pr´c´dement les blocs de base ainsi que les “chemins” entre blocs de
e e e
base que “myproof” reconnait.
Il nous est donc possible de g´n´rer des graphes CFG 7 .
e e
Nous vous pr´sentons en figure 9 un exemple de graphe d’un programme comportant deux
e
fonctions.
F0_BB2 F1_BB3
F0_BB3 F1_BB4 F1_BB5
F0_BB4 F0_BB10 F1_BB1
F0_BB5 F0_BB6
F0_BB7
F0_BB9 F0_BB8 F0_BB1
Figure 9 – Exemple de CFG d’un programme
7. Grammaire non contextuelle
8. 4 INTRUMENTATION DYNAMIQUE 8
4 Intrumentation dynamique
Pour parvenir ` une instrumentation dynamique il a fallut agir ` plusieurs endroit du projet.
a a
4.1 Directive d’instrumentation
Dans un premier temps, il ´tait indispensable d’avoir un “pragma” pr´vu pour l’instrumen-
e e
tation dynamique, nous l’appelerons pragma_instrumente. Ce premier va enregistrer dans une
liste toutes les fonctions ` instrumenter en respectant l’unicit´ des fonctions.
a e
4.2 Passe d’instrumentation
Dans un second, une “passe” pass_instrumente est pr´vu pour l’instrumentation des fonc-
e
tions figurant dans la pr´c´dente liste. L’instrumentation se produit en determinant les blocs de
e e
base d’entr´e et de sortie des fonctions et en leur affectant un nouvel arbre “gimple” effectuant
e
un “call”. Les “call” sont effectu´s sur les fonctions cit´es ci-dessous.
e e
4.3 Gestion d’erreur
Une troisi`me ´tape consiste ` d´t´cter l’existance d’une fonction d´clar´e comme “`-instrumenter”.
e e a ee e e a
L’erreur se traduit par un message d’erreur du compilateur.
4.4 La librairie “Measure”
Nous avons cr´e une librairie appel´ “measure” qui contient deux fonctions cl´s :
e e e
– myproof_measure_start(fname), maintient une pile de fonction conservant la mesure
d’entr´e d’une fonction.
e
– myproof_measure_stop(), supprime la derni`re fonction ins´r´e dans la pile et d´termine
e ee e
le nombre de cycle ´coul´ pour son ex´cution en soustrayant le temps avec une mesure de
e e e
sortie.
4.5 Mesure avec RDTSC
Pour les mesures nous utilisons l’instruction assembleur “RDTSC” qui nous retourne le
num´ro du cycle courant.
e
9. 5 CONSTRUCTION DU PROFILING 9
5 Construction du profiling
L’objectif de cette partie ´tait d’analyser et d’interpr´ter les traces de sortie d’ex´cution du
e e e
code ` compiler.
a
Nous avons donc d´velopp´ un parseur LEX et YACC capable d’analyser les traces statiques
e e
et dynamiques issues du code instrument´.
e
5.1 Parsing LEX et YACC
Les traces issues de l’instrumentation dynamique se pr´sentent sous la forme suivante :
e
Appel X ` la fonction main entr´e cycle WW sortie cycle YY
a e
Appel X ` la fonction f1 entr´e cycle WW sortie cycle YY
a e
Appel X ` la fonction f2 entr´e cycle WW sortie cycle YY
a e
La grammaire reconnaissant les traces dynamiques est la suivante :
CALL FUNCTION NAME ENTERCYCLE NUMERIC EXITCYCLE NUMERIC RETLINE
ENTERCYCLE et EXITCYCLE correspondent aux temps de d´but et de fin d’ex´cution
e e
d’une fonction.
5.2 Profilage exclusif
Le profilage issu du fichier de trace est inclusif, dans le sens o` le temps total d’ex´cution
u e
d’une fonction inclut les temps d’ex´cution des fonctions appel´es depuis la fonction parente.
e e
L’analyse du fichier de traces se propose de produire un profilage exclusif, c’est-`-dire le
a
temps d’ex´cution d’une fonction seule.
e
Pour pouvoir construire le profilage exclusif des fonctions, nous avions besoin de connaˆ
ıtre
les imbrications entre elles, et nous avons opt´ pour une construction sous forme d’arbres n-
e
aires, o` chaque noeud repr´sente une fonction.
u e
La premi`re fonction analys´e constitue la racine de l’arbre (il s’agira du point d’entr´e
e e e
main() par exemple). Ensuite, pour chaque nouvelle fonction reconnue par l’analyseur, celui-ci
cr´e un noeud qui est compar´ aux noeuds pr´c´dents, en fonction des temps d’entr´e et de
e e e e e
sortie de la fonction.
Le noeud pr´c´dent le plus r´cent contenant une mesure d’entr´e inf´rieure et une mesure
e e e e e
de sortie sup´rieure au noeud derni`rement cr´´ devient le parent de celui-ci. Le temps exclusif
e e ee
de la fonction parente est alors calcul´e en soustrayant son temps inclusif par le temps inclusif
e
de la fonction enfant.
main
f unc1
main− > exclusivetime = main− > inclusivetime − f unc1− > inclusivetime
Figure 10 – Add a first node
10. 5 CONSTRUCTION DU PROFILING 10
Si un autre noeud ayant le mˆme parent est ajout´, alors on soustrait ` nouveau le temps
e e a
exclusif du parent par le temps inclusif du nouveau noeud ajout´.
e
f unc1
main
f unc2
main− > exclusivetime = main− > exclusivetime − f unc2− > inclusivetime
Figure 11 – Add a second node
L’op´ration est r´p´t´e jusqu’` la fin de l’analyse du fichier de traces, jusqu’` obtenir le
e e ee a a
temps exclusif de toutes les fonctions.
5.3 Gestion des instances
L’un des objectifs du profiling est de pouvoir comparer les temps d’ex´cution de diff´rentes
e e
instances d’une fonction, et de pouvoir les visualiser.
Jusqu’` maintenant, tous les appels d’une mˆme fonction sont chacun repr´sent´s par un
a e e e
noeud unique (on rajoute un noeud ` chaque ligne lue par YACC).
a
func1 func2 func3 func4 func2 func5
Figure 12 – Nodes list
Nous avons avant tout besoin de d´tecter les fonctions redondantes du fichier d’entr´e, puis
e e
les consid´rer comme des instances diff´rentes d’une mˆme fonction.
e e e
Pour ´tablir le nombre d’instances par fonction, l’analyseur reparcourt la liste des noeuds,
e
identifie celles ayant le mˆme nom, puis les stocke dans une structure, en renseignant le nombre
e
d’instances.
func1 func2 func3 func4 func5
instances: 1 instances: 2 instances: 1 instances: 1 instances: 1
Figure 13 – Nodes list with instances
11. 5 CONSTRUCTION DU PROFILING 11
Les donn´es recueillies sont ainsi s´rialis´es dans un fichier de sortie, puis interpr´t´es en
e e e ee
vue de produire un diagramme gnuplot.
5.4 Corr´lation des instrumentations statique et dynamique
e
La seconde partie du profiler consiste ` corr´ler les donn´es statiques et dynamiques d’une
a e e
fonction, ` savoir confronter le temps d’ex´cution et le nombre de load/store. Dans cette op-
a e
tique, nous avons construit une grammaire lui permettant de reconnaˆ les donn´es issues de
ıtre e
l’instrumentation statique :
FUNCTION NAME RETLINE
NUMERIC LOAD RETLINE
NUMERIC MUL NUMERIC LOAD RETLINE
NUMERIC STORE RETLINE
NUMERIC MUL NUMERIC STORE RETLINE
Une fois les donn´es statiques lues, on peut calculer le nombre de load et de store par fonc-
e
tion, puis, en parcourant la liste des fonctions d´j` stock´es, faire correspondre le nombre de
ea e
load/store aux donn´es dynamiques de la fonction pr´c´demment analys´e.
e e e e
Une piste envisag´e (qui a ´t´ impl´ment´e), ´tait de calculer une estimation de la latence
e ee e e e
d’un load et d’un store. Cette op´ration revenait ` r´soudre un syst`me d’´quations ` deux
e a e e e a
inconnues (load et store), dont le r´sultat serait le temps d’ex´cution de la fonction concern´e.
e e e
On r´sout le syst`me en prenant en entr´e un couple de fonctions, ce qui se traduit par :
e e e
load1*FacteurLoad1 + store1*FacteurStore1 = TempsFonction1
load2*FacteurLoad2 + store2*FacteurStore2 = TempsFonction2
Syst`me qui a ´t´ r´solu en utilisant la m´thode de “Cramer” 8 .
e ee e e
L’op´ration a ´t´ r´p´t´e sur toutes les fonctions (en conservant la mˆme fonction comme
e ee e ee e
premi`re ´quation), afin de calculer une moyenne sur les load/store. Cependant, cette piste a
e e
´t´ ´cart´e en raison de la volatilit´ des latences d’acc`s m´moire.
eee e e e e
5.5 Graphe d’appel
Enfin, le profiler propose la g´n´ration d’un graphe d’appel des fonctions, ` l’aide d’un
e e a
parcours pr´fix´ de l’arbre n-aire construit. Il produit en sortie un fichier compr´hensible par
e e e
l’outil “dot”. Un exemple de graphe d’appel est donn´ en figure 14.
e
5.6 Script python
Compte tenu des nombreuses donn´es que le projet g´n´re, instrumentation static, ins-
e e e
trumentation dynamique, cfg, call graph, il devient donc indispensable de cr´er un outil de
e
param`trage regroupant toutes ces fonctionnalit´s.
e e
Cet outil s’appelle “myproof.py”, il s’agit d’un script d´velopp´ en python.
e e
8. La r`gle de Cramer : http://fr.wikipedia.org/wiki/Regle_de_Cramer
e
12. 5 CONSTRUCTION DU PROFILING 12
func3 func4
func1 func2
func5
func6
func7 func11
main
func8 func12
func9 func13
func10 func14
func15
func16
func17
Figure 14 – Functions Call Graph
Nous avons con¸u ce programme en annexe ` l’outil de profiling, afin de permettre ` l’utili-
c a a
sateur le choix quant ` la donn´e qu’il souhaite consulter.
a e
Il est, par exemple, possible dans un premier temps de lister toutes les fonctions que “my-
proof” ` d´tecter pendant la phase de compilation, puis d’en choisir une afin de cibler les mesures
a e
pr´cisement sur cette fonction.
e
D’autres options du progamme permettent d’afficher des graphes sur les instances des fonc-
tions. Un exemple est illustr´ en figure 15.
e
13. 6 MULTI-THREADING 13
100
Cycle's measure by instance and function
100
0
1
80
2
3
60 55 55
Cycles
40
25
20
10 10
5 5
0 0 0 0 0 10 10
0 1 2 3
Instances
Figure 15 – Exemple de graphe g´n´r´
e ee
6 Multi-threading
Un des probl`mes qui peuvent se poser dans le cas d’une ex´cution multithread´e, est
e e e
l’´criture concurrente sur les prises de mesure, faussant ainsi ces derni`res.
e e
Il est possible de rem´dier ` ce probl`me en utilisant plusieurs techniques que nous citons :
e a e
– utilisation des mutexes 9 donnant droit ` un acc`s exclusif aux donn´es en ´criture,
a e e e
– utilisation des POSIX semaphores 10 permettant une synchronisation des actions entre
processus et threads,
– utilisation du mot cl´ _thread devant une d´claration de variable.
e e
9. man pthreads
10. man sem overview
14. ´
7 REFLEXION SUR LE MODULE DE COMPILATION 14
7 R´flexion sur le module de compilation
e
Comme demand´, voici un avis critique (constructif nous l’esp´rons !) du module de compi-
e e
lation et de la mani`re dont les cours se d´roul´s :
e e e
– Les cours nous ont paru int´ressants, ils nous ont permis de d´couvrir ` quel point la
e e a
compilation ´tait une discipline dense, et qu’il n’´tait pas ais´ de le couvrir en un laps de
e e e
temps si court. Donc peu de choses ` dire sur le contenu des cours.
a
– Les travaux dirig´s, pas grand chose ` dire non plus si ce n’est qu’il n’a pas ´t´ possible
e a ee
de tous les faire enti`rement, probl`me de temps encore donc nous ne voyons pas grand
e e
chose ` reprocher aux intervenants.
a
– En revanche, nous pensons qu’il aurait ´t´ beaucoup plus simple de prendre connaissance
ee
du sujet du projet plus en avance, ce qui nous aurait permis une meilleure organisation,
et nous aurait ´vit´ de devoir le mener ”dans l’urgence”, au d´triment du reste.
e e e
– Par ailleur, il aurait peut-etre ´t´ plus prudent d’insister sur les outils ` pr´parer et ins-
ee a e
taller avant le d´marrage des travaux dirig´s, en effet, un grand nombre de personnes ne
e e
sachant toujours pas comment compiler et utiliser gcc.