1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
---
title: Arbre d'appels
slug: Tools/Performance/Call_Tree
translation_of: Tools/Performance/Call_Tree
original_slug: Outils/Performance/Call_Tree
---
<div>{{ToolsSidebar}}</div>
<div class="summary">
<p>L'arbre d'appel permet de savoir dans quelles fonctions JavaScript le navigateur passe le plus de temps. En analysant ces résultats, il est possible de trouver les points noirs du code (les endroits ou le navigateur passe beaucoup trop de temps).</p>
<p>Ces points noirs sont les endroits où les optimisations auront le plus grand impact.</p>
</div>
<p>L'arbre d'appel est un profileur par échantillons. Il prend périodiquement des échantillons de l'état du moteur JavaScript, et enregistre la pile pour le code s'exécutant dans ce moment. Statistiquement, le nombre d'échantillons dans lequel on exécute une fonction en particulier correspond au temps que le navigateur passe à l'exécuter. Il est alors possible de trouver les points noirs de votre code.</p>
<div class="note">
<p>Cet article utilisera le résultat d'un programme simple comme exemple. Si vous voulez récupérer ce programme pour expérimenter l'outil vous-même, il est disponible <a href="https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/">ici</a>. Vous pouvez trouver le profil discuté dans cet article <a href="https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/profile/call-tree.json">ici</a> - importez juste le profil dans l'outil Performance pour pouvoir voir le profil utilisé dans cet article.</p>
<p>Il y a une courte page décrivant la structure du programme disponible <a href="https://developer.mozilla.org/fr/docs/Tools/Performance/Examples/Sorting_algorithms_comparison">ici</a>.</p>
<p>Il est à noter que le même programme et le même profil est utilisé pour la page de documentation sur le <a href="/fr/docs/Tools/Performance/Flame_Chart">Flame Chart</a>.</p>
</div>
<p>La capture d'écran ci-dessous montre les résultats d'un programme qui compare trois différents algorithmes de tri (tri à bulle, tri par sélection et tri rapide). Pour faire cela, il génère un nombre de tableaux remplis avec des int aléatoires et les tris avec chaque algorithme.</p>
<p>Nous avons <a href="/fr/docs/Tools/Performance/UI_Tour#Zooming_in">zoomé</a> dans une partie de l'enregistrement qui montre un long marker JavaScript :</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/10981/perf-call-tree.png" style="display: block; height: 574px; margin-left: auto; margin-right: auto; width: 1052px;"></p>
<p>L'arbre d'appel présente les résultats dans un tableau. Chaque ligne représente une fonction dans laquelle au moins un échantillon a été pris, et les lignes sont classées par nombre d'échantillons pris dans la fonction.</p>
<p><em>Échantillons</em> correspond au nombre d'échantillons pris lors de de l'exécution de la fonction. Cela inclu ses enfants (les autres fonctions appelées par cette fonction).</p>
<p><em>Durée Totale </em>correspond est ce nombre, traduit en millisecondes, basées sur le temps total couvert par la portion sélectionnée de l'enregistrement. Ces deux nombres devraient être approximativement les même.</p>
<p><em>Cout Total </em>correspond à ce nombre traduit en pourcentage du nombre total d'échantillons dans la portion sélectionnée de l'enregistrement.</p>
<p><em>Coût individuel</em> correspond au temps passé dans cette fonction en particulier, sans inclure ses enfants. Cela vient de la pille capturé lorsque cette fonction est la plus basse.</p>
<p><em>Durée individuelle</em> est calculé depuis <em>Coût individuel </em>comme un pourcentage du nombre total d'échantillons dans la portion sélectionnée de l'enregistrement.</p>
<p>Dans la version actuelle de l'arbre d'appel, ce sont les colones les plus importantes. Les fonctions avec un <em>Cout individuel</em> important sont de bons candidats pour de l'optimisation, soit parce qu’elles prennent beaucoup de temps à s'exécuter, soit parce qu'elles sont appelées très souvent.</p>
<p>Cette capture d'écran révèle ce que l'on savait déjà : <code>bubbleSort()</code> est un algorithme très inefficace. Il y a à peu près 6 fois plus d'échantillons dans <code>bubbleSort()</code> que de dans <code>selectionSort()</code>, et 13 fois plus dans que dans <code>quickSort()</code>.</p>
<h2 id="Se_déplacer_dans_l'arbre_d'appel">Se déplacer dans l'arbre d'appel</h2>
<p>A coté de chaque nom de fonction, se trouve une flèche d'expansion : cliquer sur celle-ci révèle le chemin allant de l'appel de la fonction jusqu'a la racine. Par exemple, il est possible d'étendre l'entrée pour <code>bubbleSort()</code> :</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/10983/perf-call-tree-expanded-bubblesort.png" style="display: block; height: 512px; margin-left: auto; margin-right: auto; width: 1054px;"></p>
<p>On peut donc voir que le graphique d'appel est comme ceci :</p>
<pre>sortAll()
-> sort()
-> bubbleSort()</pre>
<p>Notez également que le <em>Cout individuel </em>pour <code>sort()</code> est ici de 1.45%, et notez également que ce chiffre est le même pour une autre ligne de <code>sort()</code> plus tard dans la liste. Cela révèle que quelques échantillons ont été pris dans <code>sort()</code> elle-même plutôt que dans la fonction qu'elle appelle.</p>
<p>Quelques fois, il y a plus d'un chemin menant à la même fonction. Essayons par exemple d'étendre la ligne de <code>swap()</code>:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/10985/perf-call-tree-expanded-sawp.png" style="display: block; height: 636px; margin-left: auto; margin-right: auto; width: 1052px;"></p>
<p>Il y a 253 échantillons qui ont été pris à l'intérieur de<code> swap()</code>. Mais <code>swap()</code> a été accédé par deux chemins différents car <code>bubbleSort()</code> <code>et selectionSort()</code> l'utilisent tous deux. Il est également possible de voir que 252 des 253 échantillons ont été pris dans la branche <code>bubbleSort()</code>, et uniquement un dans la branche <code>selectionSort()</code>.</p>
<p>Cela signifie que le tri à bulle est encore moins efficient que ce que l'on pensait ! La fonction coute 252 échantillons de plus, soit 10% de cout supplémentaire.</p>
<p>Avec ce genre de recherche, il est possible de déduire le graphique d'appel complet, avec le nombre d'échantillons associés :</p>
<pre>sortAll() // 8
-> sort() // 37
-> bubbleSort() // 1345
-> swap() // 252
-> selectionSort() // 190
-> swap() // 1
-> quickSort() // 103
-> partition() // 12</pre>
<h2 id="Données_de_la_plateforme">Données de la plateforme</h2>
<p>Vous pouvez également remarquer des lignes nommées <em>Gecko</em>, <em>Input & Events</em>, et ainsi de suite. Cela représente les appels internes au navigateur.</p>
<p>Cela peut être utile comme informations. Par exemple si votre site donne beaucoup de travail au navigateur. Ces échantillons ne sont peut-être pas pris dans votre code, mais c'est quand même votre problème.</p>
<p>Dans notre exemple, il y a 679 échantillons assignés à <em>Gecko </em>- le deuxième plus gros groupe après <code>bubbleSort()</code>. étendons donc cela :</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/10987/perf-call-tree-expanded-gecko.png" style="display: block; height: 478px; margin-left: auto; margin-right: auto; width: 1050px;"></p>
<p>Cela révèle que 614 de ces échantillons, soit environ 20% du cout total, viennent de l'appel de <code>sort()</code>. Si nous regardons au code de la fonction, il devient évident que le cout élevé des données de plateforme viennent des appels répétés à <code>console.log()</code>:</p>
<pre class="brush: js">function sort(unsorted) {
console.log(bubbleSort(unsorted));
console.log(selectionSort(unsorted));
console.log(quickSort(unsorted));
}</pre>
<p>Il serait certainement intéressant de considérer des façons plus efficientes d'implémenter cela.</p>
<p>Une chose à garder en tête est que les périodes d'inactivité sont classifiées en tant que <em>Gecko</em>, donc les parties de votre profil où votre JavaScript ne tourne pas contribueront aux échantillons <em>Gecko</em>. Ces échantillons n'impactent pas la performance de votre site.</p>
<div class="note">
<p>Par défaut, l'arbre d'appel ne sépare par les données de plateforme dans des fonctions séparées, car elles ajoutent beaucoup de nuisance et ces détails ont peu de chances d'être utiles à des personnes ne travaillant sur le développement de Firefox. Si vous voulez cependant voir ces détails, il faut cocher l'option "Afficher les données de la plateforme Gecko" dans les <a href="/fr/docs/Tools/Performance/UI_Tour#Toolbar">options</a>.</p>
</div>
<p> </p>
<h2 id="Utiliser_un_arbre_inversé_(_Bottom-Up)">Utiliser un arbre inversé ( Bottom-Up)</h2>
<p>Un arbre d'appel inversé, inverse l'ordre de toutes les piles, en mettant la fonction la plus loin dans l'arbre au début. La conséquence directe est que cette vue se focalise plus sur l'information <em>Durée Individuelle</em>. Cette vue est pratique pour trouver les points "chauds" du code.</p>
<p>Pour afficher cette vue, cliquer sur l'icône en forme d'engrenage dans la partie droite et de cliquer sur <strong>L'arbre d'appel</strong>.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/16093/performance_menu_invert_call_tree.png" style="border-style: solid; border-width: 1px; display: block; height: 201px; margin: 0 auto; width: 492px;"></p>
|