Skip to content

Graphiques en flammes

À quoi sert un graphique en flammes ?

Les graphiques en flammes permettent de visualiser le temps CPU passé dans les fonctions. Ils peuvent vous aider à identifier les endroits où vous passez trop de temps à effectuer des opérations synchrones.

Comment créer un graphique en flammes

Vous avez peut-être entendu dire que la création d'un graphique en flammes pour Node.js est difficile, mais ce n'est plus vrai. Les machines virtuelles Solaris ne sont plus nécessaires pour les graphiques en flammes !

Les graphiques en flammes sont générés à partir de la sortie de perf, qui n'est pas un outil spécifique à Node.js. Bien que ce soit le moyen le plus puissant de visualiser le temps CPU passé, il peut y avoir des problèmes avec la façon dont le code JavaScript est optimisé dans Node.js 8 et les versions supérieures. Voir la section Problèmes de sortie perf ci-dessous.

Utiliser un outil pré-emballé

Si vous souhaitez une seule étape qui produit un graphique en flammes localement, essayez 0x

Pour diagnostiquer les déploiements de production, lisez ces notes : serveurs de production 0x.

Créer un graphique en flammes avec les outils système perf

Le but de ce guide est de montrer les étapes nécessaires à la création d'un graphique en flammes et de vous permettre de contrôler chaque étape.

Si vous souhaitez mieux comprendre chaque étape, consultez les sections suivantes où nous entrerons dans les détails.

Maintenant, allons-y.

  1. Installez perf (généralement disponible via le paquet linux-tools-common s'il n'est pas déjà installé)
  2. Essayez d'exécuter perf - il pourrait se plaindre de modules du noyau manquants, installez-les également
  3. Exécutez Node avec perf activé (voir Problèmes de sortie perf pour des conseils spécifiques aux versions de Node.js)
bash
perf record -e cycles:u -g -- node --perf-basic-prof app.js
  1. Ignorez les avertissements à moins qu'ils ne disent que vous ne pouvez pas exécuter perf en raison de paquets manquants ; vous pouvez obtenir des avertissements concernant l'impossibilité d'accéder aux échantillons de modules du noyau, ce qui n'est pas ce que vous recherchez de toute façon.
  2. Exécutez perf script > perfs.out pour générer le fichier de données que vous visualiserez dans un instant. Il est utile d'appliquer un nettoyage pour un graphique plus lisible
  3. Installez stackvis s'il n'est pas encore installé npm i -g stackvis
  4. Exécutez stackvis perf < perfs.out > flamegraph.htm

Ouvrez maintenant le fichier du graphique en flammes dans votre navigateur préféré et regardez-le brûler. Il est codé par couleur afin que vous puissiez vous concentrer d'abord sur les barres orange les plus saturées. Elles représentent probablement les fonctions gourmandes en CPU.

Il est important de mentionner que si vous cliquez sur un élément d'un graphique en flammes, un zoom sur son environnement s'affichera au-dessus du graphique.

Utiliser perf pour échantillonner un processus en cours d'exécution

C'est idéal pour enregistrer des données de flame graph à partir d'un processus déjà en cours d'exécution que vous ne souhaitez pas interrompre. Imaginez un processus de production avec un problème difficile à reproduire.

bash
perf record -F99 -p `pgrep -n node` -- sleep 3

À quoi sert sleep 3 ? Il permet à perf de continuer à fonctionner ; malgré l'option -p pointant vers un PID différent, la commande doit être exécutée sur un processus et se terminer avec lui. perf s'exécute pendant toute la durée de la commande que vous lui passez, que vous profilieziiez ou non cette commande. sleep 3 garantit que perf s'exécute pendant 3 secondes.

Pourquoi -F (fréquence de profilage) est-il défini sur 99 ? C'est une valeur par défaut raisonnable. Vous pouvez l'ajuster si vous le souhaitez. -F99 indique à perf de prendre 99 échantillons par seconde ; pour plus de précision, augmentez la valeur. Des valeurs plus faibles doivent produire moins de sortie avec des résultats moins précis. La précision dont vous avez besoin dépend de la durée d'exécution réelle de vos fonctions gourmandes en CPU. Si vous recherchez la raison d'un ralentissement notable, 99 images par seconde devraient largement suffire.

Une fois que vous avez cet enregistrement perf de 3 secondes, générez le flame graph avec les deux dernières étapes ci-dessus.

Filtrer les fonctions internes de Node.js

En général, vous souhaitez uniquement examiner les performances de vos appels. Le filtrage des fonctions internes de Node.js et de V8 peut donc rendre le graphique beaucoup plus facile à lire. Vous pouvez nettoyer votre fichier perf avec :

bash
sed -i -r \
    -e '/(_libc_start|LazyCompile) |v8::internal::BuiltIn|Stub|LoadIC:\\[\\[' \
    -e '/^$/d' \
    perf.data > perf.out

Si vous lisez votre flame graph et qu'il semble étrange, comme si quelque chose manquait dans la fonction clé occupant le plus de temps, essayez de générer votre flame graph sans les filtres ; vous avez peut-être rencontré un cas rare de problème avec Node.js lui-même.

Options de profilage de Node.js

--perf-basic-prof-only-functions et --perf-basic-prof sont les deux options utiles pour le débogage de votre code JavaScript. D'autres options sont utilisées pour le profilage de Node.js lui-même, ce qui dépasse le cadre de ce guide.

--perf-basic-prof-only-functions produit moins de sortie, c'est donc l'option avec le moins de surcharge.

Pourquoi en ai-je besoin ?

Sans ces options, vous obtiendrez quand même un flame graph, mais la plupart des barres seront étiquetées v8::Function::Call.

Problèmes de sortie Perf

Modifications du pipeline V8 de Node.js 8.x

Node.js 8.x et les versions supérieures sont fournies avec de nouvelles optimisations du pipeline de compilation JavaScript dans le moteur V8, ce qui rend parfois les noms/références de fonctions inaccessibles pour perf. (Il s’agit de Turbofan)

Le résultat est que vous risquez de ne pas obtenir les bons noms de fonction dans le flame graph.

Vous remarquerez ByteCodeHandler: là où vous vous attendiez à des noms de fonction.

0x possède certaines atténuations intégrées à cet effet.

Pour plus de détails, voir :

Node.js 10+

Node.js 10.x résout le problème avec Turbofan à l’aide de l’indicateur --interpreted-frames-native-stack.

Exécutez node --interpreted-frames-native-stack --perf-basic-prof-only-functions pour obtenir les noms de fonction dans le flame graph, quel que soit le pipeline utilisé par V8 pour compiler votre JavaScript.

Étiquettes cassées dans le flame graph

Si vous voyez des étiquettes ressemblant à ceci :

bash
node`_ZN2v88internal11interpreter17BytecodeGenerator15VisitStatementsEPMS0_8Zone

cela signifie que la version de Linux perf que vous utilisez n’a pas été compilée avec la prise en charge du débogage, voir https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1396654 par exemple.

Exemples

Entraînez-vous à capturer vous-même des flame graphs avec un exercice sur les flame graphs !