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:
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:
- collecter les données avec l’outil perf (
apt install linux-perf
sous Debian pour l’obtenir); - mettre en forme les données;
- 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 perf
1:
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
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:
- il faut fournir le nom complet du
cgroup
du container, préfixé pardocker/
. Le nom complet s’obtient avecdocker inspect --format={{.Id}} nom-du-container
- 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ènementinsstructions
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:
- Tout sur les FlamGraph, par Brendan Gregg, qui est à l’origine du concept: https://github.com/brendangregg/FlameGraph
- Dépôt git pour générer les images: https://github.com/brendangregg/FlameGraph
- Sur la commande
perf
:- Page web de Brendan Gregg qui présente l’outil: http://www.brendangregg.com/perf.html
- Présentation au format PDF) du même auteur avec des informations supplémentaires: http://www.brendangregg.com/Slides/SCALE2015_Linux_perf_profiling.pdf
- Tutorial: https://perf.wiki.kernel.org/index.php/Tutorial#Sampling_with_perf_record
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
).