blob: d0472584d407c7edd125e867482e0fa1e12552ef (
plain)
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
124
125
126
127
128
|
---
title: コールツリー
slug: Tools/Performance/Call_Tree
tags:
- JavaScript
- パフォーマンス
- メモリ
translation_of: Tools/Performance/Call_Tree
---
<div>{{ToolsSidebar}}</div>
<div class="summary">
<p>コールツリーは、どの JavaScript 関数がもっともブラウザで時間をかけているかを示します。この結果を分析すると、コードのボトルネック (ブラウザが不相応に多くの時間をかけている場所) を見つけることができます。</p>
<p>これらのボトルネックは、最適化により最大の効果を得られる場所です。</p>
</div>
<p>コールツリーは、サンプリングプロファイラです。これは JavaScript エンジンの状態を定期的にサンプリングして、その時点のコード実行のスタックを記録します。統計的に、個々の関数を実行しているときに取得したサンプル数はブラウザが実行にかけた時間に対応しますので、コード内のボトルネックを発見できます。</p>
<div class="note">
<p>本記事では、例としてシンプルなプログラムから出力した結果を使用します。自身のプロファイルで実験するためにプログラムを取得したい場合は、<a href="https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/">こちら</a>をご覧ください。ここで言及するプロファイルは<a href="https://github.com/mdn/performance-scenarios/blob/gh-pages/js-call-tree-1/profile/call-tree.json">こちら</a>にあります。読み進めるために、インポートしてください。</p>
<p>プログラムの構造を説明するページは<a href="/ja/docs/Tools/Performance/Examples/Sorting_algorithms_comparison">こちら</a>です。</p>
<p>なお<a href="/ja/docs/Tools/Performance/Flame_Chart">フレームチャート</a>のドキュメントページでも、同じプログラムおよび同じプロファイルを使用しています。</p>
</div>
<p>以下のスクリーンショットはバブルソート、選択ソート、クイックソートの 3 種類のソートアルゴリズムを比較するプログラムの出力です。整数の乱数を埋めた配列をいくつか生成して、それぞれのアルゴリズムで順にソートします。</p>
<p>記録内で長い JavaScript マーカーを示している部分を<a href="/ja/docs/Tools/Performance/UI_Tour#Zooming_in">ズームイン</a>しました:</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>コールツリーは、表形式で結果を表示します。それぞれの行は 1 個以上のサンプルを取得した関数を表し、これらの行は関数内で取得したサンプル数の降順で並べられます。</p>
<p><em>Samples は、この特定の関数を実行していたときに取得されたサンプル (この関数によって呼び出された他の関数) の数です。</em></p>
<p><em>Total Time</em> <em>は、記録の選択された部分がカバーする合計時間に基づいて、その数値をミリ秒に変換したものです。これらの数値は、サンプル数とほぼ同じでなければなりません。</em></p>
<p><em>Total Cost は、記録の選択された部分のサンプルの合計数に対するパーセンテージとしての数値です。</em></p>
<p><em>Self Time</em> <em>は、その特定の機能で費やされた時間 (その子を除く) として計算されます。これは、キャプチャされたスタックから来ており、この関数は最も近い関数です。</em></p>
<p><em>Self Cost は、録音の選択された部分のサンプルの合計数に対するパーセンテージとしてセルフタイムから計算されます。</em></p>
<p>現在のバージョンのコールツリーでは、これらが最も重要な列です。<em>Self Cost </em>が比較的高い関数は、実行に時間がかかり、頻繁に呼び出されるため、最適化の候補となります。</p>
<div class="note">
<p><a href="https://developer.mozilla.org/ja/docs/Tools/Performance/Call_Tree$edit#Using_an_inverted_aka_Bottom-Up_Call_Tree">The inverted call tree</a> は、これらの <em>Self Cost </em>値に集中する良い方法です。</p>
</div>
<p>このスクリーンショットは、私たちがすでに知っていると思われるものを示しています。バブルソートは非常に非効率的なアルゴリズムです。 バブルソートは選択ソートの約6倍、クイックソートの13倍です。</p>
<h2 id="Walking_up_the_call_tree" name="Walking_up_the_call_tree">コールツリーを渡り歩く</h2>
<p>各関数名の隣に、展開用の矢印があります。クリックすると、サンプルを取得した関数からルートに向けて、コールツリーを戻るパスを確認できます。例えば、<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>コールグラフは以下のとおりであるとわかります:</p>
<pre>sortAll()
-> sort()
-> bubbleSort()</pre>
<p>ここで <code>sort()</code> の<em>コスト</em> は 1.45% であり、これはリストの後方にある個別の <code>sort()</code> の値と同じであることに注意してください。これは、一部のサンプルが呼び出した関数内ではなく <code>sort()</code> 自身で取得されたことを表します。</p>
<p>トップレベルへ戻るパスが複数存在することがあります。<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><code>swap()</code> 内で 253 個のサンプルを取得しました。しかし <code>swap()</code> は 2 つの異なるパスで到達しています。<code>bubbleSort()</code> と <code>selectionSort()</code> が使用しています。<code>swap()</code> の 253 サンプルのうち 252 個は <code>bubbleSort()</code> の枝で、また 1 個だけ <code>selectionSort()</code> の枝で取得したこともわかります。</p>
<p>これは、私たちが考えていた以上にバブルソートの効率が低いということです! 自身以外に 252 サンプル、または総コストのほぼ 10% を抱えています。</p>
<p>このような探求によりコールグラフ全体を、関連付けられたサンプル数とともに明らかにできます:</p>
<pre>sortAll() // 8
-> sort() // 37
-> bubbleSort() // 1345
-> swap() // 252
-> selectionSort() // 190
-> swap() // 1
-> quickSort() // 103
-> partition() // 12</pre>
<h2 id="Platform_data" name="Platform_data">プラットフォームのデータ</h2>
<p><em>Gecko</em>、<em>入力とイベント</em>などと記載された行がいくつかあるでしょう。これらは内部のブラウザ呼び出しを表します。</p>
<p>これらも役に立つ情報です。あなたのサイトがブラウザを懸命に働かせている場合、あなたのコードではサンプルが記録されないかもしれませんが、問題は残されています。</p>
<p>本記事の例では、679 個のサンプルが <em>Gecko </em> に割り当てられており、<code>bubbleSort()</code> に次いで 2 番目に大きいグループです。これを展開してみましょう:</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>これは 614 個のサンプル、または総コストの役 20% が <code>sort()</code> の呼び出しに由来することを表します。<code>sort()</code> のコードを見ると、プラットフォームのデータの高いコストの理由は <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>より効率がよい実装方法を検討することは、間違いなく有益でしょう。</p>
<p>ここでわかることとして、アイドル時間は <em>Gecko</em> として分類されますので、プロファイル内で JavaScript を実行していない部分は <em>Gecko</em> のサンプルが増えます。これらはサイトのパフォーマンスとは関係がありません。</p>
<div class="note">
<p>デフォルトで、コールツリーはプラットフォームのデータを個別の関数に分割しません。これは大量のノイズを加えてしまうことと、Firefox 自体に取り組んでいる人々以外には役立たないと思われるためです。これらの詳細を確認したい場合は、<a href="/ja/docs/Tools/Performance/UI_Tour#Toolbar">設定</a>で "Gecko プラットフォームのデータを表示" にチェックを入れてください。</p>
</div>
<h2 id="反転されたボトムアップコールツリーを使用する">反転されたボトムアップコールツリーを使用する</h2>
<p>反転されたコールツリーはすべてのスタックの順序を逆転させ、一番近い関数コールを一番上に置きます。直接的な結果は、これは関数の Self Time 情報に焦点を当てたビューであるということです。 これはコード内のホットスポットを見つけるのに非常に便利なビューです。</p>
<p>このビューを表示するには、[パフォーマンス]タブの右端にある歯車アイコンをクリックし、<strong>Invert Call Tree</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>
|