• Aucun résultat trouvé

Échantillonneur d’allocations (Poor man’s profiler)

Dans le document Profilage mémoire d’applications OCaml (Page 96-101)

4.7 Outils en OCaml

4.7.4 Échantillonneur d’allocations (Poor man’s profiler)

”Poor man have no time to learn complicated new tools. Poor man need simulation results.”5

L’idée derrière ce profileur est de simplifier le profiling d’une application au maxi- mum. Le but principal est de pouvoir extraire des informations sans forcément connaître les détails du programme, mais de pouvoir comprendre pourquoi l’application est lente.

Avec les debuggers classiques, pour profiler les programmes lents, la façon standard d’obtenir des traces intéressantes est la suivante :

1. Lancer le programme avec le debugger

2. L’arrêter après un certain temps puis regarder le code exécuté 3. Répéter l’étape 2 autant que nécessaire

Ensuite selon les outils, une représentation graphique peut être obtenue pour pouvoir naviguer entre le code source et les données obtenues avec la trace. Il faut alors com- prendre le fonctionnement de l’outil, lire la documentation, refaire ces étapes de profiling jusqu’à obtenir l’information pertinente nous expliquant une ou les causes de la lenteur du programme.

L’idée du profileur du pauvre est de simplifier ce processus en enlevant les parties superflues, comme le fait d’avoir une trace toutes les microsecondes ou l’apprentissage d’un nouvel outil de profiling.

La philosophie du profileur est d’utiliser les outils classiques disponibles en les pous- sant le plus loin possible.

alloc-prof une variante en OCaml

alloc-prof [21] permet au programmeur de trouver les points critiques d’allocation dans leur programme. Inspiré d’un échange sur la mailing-list d’OCaml présentant le profileur du pauvre, il consiste en une modification de la runtime d’OCaml qui sau- vegarde dans un journal la pile du programme à chaque fois qu’une certaine quantité de mémoire est allouée. Les traces peuvent être affichées sur une page web écrit avec js_of_ocaml [90] pour l’affichage et la navigation dans le graphe. Sur la figure 4.14, on peut voir l’exemple de ce graphe généré par alloc-prof pour la commande ocamlopt. On peut alors naviguer dans ce graphe en cliquant sur les points critiques d’allocations.

Le constat que nous faisons est qu’en OCaml, très peu d’outils nous permettent aujourd’hui de faire du profiling mémoire comme en Java, Haskell ou Scheme. Contrai- rement à Java dont les blocs mémoires contiennent beaucoup d’informations utile pour le profiling, en OCaml, la runtime n’offre très peu d’informations de ce genre.

Nous avons vu qu’analyser l’exécution d’une application avec un profileur permet de mieux comprendre son comportement. Les résultats peuvent permettre de faire de l’optimisation de la mémoire ou de la performance et dans certains cas de détecter des problèmes liés à la mémoire.

Nous nous sommes fixés comme objectif de ne proposer pour OCaml que des tech- niques de profiling qui ne modifiaient pas le comportement mémoire des applications, afin de ne pas être contraints de collecter des informations qui pourraient ne plus être pertinentes, ni les performances, afin de pouvoir être utilisées en production.

Figure 4.14 – Exemple d’affichage des points d’allocations chauds pour ocamlopt avec l’outil alloc-prof.

permettre, sans aucun surcoût mémoire, de retracer les points d’allocation de chaque bloc en mémoire. Comme nous l’avons vu précédemment, cette absence de surcoût lors du profiling est très importante, car le comportement mémoire doit rester le plus proche possible de l’application réelle, sinon les résultats peuvent devenir inexploitables, car faussés par ce surcoût.

”L’important c’est de savoir ce qu’il faut observer.” Edgar Allan Poe

5

Extraction de données

Grâce à son système de typage fort, statique et inféré, OCaml n’a pas besoin d’in- formations de types pendant l’exécution d’un programme. C’est grâce à cela que la représentation mémoire vue dans la Section 2.5 est très compacte, contrairement aux langages avec un système de types moins fort, et par conséquent les programmes ont de meilleures performances pendant leur exécution.

Malheureusement, cet avantage devient rapidement un inconvénient lorsque l’on tente de faire du profiling mémoire, à cause de l’absence d’information de types durant l’exé- cution d’un programme. Il devient alors très compliqué d’essayer de comprendre l’occu- pation mémoire et la nature des valeurs allouées.

Afin de pouvoir relier les informations d’allocation recueillies dynamiquement par un profileur et les points de programme à l’origine de ces allocations, nous avons ajouté un identifiant de site d’allocation sur chacun des blocs en mémoire, pour pouvoir les retracer par la suite.

Pour cela, après avoir décoré l’arbre de syntaxe abstraite du programme avec un identifiant unique pour chaque site d’allocation, nous avons propagé ces identifiants le long de toute la chaîne de compilation, jusqu’aux instructions d’allocation elles-mêmes, afin de les insérer dans les en-têtes des blocs mémoires alloués. La représentation de ces identifiants est très compacte, et, au prix d’une légère restriction de la taille maximale

des blocs alloués, l’insertion des identifiants a un coût mémoire nul.

Durant l’analyse de la mémoire dynamique d’un programme, ces identifiants nous permettent de retrouver facilement depuis un bloc mémoire, son point d’allocation dans le programme source. De plus, la génération de ces identifiants se faisant sur l’arbre de syntaxe abstraite typé‚ il est également possible de leurs associer le type statique de la valeur correspondante.

La génération d’identifiants nécessite un travail conséquent sur le compilateur, pour tracer ces points d’allocation et de propager les identifiants. Une modification supplé- mentaire est également nécessaire dans la bibliothèque d’exécution d’OCaml afin de pouvoir sauvegarder l’image de la mémoire d’une application durant son exécution. En effet, une fois les identifiants générés et sauvegardés dans les en-têtes des blocs, nous avons mis en œuvre plusieurs façons de dumper le tas (les instantanés) sur disque, afin de pouvoir ensuite relire la mémoire et ainsi récupérer les nouveaux blocs mémoires avec ces identifiants de site d’allocation. Ce chapitre décrit notre technique d’extraction de ces données.

5.1 Ajout des identifiants de site d’allocation

Le but est d’ajouter à chaque bloc du tas une information utile pour le profiling (position de l’allocation dans le code source, son type, etc.), sans augmenter l’occupation mémoire des blocs.

L’idée de notre outil est de décorer l’arbre de syntaxe abstraite avec un identifiant unique pour chaque emplacement qui puisse provoquer une allocation, puis de propa- ger ces identifiants durant la compilation jusqu’aux instructions d’allocation afin de les conserver explicitement dans chaque bloc mémoire. Sur les architectures 64 bits, un cer- tain nombre de bits des en-têtes de blocs sont utilisables, si on réduit la taille maximale des blocs alloués, et c’est dans cet espace que nous stockons les identifiants. Durant l’analyse d’un tas mémoire, ils nous permettent de « remonter » d’un bloc mémoire à son point d’allocation dans le programme source. De plus, en effectuant la génération des identifiants sur l’arbre de syntaxe abstraite typé, on peut aussi associer à chaque identi- fiant le type statique de la valeur correspondante. Cela nécessite également de modifier la machine virtuelle.

5.1.1 Générations des identifiants

Dans le document Profilage mémoire d’applications OCaml (Page 96-101)