blob: 44135aed3dfc0c4a54b0b6f927f94b0819e1fb88 (
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
---
title: JavaScript プロファイラ
slug: Tools/Profiler
tags:
- Debugging
- Firefox
- Guide
- Profiler
- Profiling
- Tools
translation_of: Tools/Performance
---
<div>{{ToolsSidebar}}</div><p>プロファイラツールを使用して、JavaScript コードのボトルネックを見つけましょう。プロファイラは周期的に、サンプルについて現在の JavaScript コールスタックやコンパイルの統計情報を抽出します。</p>
<p>"Web 開発" メニューから "プロファイラ" を選択することで、プロファイラを起動できます。"Web 開発" メニューは、Linux や OS X では "ツール" メニューの配下に、Windows では "Firefox" メニューの直下にあります。</p>
<p><a href="/ja/docs/Tools/Tools_Toolbox" title="Tools/Tools_Toolbox">ツールボックス</a>が開いて、プロファイラが選択されます。</p>
<h2 id="Sampling_profilers" name="Sampling_profilers"><a name="sampling-profilers">サンプリング型プロファイラ</a></h2>
<p>JavaScript プロファイラは、サンプリング型のプロファイラです。これは JavaScript エンジンの状態を定期的にサンプリングして、その時点のコード実行のスタックを記録します。統計的に、個々の関数を実行しているときに取得したサンプル数はブラウザが実行にかけた時間に対応しますので、コード内のボトルネックを発見できます。<br>
<br>
<a name="profiling-example">例えば、以下のようなプログラムについて考えてみましょう:</a></p>
<pre class="brush: js">function doSomething() {
var x = getTheValue();
x = x + 1; // -> サンプル A
logTheValue(x);
}
function getTheValue() {
return 5;
}
function logTheValue(x) {
console.log(x); // -> サンプル B、サンプル C
}
doSomething();</pre>
<p>プロファイラをアクティブにしてこのプログラムを実行したら、実行時にプロファイラは上記のインラインコメントで示したように 3 つのサンプルを取得します。</p>
<p>これらはすべて <code>doSomething()</code> の内部から取得されますが、2 番目の 2 つは <code>doSomething()</code> から呼び出された <code>logTheValue()</code> 関数の内部です。よってプロファイルは、以下のように 3 つのスタックトレースで構成されます:</p>
<pre>サンプル A: doSomething()
サンプル B: doSomething() > logTheValue()
サンプル C: doSomething() > logTheValue()</pre>
<p>これは私たちに何も伝えられない不十分なデータであることが明らかですが、より多くのサンプルにより、<code>logTheValue()</code> がコード内のボトルネックであると断定できるかもしれません。</p>
<h2 id="Creating_a_profile" name="Creating_a_profile">プロファイルの作成</h2>
<p>プロファイラで<em>ストップウォッチ</em>のボタンをクリックして、サンプルの記録を始めます。プロファイラが記録を行っている間は、ストップウォッチのボタンがハイライトされます。ボタンを再度押すと記録を停止して、新たなプロファイルを保存します:</p>
<p style="text-align: center;"><img alt="" src="https://mdn.mozillademos.org/files/5977/Screen%20Shot%202013-08-26%20at%2010.35.47%20AM.png"></p>
<p>"終了" をクリックすると、新しいプロファイルが自動的に開きます:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5981/Screen%20Shot%202013-08-26%20at%2011.07.18%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>このペインは 2 つのパーツに分かれています:</p>
<ul>
<li>左側は取得したすべてのプロファイルを一覧表示しており、それぞれのプロファイルを読み込むことができます。また、リストの上にボタンが 2 つあります。<em>ストップウォッチ</em>のボタンは新たなプロファイルの記録を、<em>インポート...</em> ボタンは以前に保存したデータのインポートを行います。プロファイルを選択しているときは、<em>保存</em>ボタンをクリックするとデータを JSON ファイルとして保存できます。</li>
<li>右側は現在読み込んでいるプロファイルを表示します。</li>
</ul>
<h2 id="Analyzing_a_profile" name="Analyzing_a_profile">プロファイルの分析</h2>
<p>プロファイルは 2 つのパーツに分かれています:</p>
<ul>
<li><a href="#profile-timeline" title="#profile-timeline">プロファイルのタイムライン</a></li>
<li><a href="#profile-details" title="#profile-details">プロファイルの詳細</a></li>
</ul>
<h3 id="Profile_timeline" name="Profile_timeline"><a name="profile-timeline">プロファイルのタイムライン</a></h3>
<p>プロファイルのタイムラインは、プロファイル表示の上部を占めています:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5987/timeline" style="display: block; margin-left: auto; margin-right: auto;">横軸は時間、縦軸はサンプルにおけるコールスタックのサイズを表します。コールスタックは、サンプルを取得したときにアクティブであった関数の量を表します。</p>
<p>チャートで赤色のサンプルは、そのときにブラウザが応答していなかったことを示しており、ユーザはアニメーションや応答性が止まったことに気づいたかもしれません。プロファイルに赤色のサンプルがある場合は、そのコードをいくつかのイベントに分解することを検討したり、<a href="/ja/docs/Web/API/window.requestAnimationFrame" title="Web/API/window.requestAnimationFrame">requestAnimationFrame</a> や <a href="/ja/docs/Web/Guide/Performance/Using_web_workers" title="Web/Guide/Performance/Using_web_workers">Worker</a> の使用について調べたりしましょう。</p>
<p>タイムラインでクリックアンドドラッグすることで、プロファイル内の特定の範囲を調査できます:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5989/Screen%20Shot%202013-08-26%20at%2011.17.59%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>タイムラインの上に "サンプリング範囲 [AAA, BBB]" というラベルがついた、新たなボタンが現れます。そのボタンを押すとプロファイルがズームされて、そのタイムスライスの詳細なビューが下部に表示されます:</p>
<p><br>
<img alt="" src="https://mdn.mozillademos.org/files/5991/Screen%20Shot%202013-08-26%20at%2011.18.03%20AM.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<h3 id="Profile_details" name="Profile_details"><a name="profile-details">プロファイルの詳細</a></h3>
<p>プロファイルの詳細は、プロファイル表示の下部を占めています:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5993/profiler-details-highligted.png" style="display: block; margin-left: auto; margin-right: auto;">始めに新しいサンプルを開くと、サンプルペインには上のスクリーンショットのように "(total)" という名前の行があります。"(total)" の隣にある三角印をクリックすると、サンプル内にあるすべてのトップレベル関数がリストアップされます。</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5995/Screen%20Shot%202013-08-26%20at%2011.22.10%20AM.png"></p>
<p><strong>実行時間</strong>は当該関数が現れたサンプルの総数を示し<a href="#footnote-1"><sup>1</sup></a>、その後ろにプロファイル内で当該関数が現れた全サンプルのパーセント値があります。最上段の行はプロファイル全体で 2021 のサンプルがあることを表し、また 2 行目は 1914 サンプルすなわち全体の 94.7% が、<code>detectImage()</code> 関数内にいたことを表します。</p>
<p><strong>滞在</strong> は当該関数そのものを実行する間に取得したサンプル数を示しており、関数を呼び出しているときではありません。前出の<a href="#profiling-example" title="#profiling-example">シンプルな例</a>では、<code>doSomething()</code> は<strong>実行時間</strong>が 3 (サンプル A、B、C) ですが、<strong>滞在</strong>の値は 1 (サンプル A) になるでしょう。</p>
<p>3 列目は関数名およびファイル名と行数 (ローカルの関数) またはベースネームとドメイン名を表示します。灰色の関数はブラウザ組み込みの関数です。黒色の関数がページで読み込んだ JavaScript を表します。行にマウスポインタを乗せると、関数の識別名の右側に矢印が現れます: 矢印をクリックすると関数のソースを表示します。</p>
<h3 id="Expanding_the_call_tree" name="Expanding_the_call_tree">コールツリーの展開</h3>
<p>ある行で、この関数から呼び出された関数に滞在している間のサンプルが存在する場合 (すなわち、<strong>実行時間</strong>がその行の<strong>滞在</strong>より大きい場合) は、関数名の左側に三角印が表示され、コールツリーを展開できます。</p>
<p>前出の<a href="#profiling-example" title="#profiling-example">シンプルな例</a>では、完全に展開したコールツリーは以下のようになります:</p>
<table class="standard-table" style="height: 100px; width: 378px;">
<tbody>
<tr>
<td style="text-align: center;"><strong>実行時間</strong></td>
<td style="text-align: center;"><strong>滞在</strong></td>
<td style="text-align: center;"> </td>
</tr>
<tr>
<td style="text-align: center;">3 100%</td>
<td style="text-align: center;">1</td>
<td style="text-align: center;">doSomething()</td>
</tr>
<tr>
<td style="text-align: center;">2 67%</td>
<td style="text-align: center;">2</td>
<td style="text-align: center;">logTheValue()</td>
</tr>
</tbody>
</table>
<p>より実際的な例を見ましょう: 前出のスクリーンショットで、上から 2 行目を見ると <code>detectImage()</code> 関数の内部で 1914 サンプルかかっていることがわかります。しかし、そのすべては <code>detectImage()</code> から呼び出された関数でかかっています (<strong>滞在</strong> セルが 0 です)。コールツリーを展開して、ほとんどのサンプルがかかっていたとき実際に実行していた関数は何かを明らかにできます:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5999/bla.png" style="display: block; margin-left: auto; margin-right: auto;"></p>
<p>これは、<code>detectAtScale()</code> を実際に実行しているときに 6 サンプル、<code>getRect()</code> の実行に 12 サンプルかかっていたことなどを表します。</p>
<h2 id="Footnotes" name="Footnotes">脚注</h2>
<ol>
<li><a name="footnote-1">関数がさまざまなソースから複数回呼び出される場合、プロファイラの出力にも複数回現れます。よって、<code>forEach</code> など汎用的な関数はコールツリー内に複数回現れるでしょう。</a></li>
</ol>
|