De quoi parle-t-on?

Les graphes de flammes (traduction plus qu’approximative de flam graphs) sont une représentation graphiques des appels de fonctions d’un serveur ou d’un programme, qui permet de visualiser:

  • l’empilement des appels de fonctions (quelle fonction appelle qui);
  • la durée (ou une autre quantité comme la mémoire) occupée par chaque fonction.

Comme une image vaut mieux qu’un long discours voici un exemple:

Cliquer pour voir l’original en SVG image

Figure 1 : Un serveur qui ne fait presque rien

Ceci est une image statique. Mais l’image originale permet de zoomer à volonté.

Premières flammes

Pour créer un tel graphe, trois étapes théoriques sont nécessaires:

  1. collecter les données avec l’outil perf (apt install linux-perf sous Debian pour l’obtenir);
  2. mettre en forme les données;
  3. générer l’image.

J’ai écrit en théorie ci-dessus, parce qu’en pratique l’étape deux et trois sont généralement effectuées en même temps.

La génération des données s’effectue donc avec la commande perf. Par exemple:

perf record -F 99 -a -g -- sleep 20

Cette commande collecte pendant 20 secondes tous les appels de fonctions à la fréquence 99. Elle génère un fichier perf.data dans le répertoire où elle a été lancée.

La première transformation que l’on va apporter à ce fichier s’effectue aussi avec la commande perf1:

perf script --header -i perf.data > out.perf

Cela génère un fichier texte, auquel vous pouvez jeter un œil. C’est lisible, mais pas très pratique. À la limite, pour lire le contenu des données collectée, la commande report est plus adaptée: perf report -n --stdio.

Pour la suite, vous allez avoir besoin de FlameGraph. Il suffit de récupérer le dépôt, et d’appeler les commandes suivantes depuis le répertoire où est téléchargé le dépôt:

./stackcollapse-perf.pl ../out.perf > out.folded
./flamegraph.pl --title "Server On Fire" out.folded > image.svg

Et voilà, vous avez généré votre premier graphe de flammes!

On peut résumer les dernières commandes en une seule ligne:

perf script --header -i ../path-to/perf.data | ./stackcollapse-perf.pl | ./flamegraph.pl --title "Title" > en-flamme.svg

Plus de précisions

Parfois il y a beaucoup de unknown qui apparaissent comme nom de fonction. Cela signifie que perf n’arrive pas à retrouver la fonction appelée. Généralement en remplaçant -g par --call-graph dwarf cela résout le problème. J’ai aussi rencontré une situation où la solution a été d’effacer le contenu de mon répertoire ~/.debug/ qui contenait des fichiers obsolètes.

Jusqu’à présent, nous avons obtenu une image globale de notre système. Mais il est aussi possible de surveiller un ou plusieurs processus, grâce à l’argument -p:

record -F 99 -a --call-graph dwarf -p 469325,521774 -- sleep 10

Cliquer pour voir l’original en SVG image

Figure 2 : Graphe de flamme d’un processus Emacs

De même les arguments -t et -u filtrent le premier sur les thread id, et le second sur les processus appartenant à un utilisateur donné.

Il est aussi possible d’observer un container.

perf record -F 99 -a --call-graph dwarf -e instructions --cgroup=docker/424d518a79c2bf2bed363a32ef0ceee3e9ec47e34020eaff41bf0b09fba84251 -- sleep 10

Quelques explications s’imposent:

  1. il faut fournir le nom complet du cgroup du container, préfixé par docker/. Le nom complet s’obtient avec docker inspect --format={{.Id}} nom-du-container
  2. il faut spécifier un event. Perf, qui sert à beaucoup d’autres choses que produire des graphes de flammes, permet d’observer uniquement certains évènement. L’évènement insstructions est suffisant pour notre besoin.

Références

Cet article n’est qu’une légère introduction.

Quelques références, toutes en anglais, pour aller plus loin:

1

L’argument -i, qui indique le fichier à traiter, est inutile dans le cas présent, puisque perf.data est le fichier par défaut. Je ne l’ai mis ici uniquement pour vous évitez de le rechercher dans la documentation (perf help script).