From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- files/ja/tools/performance/allocations/index.html | 86 ++++ files/ja/tools/performance/call_tree/index.html | 128 ++++++ files/ja/tools/performance/examples/index.html | 12 + .../sorting_algorithms_comparison/index.html | 73 ++++ files/ja/tools/performance/flame_chart/index.html | 103 +++++ files/ja/tools/performance/frame_rate/index.html | 58 +++ files/ja/tools/performance/how_to/index.html | 62 +++ files/ja/tools/performance/index.html | 80 ++++ .../performance/profiler_walkthrough/index.html | 113 +++++ .../scenarios/animating_css_properties/index.html | 156 +++++++ files/ja/tools/performance/scenarios/index.html | 10 + .../scenarios/intensive_javascript/index.html | 231 ++++++++++ files/ja/tools/performance/ui_tour/index.html | 125 ++++++ files/ja/tools/performance/waterfall/index.html | 478 +++++++++++++++++++++ 14 files changed, 1715 insertions(+) create mode 100644 files/ja/tools/performance/allocations/index.html create mode 100644 files/ja/tools/performance/call_tree/index.html create mode 100644 files/ja/tools/performance/examples/index.html create mode 100644 files/ja/tools/performance/examples/sorting_algorithms_comparison/index.html create mode 100644 files/ja/tools/performance/flame_chart/index.html create mode 100644 files/ja/tools/performance/frame_rate/index.html create mode 100644 files/ja/tools/performance/how_to/index.html create mode 100644 files/ja/tools/performance/index.html create mode 100644 files/ja/tools/performance/profiler_walkthrough/index.html create mode 100644 files/ja/tools/performance/scenarios/animating_css_properties/index.html create mode 100644 files/ja/tools/performance/scenarios/index.html create mode 100644 files/ja/tools/performance/scenarios/intensive_javascript/index.html create mode 100644 files/ja/tools/performance/ui_tour/index.html create mode 100644 files/ja/tools/performance/waterfall/index.html (limited to 'files/ja/tools/performance') diff --git a/files/ja/tools/performance/allocations/index.html b/files/ja/tools/performance/allocations/index.html new file mode 100644 index 0000000000..29a7719108 --- /dev/null +++ b/files/ja/tools/performance/allocations/index.html @@ -0,0 +1,86 @@ +--- +title: メモリ割り当て +slug: Tools/Performance/Allocations +translation_of: Tools/Performance/Allocations +--- +
{{ToolsSidebar}}
+

パフォーマンスツールのメモリ割り当てビューは、プロファイルの中でページ内のどの関数がもっとも多くのメモリ割り当てを行ったかを表示します。

+ +

メモリを大量に割り当てたりメモリ割り当てを多数行ったりするとガベージコレクションを引き起こすため、パフォーマンスの観点で重要です。ガベージコレクションは、ページの応答性を損なう可能性があります。

+
+ +
+

メモリ割り当てビューは、Firefox 46 の新機能です。

+
+ +

メモリ割り当てビューを有効にするため、プロファイルを記録する前にパフォーマンスツールの設定で "メモリ割り当てを記録" にチェックを入れなければなりません。そして通常どおりプロファイルの記録を行うと、ツールバーに "メモリ割り当て" という新たなタブが現れます:

+ +

{{EmbedYouTube("Le9tTo7bqts")}}

+ +

メモリ割り当てビューを分析する

+ +

メモリ割り当てビューは、以下のようなものです:

+ +

+ +

メモリ割り当てビューは、記録中に行われたメモリ割り当てを定期的にサンプリングします。それぞれの行は、記録中に少なくとも 1 回、メモリ割り当てのサンプルを取得した関数を表します。

+ +

各行に、以下の列があります:

+ + + +

行は "Self Bytes" 列の値でソートします。

+ +

よって、前出の例では以下のことが分かります:

+ + + +

それぞれの関数名の隣に、展開用の三角印があります。これをクリックすると、関数を呼び出した場所がわかります:

+ +

+ +

この例では signalLater() が 2 つの場所から呼び出されたことが分かります。removeInner()setSelectionInner() です。この方法でコールスタックを戻ることができ、メモリ割り当ての状況をよく理解できます。

+ +

Self Cost と Total Cost

+ + + +

このビューでは、列が "Self" と "Total" の 2 つのセットに分けられていることがわかるでしょう。"Self" は、関数自体で取得したサンプルを記録します。"Total" は関数自体と、この関数から呼び出した関数で取得したサンプルを記録します。ビューではツリーの葉に位置する関数をトップレベルに置きます (つまり、コールスタックを反転して表示します) ので、トップレベルではどちらも同じ値になります。一方、コールスタックを戻っていくと違いが出てくることがわかるでしょう:

+ +

+ +

この図では、signalLater() で 8904 個のサンプルを取得しています。しかし signalLater() は、removeInner()setSelectionInner() の 2 か所から呼び出されています。これらの関数はどちらも Self Count が 0 であり、その関数内で直接メモリ割り当ては行っていないことを意味します。一方、removeInner() の Total Count は 8901、setSelectionInner() の Total Count はわずか 3 です。これは 8904 回のメモリ割り当てが、removeInner() の枝で行われた 3回を除き、すべて signalLater() で発見されたことを語ります。

+ +

メモリ割り当てとガベージコレクション

+ +

当然ながらサイト内で割り当てたメモリは、知っておくと役に立つ情報です。しかし、サイトのメモリ割り当てのプロファイルとサイトの応答性を主に結びつけるものは、ガベージコレクション (GC) のコストです。

+ +

ガベージコレクションを行う JavaScript などの言語は、到達性がなくなったオブジェクトを発見するためにランタイムが定期的にヒープを走査して、そのようなオブジェクトが占めていたメモリを解放しなければなりません。このような GC イベントを実行する間は JavaScript エンジンが一時停止しますので、プログラムが休止して応答性が完全になくなります。

+ +

応答性への影響を軽減するため SpiderMonkey (Firefox の JavaScript エンジン) は少しずつ増加する GC を実施でき、GC の合間にプログラムを実行できます。それでも時にはノンインクリメンタルガベージコレクションが必要であり、この場合プログラムは完了するまで待たなければなりません。

+ +

GC イベントはタイムラインビューで赤色のマーカーで示され、時には数百ミリ秒続くなど応答性に危険信号がともります:

+ +

+ +

サイトのパフォーマンスプロファイルに GC イベントがある場合、何ができるのでしょうか? SpiderMonkey は、いつどのようなガベージコレクションを行うかを決めるために複雑なヒューリスティック技術を使用しています。

+ +

ただし、通常はメモリ割り当ての圧力 (大量のメモリを割り当てる、または高い頻度でメモリを割り当てる) によって SpiderMonkey がガベージコレクションを行う可能性が高くなり、さらにインクりメンタルではないガベージコレクションを行う可能性も高くなります

+ +

メモリ割り当ての圧力によってガベージコレクションが発生した場合は、タイムラインのマーカーの右側にあるサイドバーで "Show allocation triggers" という名前のリンクを表示します。このリンクをクリックすると開発ツールがメモリ割り当てビューに切り替わり、前回の GC が終了したときからクリックした GC が始まるときまでの時間帯を選択します。これにより、GC イベントを引き起こしたメモリ割り当てを集約して表示します:

+ +

{{EmbedYouTube("tO5ovD9Jw4k")}}

+ +

このような問題がみられる場合は、そのときに行っているメモリ割り当ての回数や量を削減できないか検討してください。例えば:

+ + diff --git a/files/ja/tools/performance/call_tree/index.html b/files/ja/tools/performance/call_tree/index.html new file mode 100644 index 0000000000..d0472584d4 --- /dev/null +++ b/files/ja/tools/performance/call_tree/index.html @@ -0,0 +1,128 @@ +--- +title: コールツリー +slug: Tools/Performance/Call_Tree +tags: + - JavaScript + - パフォーマンス + - メモリ +translation_of: Tools/Performance/Call_Tree +--- +
{{ToolsSidebar}}
+ +
+

コールツリーは、どの JavaScript 関数がもっともブラウザで時間をかけているかを示します。この結果を分析すると、コードのボトルネック (ブラウザが不相応に多くの時間をかけている場所) を見つけることができます。

+ +

これらのボトルネックは、最適化により最大の効果を得られる場所です。

+
+ +

コールツリーは、サンプリングプロファイラです。これは JavaScript エンジンの状態を定期的にサンプリングして、その時点のコード実行のスタックを記録します。統計的に、個々の関数を実行しているときに取得したサンプル数はブラウザが実行にかけた時間に対応しますので、コード内のボトルネックを発見できます。

+ +
+

本記事では、例としてシンプルなプログラムから出力した結果を使用します。自身のプロファイルで実験するためにプログラムを取得したい場合は、こちらをご覧ください。ここで言及するプロファイルはこちらにあります。読み進めるために、インポートしてください。

+ +

プログラムの構造を説明するページはこちらです。

+ +

なおフレームチャートのドキュメントページでも、同じプログラムおよび同じプロファイルを使用しています。

+
+ +

以下のスクリーンショットはバブルソート、選択ソート、クイックソートの 3 種類のソートアルゴリズムを比較するプログラムの出力です。整数の乱数を埋めた配列をいくつか生成して、それぞれのアルゴリズムで順にソートします。

+ +

記録内で長い JavaScript マーカーを示している部分をズームインしました:

+ +

+ +

コールツリーは、表形式で結果を表示します。それぞれの行は 1 個以上のサンプルを取得した関数を表し、これらの行は関数内で取得したサンプル数の降順で並べられます。

+ +

Samples は、この特定の関数を実行していたときに取得されたサンプル (この関数によって呼び出された他の関数) の数です。

+ +

Total Time は、記録の選択された部分がカバーする合計時間に基づいて、その数値をミリ秒に変換したものです。これらの数値は、サンプル数とほぼ同じでなければなりません。

+ +

Total Cost は、記録の選択された部分のサンプルの合計数に対するパーセンテージとしての数値です。

+ +

Self Time は、その特定の機能で費やされた時間 (その子を除く) として計算されます。これは、キャプチャされたスタックから来ており、この関数は最も近い関数です。

+ +

Self Cost は、録音の選択された部分のサンプルの合計数に対するパーセンテージとしてセルフタイムから計算されます。

+ +

現在のバージョンのコールツリーでは、これらが最も重要な列です。Self Cost が比較的高い関数は、実行に時間がかかり、頻繁に呼び出されるため、最適化の候補となります。

+ +
+

The inverted call tree は、これらの Self Cost 値に集中する良い方法です。

+
+ +

このスクリーンショットは、私たちがすでに知っていると思われるものを示しています。バブルソートは非常に非効率的なアルゴリズムです。 バブルソートは選択ソートの約6倍、クイックソートの13倍です。

+ +

コールツリーを渡り歩く

+ +

各関数名の隣に、展開用の矢印があります。クリックすると、サンプルを取得した関数からルートに向けて、コールツリーを戻るパスを確認できます。例えば、bubbleSort() のエントリを展開します:

+ +

+ +

コールグラフは以下のとおりであるとわかります:

+ +
sortAll()
+
+    -> sort()
+
+        -> bubbleSort()
+ +

ここで sort()コスト は 1.45% であり、これはリストの後方にある個別の sort() の値と同じであることに注意してください。これは、一部のサンプルが呼び出した関数内ではなく sort() 自身で取得されたことを表します。

+ +

トップレベルへ戻るパスが複数存在することがあります。swap() のエントリを展開してみましょう:

+ +

+ +

swap() 内で 253 個のサンプルを取得しました。しかし swap() は 2 つの異なるパスで到達しています。bubbleSort()selectionSort() が使用しています。swap() の 253 サンプルのうち 252 個は bubbleSort() の枝で、また 1 個だけ selectionSort() の枝で取得したこともわかります。

+ +

これは、私たちが考えていた以上にバブルソートの効率が低いということです! 自身以外に 252 サンプル、または総コストのほぼ 10% を抱えています。

+ +

このような探求によりコールグラフ全体を、関連付けられたサンプル数とともに明らかにできます:

+ +
sortAll()                         //    8
+
+    -> sort()                     //   37
+
+        -> bubbleSort()           // 1345
+
+            -> swap()             //  252
+
+        -> selectionSort()        //  190
+
+            -> swap()             //    1
+
+        -> quickSort()            //  103
+
+            -> partition()        //   12
+ +

プラットフォームのデータ

+ +

Gecko入力とイベントなどと記載された行がいくつかあるでしょう。これらは内部のブラウザ呼び出しを表します。

+ +

これらも役に立つ情報です。あなたのサイトがブラウザを懸命に働かせている場合、あなたのコードではサンプルが記録されないかもしれませんが、問題は残されています。

+ +

本記事の例では、679 個のサンプルが Gecko に割り当てられており、bubbleSort() に次いで 2 番目に大きいグループです。これを展開してみましょう:

+ +

+ +

これは 614 個のサンプル、または総コストの役 20% が sort() の呼び出しに由来することを表します。sort() のコードを見ると、プラットフォームのデータの高いコストの理由は console.log() を繰り返し呼び出しているためであることが明白でしょう:

+ +
function sort(unsorted) {
+  console.log(bubbleSort(unsorted));
+  console.log(selectionSort(unsorted));
+  console.log(quickSort(unsorted));
+}
+ +

より効率がよい実装方法を検討することは、間違いなく有益でしょう。

+ +

ここでわかることとして、アイドル時間は Gecko として分類されますので、プロファイル内で JavaScript を実行していない部分は Gecko のサンプルが増えます。これらはサイトのパフォーマンスとは関係がありません。

+ +
+

デフォルトで、コールツリーはプラットフォームのデータを個別の関数に分割しません。これは大量のノイズを加えてしまうことと、Firefox 自体に取り組んでいる人々以外には役立たないと思われるためです。これらの詳細を確認したい場合は、設定で "Gecko プラットフォームのデータを表示" にチェックを入れてください。

+
+ +

反転されたボトムアップコールツリーを使用する

+ +

反転されたコールツリーはすべてのスタックの順序を逆転させ、一番近い関数コールを一番上に置きます。直接的な結果は、これは関数の Self Time 情報に焦点を当てたビューであるということです。 これはコード内のホットスポットを見つけるのに非常に便利なビューです。

+ +

このビューを表示するには、[パフォーマンス]タブの右端にある歯車アイコンをクリックし、Invert Call Tree を選択します。

+ +

diff --git a/files/ja/tools/performance/examples/index.html b/files/ja/tools/performance/examples/index.html new file mode 100644 index 0000000000..06fadd2aca --- /dev/null +++ b/files/ja/tools/performance/examples/index.html @@ -0,0 +1,12 @@ +--- +title: Examples +slug: Tools/Performance/Examples +tags: + - TopicStub +translation_of: Tools/Performance/Examples +--- +
{{ToolsSidebar}}
+ +

パフォーマンスシナリオとチュートリアルのデモページのリストです。

+ +

{{ ListSubpages ("/ja/docs/Tools/Performance/Examples", 5) }}

diff --git a/files/ja/tools/performance/examples/sorting_algorithms_comparison/index.html b/files/ja/tools/performance/examples/sorting_algorithms_comparison/index.html new file mode 100644 index 0000000000..70e8a8f7b5 --- /dev/null +++ b/files/ja/tools/performance/examples/sorting_algorithms_comparison/index.html @@ -0,0 +1,73 @@ +--- +title: ソートアルゴリズムの比較 +slug: Tools/Performance/Examples/Sorting_algorithms_comparison +translation_of: Tools/Performance/Examples/Sorting_algorithms_comparison +--- +
{{ToolsSidebar}}
+ +

この記事では、2つのパフォーマンスガイドで使用する簡単なサンプルプログラムについて説明します。コールツリーのガイドとフレームチャートのガイドです。

+ +

このプログラムは、3つの異なるソートアルゴリズムのパフォーマンスを比較します。

+ + + +

これは以下の機能で構成されています。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
sortAll()トップレベルの関数。 (200回)反復的に配列を生成し、sort()を呼び出します。
sort()bubbleSort()selectionSort()quickSort()を順に選択し、結果を記録します。
bubbleSort()バブルソートを実装し、ソートされた配列を返します。
selectionSort()選択ソートを実装し、ソートされた配列を返します。
quickSort()クイックソートを実装し、ソートされた配列を返します。
swap()bubbleSort()selectionSort()のヘルパー関数。
partition()quickSort()のヘルパー関数。
+ +

コールグラフは次のようになります。

+ +
sortAll()                     // (generate random array, then call sort) x 200
+
+    -> sort()                 // sort with each algorithm, log the result
+
+        -> bubbleSort()
+
+            -> swap()
+
+        -> selectionSort()
+
+            -> swap()
+
+        -> quickSort()
+
+            -> partition()
+ +

プログラムのソートアルゴリズムの実装は、https://github.com/nzakas/computer-science-in-javascript/から取得され、MITライセンスで使用されます。

+ +

ここでサンプルプログラムを試してみて、ここでコードをクローンすることができます(gh-pagesブランチを確認してください)。 私たちが議論した特定のプロフィールをダウンロードすることもできます。あなたがフォローしたい場合は、パフォーマンスツールにインポートするだけです。 もちろん、独自のプロファイルを生成することもできますが、数字は少し異なります。

diff --git a/files/ja/tools/performance/flame_chart/index.html b/files/ja/tools/performance/flame_chart/index.html new file mode 100644 index 0000000000..3a2cf0c069 --- /dev/null +++ b/files/ja/tools/performance/flame_chart/index.html @@ -0,0 +1,103 @@ +--- +title: フレームチャート +slug: Tools/Performance/Flame_Chart +translation_of: Tools/Performance/Flame_Chart +--- +
{{ToolsSidebar}}
+

フレームチャートはパフォーマンスのプロファイリングを行っている間、ミリ秒ごとにコードの JavaScript スタックの状態を表示します。

+ +

これは記録中の任意の時点でどの関数を実際に実行しているか、またどれだけの期間実行したか、さらにどこから呼び出されたかを知る手段を提供します。

+
+ +

呼び出しツリーとフレームチャートはどちらもサイトの JavaScript を分析するために使用します。またどちらも、記録している間定期的に取得する JavaScript エンジンのスタックのサンプルをデータとして使用します。

+ +

しかし、呼び出しツリーは記録全体の合計に対してプログラムのどこでもっとも多くの時間がかかっているかを示すためにこれらのデータを編成するのに対して、フレームチャートは記録中のどこで特定の関数を実行していたかを示すためにこれらのデータを使用します。本質的には、記録中の任意の位置のコールスタックの状態を表示します。

+ +

こちらは、プロファイルの一部分のフレームチャートを示したスクリーンショットです:

+ +

+ +

始めに記録の概要ペインで、フレームチャートに表示したい記録の一部分を選択していることがわかるでしょう。フレームチャートは大量のデータを表示しており、見やすい結果を得るためには通常、ズームインが必要です。

+ +

フレームチャートビュー自体は、X 軸に沿って時間を表します。前出のスクリーンショットでは、1435ms から 1465ms の間を表示しています。Y 軸に沿ってその時点のコールスタックに存在する関数を、上にトップレベル、下に葉の関数の順に並べます。関数は区別しやすいように色分けします。

+ +

これは記録中の任意の時点でどの関数を実際に実行しているか、またどれだけの期間実行したか、さらにどこから呼び出されたかを知る手段を提供します。

+ +

ズームとパン

+ +

フレームチャートを効果的に使用するため、ナビゲーションできることが必要でしょう。フレームチャートのナビゲーションに使用できる主要な操作が 2 つあります:

+ + + + + + + + + + + + +
ズーム: プロファイル全体のうち、フレームチャートに表示する選択範囲を増減します。 +

1) フレームチャート上でマウスホイールを上下に回します。

+ +

2) フレームチャート上で、トラックパッドで 2 本の指を上下に動かします。

+
パン: プロファイル全体内で、選択範囲を左右に動かします。 +

1) 記録の概要ペインで、選択範囲をクリック・アンド・ドラッグします。

+ +

2) フレームチャートでクリック・アンド・ドラッグします。

+
+ +

{{EmbedYouTube("BzfkBRFucp8")}}

+ +

+ +

フレームチャートがプログラムの動作をどのように明らかにできるかを見るため、シンプルな例を見ていきましょう。呼び出しツリーのページとで使用したものと同じサンプルを使用します。これは、3 種類の異なるソートアルゴリズムを比較するものです。このプログラムの構造の概要は、別のページで説明しています。

+ +

ここでは、呼び出しツリーで使用したものと同じプロファイルのファイルを使用します。呼び出しツリーのページではプロファイル内のプログラム呼び出しグラフと、関連付けられたサンプル数を以下のように明らかにしました:

+ +
sortAll()                         //    8
+
+    -> sort()                     //   37
+
+        -> bubbleSort()           // 1345
+
+            -> swap()             //  252
+
+        -> selectionSort()        //  190
+
+            -> swap()             //    1
+
+        -> quickSort()            //  103
+
+            -> partition()        //   12
+ +

始めに、ぷろぐらむがアクティブであった部分の全体を選択します:

+ +

+ +

最上段の紫色の箇所は sortAll() の呼び出しであり、プログラムの始めから終りまで実行されています。その下にあるオリーブグリーン色は、sort() を呼び出しています。さらに下にあるくしの歯のようなものは、それぞれのソートアルゴリズムを実行する呼び出しです。

+ +

ズームしましょう:

+ +

+ +

この部分は約 140 ミリ秒間です。また、sort() が呼び出した関数をより詳しく示しています。sort() のコードは以下のようなものです:

+ +
function sort(unsorted) {
+  console.log(bubbleSort(unsorted));
+  console.log(selectionSort(unsorted));
+  console.log(quickSort(unsorted));
+}
+ +

"bubb..." と記載されたオリーブグリーン色のマーカーは、おそらく bubbleSort() です。緑色のマーカーは、おそらく別のソートアルゴリズムです。ひと目見ただけで、バブルソートのブロックが他のアルゴリズムより幅が広い (存続時間が長い) ことがわかります。

+ +

また、bubbleSort() から呼ばれている関数 (紫色) がいくつかあることもわかります。

+ +

もう一度ズームしましょう:

+ +

+ +

この部分は約 20 ミリ秒間です。bubbleSort() の下にある紫色のマーカーは、swap() の呼び出しであることがわかります。それらをすべて数えると 253 個あることが、呼び出しツリービューで示されています。ズームした範囲内ではすべて bubbleSort() の下にありますが、呼び出しツリービューによればプロファイル内で 1 個は selectionSort() の下にあります。

+ +

また、緑色のマーカーのうち 2 個は selectionSort() および quickSort() であることがわかる一方で、ソート関数の呼び出しの合間にプラットフォーム (Gecko) のコードを呼び出していることもわかります。これは、sort() 内で console.log() を呼び出していることに由来する可能性が高いと考えられます。

diff --git a/files/ja/tools/performance/frame_rate/index.html b/files/ja/tools/performance/frame_rate/index.html new file mode 100644 index 0000000000..bbd66f03d0 --- /dev/null +++ b/files/ja/tools/performance/frame_rate/index.html @@ -0,0 +1,58 @@ +--- +title: フレームレート +slug: Tools/Performance/Frame_rate +translation_of: Tools/Performance/Frame_rate +--- +
{{ToolsSidebar}}
+

フレームレートは、Web サイトの応答性を測定したものです。低い、あるいは不安定なフレームレートによりサイトの応答性が低い、あるいはジャンキーな状態になり、ユーザエクスペリエンスを損ないます。

+ +

60fps のフレームレートがなめらかなパフォーマンスの目標値であり、あるイベントに対して必要なすべての更新に与えられた時間は 16.7 ミリ秒です。

+ +

パフォーマンスツールでフレームレートのグラフは、記録していた間のフレームレートを表示します。サイトのどこに問題があると思われるかを迅速に示して、より深く分析するために他のツールを使用できるようにします。

+
+ +

フレームレートと応答性

+ +

フレームレートは、ビデオデバイスが生成できる画像 (またはフレーム) のペースです。これは映画やゲームで特に知られていますが、現在は Web サイトや Web アプリのパフォーマンス測定として広く使用されます。

+ +

Web のパフォーマンスにおいて、フレームにはブラウザがスクリーンを更新および再描画するために必要な作業が含まれます。フレームレートは、アニメーションに対してもっとも明らかな効用があります。フレームレートが低すぎるとアニメーションがぎこちない動きになり、フレームレートが高ければスムーズになります。一方でユーザと対話することから、サイトの応答性の一般的な指標としてもフレームレートは有用です。

+ +

例えばページ上のある要素にマウスポインタを動かすと要素の外見を変える JavaScript が実行されてリフローや再描画が発生する場合、すべての作業をフレーム内で完了させることが必要です。ブラウザがフレームを処理するのにかかる時間が長すぎると、ブラウザが一時的に応答しなくなった (ジャンキー) ように見えるでしょう。

+ +

同様に、ページをスクロールすると多くの複雑なページ更新が発生して、許容できるフレームレートをブラウザが維持できない場合、スクロールが遅くなったりときどきフリーズするように見えたりするかもしれません。

+ +

一般的に高く安定したフレームレートにより、ユーザとサイトの対話はより快適かつ魅力的になるでしょう。

+ +
+

60fps のフレームレートがなめらかなパフォーマンスの目標値と考えられており、あるイベントに対して同時に必要なすべての更新に与えられた時間は 16.7 ミリ秒です。

+ +

しかし、安定性は特に重要です。60fps を実現できない場合は低いフレームレートを安定的に実現して、サイトのフリーズをもたらすフレームレートの急な落ち込みを避けるとよいでしょう。

+
+ +

フレームレートのグラフ

+ +

フレームレートのグラフは、パフォーマンスツールの記録の概要の部分にあります。これはブラウザがフレームの処理を終えたときのタイムスタンプを取得して、記録していた期間のフレームレートを追跡するために使用します。

+ +

X 軸はプロファイルを採取した期間の経過時間です。また最大フレームレート、平均フレームレート、最小フレームレートを注釈として表示します。

+ +

フレームレートのグラフを使用する

+ +

フレームレートのグラフの大きな価値は、Web コンソールと同様に、サイトのどこに問題があると思われるかを迅速に示して、より深く分析するために他のツールを使用できるようにすることです。例えば、以下にパフォーマンスツールのスクリーンショットを示します:

+ +

+ +

平均フレームレートはおおむね良好な値ですが、フレームレートが数十ミリ秒間落ち込むときが 3 か所あります。これはきっと、ページで実行しているアニメーションが目立ってぎこちない状況を引き起こすでしょう。

+ +

フレームレートのグラフは、上部にあるウォーターフォールの概要と直接的に関連性があります。フレームレートが落ち込んでいる始めの 2 か所は橙色のバーと関連性があり、これは JavaScript の実行に時間をかけていることを示します。

+ +

落ち込んでいる部分のひとつを選択すると、下部にあるメインのウォーターフォールビューをその部分だけに拡大表示して、問題を起こしている機能を知ることができます:

+ +

+ +

click イベントで実行される JavaScript 関数が、メインスレッドを 170 ミリ秒間ブロックしています。

+ +

どの関数でしょう? この時点のコールスタックを見るため、フレームチャートに切り替えてください:

+ +

+ +

問題を起こしている関数は doPointlessComputations() であり、"main.js" で定義されています。これを修正するには、関数を分割して部品を requestAnimationFrame で実行するか、関数全体を Worker で実行します。集約的な JavaScript の記事では、長く実行される同期式の JavaScript が引き起こす応答性の問題を解決するために、本記事のような手段をどのように利用できるかを説明します。

diff --git a/files/ja/tools/performance/how_to/index.html b/files/ja/tools/performance/how_to/index.html new file mode 100644 index 0000000000..ff4d540ffe --- /dev/null +++ b/files/ja/tools/performance/how_to/index.html @@ -0,0 +1,62 @@ +--- +title: 操作手順 +slug: Tools/Performance/How_to +translation_of: Tools/Performance/How_to +--- +
{{ToolsSidebar}}

パフォーマンスツールを開く

+ +

パフォーマンスツールを開く方法は以下のとおりです:

+ + + +

プロファイルを記録する

+ +

記録ペインでストップウォッチのアイコンを押下すると、新しい記録を開始します。もう一度押下すると、記録を終了します:

+ +

+ +

console.profile()console.profileEnd() を使用して、Web コンソールから記録を開始および終了することもできます。

+ +

プロファイルを保存する

+ +

記録ペインで "保存" と記載されたリンクをクリックすると、プロファイルを保存します:

+ +

+ +

プロファイルを読み込む

+ +

"インポート..." をクリックしてファイルを選択すると、プロファイルを読み込みます:

+ +

+ +

すべてのプロファイルを消去する

+ +

"消去" をクリックすると、すべての読み込み済みプロファイルを消去します。

+ +
+

これを行うと、すべての未保存プロファイルを失います。

+
+ +

+ +

ツールを選択する

+ +

ツールバーのボタンを使用してウォーターフォール呼び出しツリーフレームチャートを切り替えます:

+ +

+ +

表示するマーカーを設定する

+ +

ツールバーのボタンを使用して、ウォーターフォールでどのマーカーを表示するかを設定できます:

+ +

+ +

拡大

+ +

記録の概要で一部分を選択すると、その部分を拡大表示します:

+ +

diff --git a/files/ja/tools/performance/index.html b/files/ja/tools/performance/index.html new file mode 100644 index 0000000000..8abebb675e --- /dev/null +++ b/files/ja/tools/performance/index.html @@ -0,0 +1,80 @@ +--- +title: パフォーマンス +slug: Tools/Performance +translation_of: Tools/Performance +--- +
{{ToolsSidebar}}

パフォーマンスツールは、サイトの一般的な応答性、JavaScript やレイアウトのパフォーマンスを知ることができるツールです。パフォーマンスツールを使用してあなたのサイトで、ある期間の記録やプロファイルを作成できます。記録後は、プロファイル内でサイトをレンダリングするためにブラウザーが行ったことの概要や、プロファイル内のフレームレートを表示します。

+ +

プロファイルのさまざまな側面を詳しく調査するために、4 つのサブツールを使用できます:

+ + + +

{{EmbedYouTube("WBmttwfA_k8")}}

+ +
+

はじめに

+ +
+
+
+
UI ツアー
+
パフォーマンスツールについてひととおり理解するために、UI のクイックツアーを用意しました。
+
+
+ +
+
+
操作手順
+
基本操作: ツールを開く、記録を作成・保存・読み込み・設定する
+
+
+
+ +
+

パフォーマンスツールのコンポーネント

+ +
+
+
+
フレームレート
+
サイトの全体的な応答性を理解します。
+
呼び出しツリー
+
サイトの JavaScript のボトルネックを発見します。
+
メモリ割り当て
+
記録の中でコードが実施したメモリ割り当てを表示します。
+
+
+ +
+
+
タイムライン
+
サイトとの対話として、ブラウザーが実行した作業を理解します。
+
フレームチャート
+
記録全体で、どの JavaScript 関数をいつ実行したかを明らかにします。
+
+
+
+ +
+

シナリオ

+ +
+
+
+
CSS プロパティのアニメーション
+
ブラウザーがどのようにページを更新するか、およびさまざまな CSS プロパティのアニメーションがパフォーマンスにどのような影響を与えるかを、タイムラインを使用して理解します。
+
+
+ +
+
+
集約的な JavaScript
+
長時間実行される JavaScript によって引き起こされるパフォーマンスの問題、およびこのような状況で Worker がどのように役立つかを明らかにするために、フレームチャートとタイムラインを使用します。
+
+
+
diff --git a/files/ja/tools/performance/profiler_walkthrough/index.html b/files/ja/tools/performance/profiler_walkthrough/index.html new file mode 100644 index 0000000000..35e36bc3a9 --- /dev/null +++ b/files/ja/tools/performance/profiler_walkthrough/index.html @@ -0,0 +1,113 @@ +--- +title: プロファイラのチュートリアル +slug: Tools/Performance/Profiler_walkthrough +translation_of: Tools/Performance/Call_Tree +--- +
{{ToolsSidebar}}

JavaScript プロファイラは JavaScript エンジンの状態を定期的にサンプリングして、その時点のコード実行のスタックを記録します。統計的に、個々の関数を実行しているときに取得したサンプル数はブラウザが実行にかけた時間に対応しますので、コード内のボトルネックを発見できます。

+ +

プロファイルを分析する

+ +

パフォーマンスツールがどのようにプロファイルを提供するかを理解するには、例を見ていくことがもっとも簡単です。以下のコードは 2 から 10,000 までの数値について素数であるかを確認して、その結果を表示します。少しおもしろくするため、素数の確認は setTimeout のコールバックとして実行します:

+ +
function isPrime(i) {
+  for (var c = 2; c <= Math.sqrt(i); ++c) {
+    if (i % c === 0) {
+        console.log(i + " is not prime");
+        return;
+     }
+  }
+  console.log(i + " is prime");
+}
+
+function timedIsPrime(i) {
+  setTimeout(function() {
+    isPrime(i);
+  }, 100);
+}
+
+function testPrimes() {
+  var n = 10000;
+  for (var i = 2; i != n; ++i) {
+    timedIsPrime(i);
+  }
+}
+
+var testPrimesButton = document.getElementById("test-primes");
+testPrimesButton.addEventListener("click", testPrimes, false);
+ +

このコードを Web ページに貼り付けて実行すると、コンソールへ以下のように出力します:

+ +
"2 is prime"
+"3 is prime"
+"4 is not prime"
+"5 is prime"
+"6 is not prime"
+ +

このコードのプロファイルを取得すると、以下のように表示されるでしょう:

+ +

+ +

最初の行は、関数列が常に (ルート) になります。ここでは 2 つのことを示しています: プロファイリングに 1,121.95 ミリ秒かかっており、またその間に 78 個のサンプルを取得しました。(ルート) の下に、サンプルの取得中にプログラムで経由した、さまざまなパスのツリーを表示します。(ルート) の直下に、スタックの底にあるトップレベルの関数が現れます。この例では、トップレベルの関数が 2 つあります:

+ + + +

testPrimes() の行を見ていきましょう:

+ +

+ +

ここでは、78 個のサンプルのうち 29 個を testPrimes() 内で取得したことがわかります。合計コストの列は、サンプル数をパーセント値に置き換えたものです: (29/78) * 100 = 37.17

+ +

ところが時間コストは、ともに 0 です。これは、そのスタックフレームのコードを実行している間に取得したサンプルがないためです。サンプルはすべて、関数内にネストしているブロックまたは testPrimes() が呼び出した関数の内部で取得したものです。これは次の行でわかります:

+ +

+ +

この行も testPrimes という名称です。これは 19 行目から始まる for ループが作成した、testPrimes() の新たなスタックフレームを指しています。前のフレームのコストが 0 であったことから予想されるとおり、このフレームのサンプル列も 29 です。

+ +

しかし、コスト時間は 0 ではありません。これはいくつかのサンプルが、このフレームを実行しているときに取得されたことを表します。プロファイルではサンプルをいくつ取得したかを明示していませんが、次の timedIsPrime という名前の行で取得したサンプルが 24 個であることから、5 個取得したはずです。これは簡単に確認できます。(5/78) * 100 = 6.41 であり、コストの値と一致します。

+ +

この分岐で残る 24 個のサンプル (全体の 30.76%) は timedIsPrime() で取得されました。つまり、setTimeout() (12 行目) を呼び出している部分です。

+ +

コールツリーの別の分岐は、setTimeout() (13 行目) に渡した無名のコールバック関数から始まっています。ここではサンプルを 1 個取得しており、残り 48 個のサンプル (全体の 61.53%) はコールバックで呼び出す isPrime() で取得されました。

+ +

総括すると、もっとも多くのサンプルを isPrime() で取得しており (全体の 61.53%)、その次が timedIsPrime() (全体の 30.76%)、残りは取るに足らない量です。統計的に言えば、おそらくこれらの関数がほとんどの時間を消費していますので、プログラムを高速化したい場合の有力な最適化候補になります。

+ +

合計時間時間

+ +

合計時間時間の列は合計コストコストから算出していますが、直接反映したものではありません。規則的にサンプルを取得しようとしていますが、そのとおりに取得できない場合もあります。適切な時期にサンプルを取得できなかった場合は、その不規則性を補正しようとします。

+ +

呼び出しツリーを反転

+ +

既定では、プロファイラは一般的なコールスタックと同様に、呼び出しツリーを根から葉の順に表示します。つまりそれぞれのトップレベル関数、トップレベル関数が呼び出す関数、その関数から呼び出される関数、といった順になります:

+ +
testPrimes
+
+  -> timedIsPrime
+
+
+
+(setTimeout callback)
+
+  -> isPrime
+ +

これは論理的かつスタックが積み上げられる時系列に従っており、コールスタックを表現するための慣習的な方法でもあります。一方、時間がかかっている場所が呼び出しツリーの深部にあることがよくあります。前出の例でわかるとおり、全サンプルの 90% は 2 つの主要な分岐の終端で発生しています。

+ +

多くのサンプルを記録したスタックフレームに注目させるため、呼び出しツリーを反転させるオプションがプロファイラにあります。このオプションを選択すると、プロファイラは以下のようになります:

+ + + +

例えば testPrimes の例を、既定の表示でもう一度示します:

+ +

+ +

呼び出しツリーを反転すると以下のようになります:

+ +

+ +

反転した表示では、プログラムで時間がかかっている場所を効果的に目立たせていることがわかるでしょう。

diff --git a/files/ja/tools/performance/scenarios/animating_css_properties/index.html b/files/ja/tools/performance/scenarios/animating_css_properties/index.html new file mode 100644 index 0000000000..106a08aecc --- /dev/null +++ b/files/ja/tools/performance/scenarios/animating_css_properties/index.html @@ -0,0 +1,156 @@ +--- +title: CSS プロパティのアニメーション +slug: Tools/Performance/Scenarios/Animating_CSS_properties +translation_of: Tools/Performance/Scenarios/Animating_CSS_properties +--- +
{{ToolsSidebar}}
+

CSS プロパティのアニメーションにかかるパフォーマンスのコストは、プロパティにより異なります。また、高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために jank が発生する場合があります。

+ +

フレームレートウォーターフォールは CSS アニメーションにおいてブラウザが何を行っているかを明らかにして、パフォーマンスの問題の診断を支援します。

+
+ +

CSS アニメーションでは複数のキーフレームを指定して、それぞれのキーフレームではアニメーションの特定の段階における要素の外見を定義するために CSS を使用します。ブラウザは、それぞれのキーフレームから次のキーフレームへ遷移することでアニメーションを作成します。

+ +

JavaScript を使用して要素のアニメーションを行うのに比べて、CSS アニメーションは簡単に作れます。またブラウザはいつフレームを描画するかをより制御でき、また必要に応じてフレームを破棄できますので、パフォーマンスが高くなります。

+ +

しかし CSS プロパティを変更するためのパフォーマンスコストは、プロパティにより異なります。高コストな CSS プロパティのアニメーションは、ブラウザがスムーズなフレームレートを確保しようと努力するために jank が発生する場合があります。

+ +

CSS レンダリングのウォーターフォール

+ +

CSS が変更されたときにブラウザがページを更新するためのプロセスは、以下のステップで構成されるウォーターフォールで説明できます:

+ +

+ +
    +
  1. スタイルを再計算: 要素の CSS プロパティが変更されるたびに、ブラウザは算出スタイルを再計算しなければなりません。
  2. +
  3. レイアウト: 続いて、要素の位置や形状を計算するために算出スタイルを使用します。この操作は "レイアウト" と名付けられていますが、"リフロー" とも呼ばれます。
  4. +
  5. 描画: そして、ブラウザはスクリーンに要素を再描画しなければなりません。最後のステップはこの流れで示していません。ページは複数のレイヤーに分割され、それぞれを独立して描画した後に、"コンポジション" と呼ばれるプロセスで合成されます。
  6. +
+ +

この流れが完了しなければスクリーンを更新できませんので、ひとつのフレーム内に一連の操作を収めなければなりません。毎秒 60 フレームが、アニメーションがスムーズに見えるレートとして広く受け入れられています。毎秒 60 フレームのレートのために、ブラウザが一連の操作を実行する時間として 16.7 ミリ秒が与えられます。

+ +

CSS プロパティのコスト

+ +

レンダリングのウォーターフォールにおいて、一部のプロパティは他のプロパティに比べて特にコストが高くなります:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
プロパティの種類コスト
要素の形状位置に影響を与えるプロパティ。これらはスタイルの再計算、レイアウト、再描画を発生させる。 +

left
+ max-width
+ border-width
+ margin-left
+ font-size

+
+

形状や位置への影響はないが、個別のレイヤーでは描画されないプロパティ。レイアウトは発生しない。

+
+

color

+
個別のレイヤーで描画されるプロパティは、再描画が発生しない。更新はコンポジションで制御される。 transform
+ opacity
+ +
+

CSS Triggers の Web サイトで、各 CSS プロパティでどれだけのウォーターフォールが発生するかをまとめています。WebKit 固有の情報ですが、ほとんどはすべての最新ブラウザで同じです。

+
+ +

例: margin と transform

+ +

本章では、ウォーターフォールmargin を使用したアニメーションと transform を使用したアニメーションの違いを、どのように明らかにできるかを示します。

+ +

このシナリオは、margin を使用したアニメーションは例外なく悪いアイデアであると納得させる意図はありません。サイトを描画するためにブラウザが何を行っているかをツールがどのようにして明らかにするか、およびパフォーマンスの問題の診断や解決のためにその情報をどのように適用できるかを示すものです。

+ +

自身でも試してみたい場合は、デモ Web サイトがこちらにあります。サンプルは以下のようなものです:

+ +

ここには 2 つのコントロールがあります。アニメーションを開始/停止するボタンと、margin のアニメーションまたは transform のアニメーションを選択するラジオボタンです。

+ +

ページ上には複数の要素を置いており、それらに linear-gradient の背景と box-shadow を追加しています。これは、双方のプロパティは描画のコストが比較的高いためです。

+ +

動画版のウォークスルーも用意しています:

+ +

{{EmbedYouTube("Tvu6_j8Qzfk")}}

+ +

margin を使用したアニメーション

+ +

"Use margin" を選択したままでアニメーションを開始して、パフォーマンスツールを開いて記録を始めましょう。記録時間は数秒だけでかまいません。

+ +

最初の記録を開きます。どのような結果になるかはマシンやシステム負荷に大きく依存しますが、おそらく以下のようになるでしょう:

+ +

+ +

ここでは 3 つの視点で示しています: (a) ウォーターフォールの概要、(b) フレームレート、(c) タイムラインの詳細 です。

+ +

ウォーターフォールの概要

+ +

+ +

これは、ウォーターフォールをコンパクトに表示したビューです。

+ +

緑色が圧倒的に多いことは、描画に多くの時間を費やしていることを示しています。

+ +

 

+ +

フレームレート

+ +

+ +

これは、フレームレートを表示します。ここでは平均フレームレートが 46.67fps であり、目標の 60fps をかなり下回っています。さらに悪いことにフレームレートが何度も 10 から 20 fps 台に低下しており、グラフがぎざぎざになっています。特にユーザとの対話が加わると、スムーズなアニメーションではなくなるでしょう。

+ +

ウォーターフォール

+ +

記録表示領域の残りの部分で、ウォーターフォールを表示します。ウォーターフォールをスクロールすると、以下のようなパターンが見られるでしょう:

+ +

+ +

これはレンダリングのウォーターフォールを表します。それぞれのアニメーションフレームで、すべての要素のスタイルを再計算してからレイアウト処理を 1 回実施して、再描画を行います。

+ +

ここでは、描画が特にパフォーマンスへ悪影響を与えていることがわかります。前出のスクリーンショットでは描画処理をハイライトしており、この処理は 13.11 ミリ秒かかっていることが右側のボックスでわかります。すべての処理に割り当てられた時間は 16.7 ミリ秒しかありませんので、高いフレームレートを維持できないのは驚くことではありません。

+ +

ここでインスペクタを使用して box-shadow を削除すると、描画時間にどのような影響があるかを実験できます。しかし次は、margin の代わりに transform を使用して高コストな描画を完全になくす方法を見ていきます。

+ +

transform を使用したアニメーション

+ +

Web ページのラジオボタンを "Use transform" に切り替えて、新たに記録してみましょう。すると、以下のようになるでしょう:

+ +

+ +

ウォーターフォールの概要

+ +

+ +

margin を使用した場合と比べて緑色がとても少なく、また桃色がとても多くなっています。桃色はレイアウトやスタイルの再計算でしょう。

+ +

フレームレート

+ +

+ +

margin を使用した場合と比べて、良好であるように見えます。平均値は 60fps に近く、また開始付近で 1 回落ち込んでいることを除けば高いフレームレートを維持しています。

+ +

ウォーターフォール

+ +

タイムラインビューで、フレームレートが向上した理由が示されています。margin を使用した場合と比べて、レイアウトや (この例ではさらに重要な) 描画に少しも時間を費やしていません:

+ +

+ +

この例では transform を使用することでサイトのパフォーマンスが著しく向上しており、またどのようにおよびなぜ向上したかを、パフォーマンスツールで示すことができました。

diff --git a/files/ja/tools/performance/scenarios/index.html b/files/ja/tools/performance/scenarios/index.html new file mode 100644 index 0000000000..0b1a33b018 --- /dev/null +++ b/files/ja/tools/performance/scenarios/index.html @@ -0,0 +1,10 @@ +--- +title: シナリオ +slug: Tools/Performance/Scenarios +tags: + - TopicStub +translation_of: Tools/Performance/Scenarios +--- +
{{ToolsSidebar}}
+ +

パフォーマンスシナリオ

diff --git a/files/ja/tools/performance/scenarios/intensive_javascript/index.html b/files/ja/tools/performance/scenarios/intensive_javascript/index.html new file mode 100644 index 0000000000..34cc1db672 --- /dev/null +++ b/files/ja/tools/performance/scenarios/intensive_javascript/index.html @@ -0,0 +1,231 @@ +--- +title: 集約的な JavaScript +slug: Tools/Performance/Scenarios/Intensive_JavaScript +translation_of: Tools/Performance/Scenarios/Intensive_JavaScript +--- +
{{ToolsSidebar}}
+

デフォルトでブラウザはレイアウト、リフロー、ガベージコレクションだけでなく、ページ内のすべての JavaScript もひとつのスレッドで実行します。これは長い間実行する JavaScript がスレッドをブロックして、ページの不応答やユーザエクスペリエンスの悪化を招くおそれがあるということです。

+ +

フレームレートおよびウォーターフォールツールを使用して、いつ JavaScript がパフォーマンスの問題を起こしているかを知る、および特に注意が必要な関数を選び出すことができます。

+ +

本記事では長い間実行する JavaScript が応答性の問題を起こしているサンプルサイトを使用して、問題を修正するために 2 種類の方法を適用していきます。ひとつは長い間実行する JavaScript を複数の部品に分けて、それらのスケジューリングに requestAnimationFrame を使用する方法、もうひとつは web worker を使用して関数全体を別のスレッドに分ける方法です。

+
+ +

自身でも試してみたい場合は、デモ Web サイトがこちらにあります。

+ +

動画版のウォークスルーも用意しています:

+ +

{{EmbedYouTube("Pcc6jQX6JDI")}}

+ +

デモ Web サイトは以下のようなものです:

+ +

ここには 3 つのコントロールがあります:

+ + + +

ラジオボタンで "Use blocking call in main thread" を選択して、記録を始めましょう:

+ + + +

どのような結果になるかはマシンにより異なりますが、おそらく以下のようになるでしょう:

+ +

+ +

この画像の上半分はウォーターフォールの概要です。これはウォーターフォールをコンパクトに表示したビューであり、記録中にブラウザが行った処理は何かを示します。桃色はほとんどの場合 CSS の再計算、一部はリフローです。これは、プロファイルで終始実行している CSS アニメーションです。また連続したの橙色のブロックが 3 つありますが、これは JavaScript を実行していることを表します。それぞれ、ボタンを押したときです。

+ +

下半分はタイムラインの概要と時系列が合わせられており、フレームレートを示しています。記録中のほとんどはフレームレートが良好ですが、ボタンを押すたびに大きく落ち込んでいます。

+ +

それら 3 か所のうちひとつを選択して、メインのウォーターフォールビューで詳しく見ることができます:

+ +

+ +

ここではボタンを押したときに、ブラウザが JavaScript の関数をひとつまたは連続的に実行して、メインスレッドを 71.73 ミリ秒、言い換えるとフレーム 4 つ分の時間ブロックしています。

+ +

どの関数でしょう? フレームチャートビューに切り替えると、それがわかります:

+ +

+ +

これは、その時点で実行している JS のコールスタックを表示します。スタックの一番上は calculatePrimes() という関数であり、ファイル名や行番号がわかります。以下に掲載したコードで、直近の呼び出し元を見てみましょう:

+ +
const iterations = 50;
+const multiplier = 1000000000;
+
+function calculatePrimes(iterations, multiplier) {
+  var primes = [];
+  for (var i = 0; i < iterations; i++) {
+    var candidate = i * (multiplier * Math.random());
+    var isPrime = true;
+    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
+      if (candidate % c === 0) {
+          // not prime
+          isPrime = false;
+          break;
+       }
+    }
+    if (isPrime) {
+      primes.push(candidate);
+    }
+  }
+  return primes;
+}
+
+function doPointlessComputationsWithBlocking() {
+  var primes = calculatePrimes(iterations, multiplier);
+  pointlessComputationsButton.disabled = false;
+  console.log(primes);
+}
+
+ +

ここではかなり大きな数に対して、(とても非効率な) 素数の判定を 50 回行っています。

+ +

requestAnimationFrame を使用する

+ +

この問題を解決するための最初の試みとして、関数をいくつかの自己充足した小さな関数に分割して、requestAnimationFrame() を使用してそれらをスケジューリングします。

+ +

requestAnimationFrame() は与えられた関数を、各フレームで再描画を行う直前に実行するようブラウザに指示します。それぞれの関数が適度に小さければ、ブラウザは実行時間を、フレーム間に与えられた時間内に収めることができるでしょう。

+ +

calculatePrimes() の分割はとてもシンプルです。別の関数で、それぞれの値が素数であるかの計算を行います:

+ +
function doPointlessComputationsWithRequestAnimationFrame() {
+
+  function testCandidate(index) {
+    // finishing condition
+    if (index == iterations) {
+      console.log(primes);
+      pointlessComputationsButton.disabled = false;
+      return;
+    }
+    // test this number
+    var candidate = index * (multiplier * Math.random());
+    var isPrime = true;
+    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
+      if (candidate % c === 0) {
+          // not prime
+          isPrime = false;
+          break;
+       }
+    }
+    if (isPrime) {
+      primes.push(candidate);
+    }
+    // schedule the next
+    var testFunction = testCandidate.bind(this, index + 1);
+    window.requestAnimationFrame(testFunction);
+  }
+
+  var primes = [];
+  var testFunction = testCandidate.bind(this, 0);
+  window.requestAnimationFrame(testFunction);
+}
+ +

こちらのバージョンを試してみましょう。"Use requestAnimationFrame" と記載されたラジオボタンを選択して、新たにプロファイルを記録します。すると、記録は以下のようになるでしょう:

+ +

+ +

これはまさに、私たちが期待していたものです。一続きの橙色のブロックに代わり、ボタンを押すたびにとても短い橙色のブロックがたくさん並んでいます。橙色のブロックは 1 個ずつのフレームに分かれて現れており、またそれぞれのブロックが、requestAnimationFrame() から呼び出された関数 1 個を表しています。なお、このプロファイルではボタンを 2 回しか押していないことに注意してください。

+ +

関数の呼び出しは CSS アニメーションに由来する桃色のブロックの間に挟み込まれており、またそれぞれの関数は、全体のフレームレートを落とすことなく処理できるほど十分に小さくなっています。

+ +

ここでは requestAnimationFrame が応答性の問題の解決策として機能しましたが、潜在的な問題点が 2 つあります:

+ + + +

Web Worker を使用する

+ +

ここでは、Web Worker を使用して問題を解決します。Web Worker を使用すると、別のスレッドで JavaScript を実行できます。メインスレッドと Worker スレッドは互いに直接呼び出すことはできませんが、非同期メッセージ API を使用して通信できます。

+ +

メインスレッドのコードは以下のようになります:

+ +
const iterations = 50;
+const multiplier = 1000000000;
+
+var worker = new Worker("js/calculate.js");
+
+function doPointlessComputationsInWorker() {
+
+  function handleWorkerCompletion(message) {
+    if (message.data.command == "done") {
+      pointlessComputationsButton.disabled = false;
+      console.log(message.data.primes);
+      worker.removeEventListener("message", handleWorkerCompletion);
+    }
+  }
+
+  worker.addEventListener("message", handleWorkerCompletion, false);
+
+  worker.postMessage({
+    "multiplier": multiplier,
+    "iterations": iterations
+  });
+}
+ +

元のコードと比べたときの主な違いは、以下のものが必要であることです:

+ + + +

また、新たに "calculate.js" ファイルが必要であり、こちらは以下のようになります:

+ +
self.addEventListener("message", go);
+
+function go(message) {
+  var iterations = message.data.iterations;
+  var multiplier = message.data.multiplier;
+  primes = calculatePrimes(iterations, multiplier);
+
+  self.postMessage({
+    "command":"done",
+    "primes": primes
+  });
+}
+
+function calculatePrimes(iterations, multiplier) {
+  var primes = [];
+  for (var i = 0; i < iterations; i++) {
+    var candidate = i * (multiplier * Math.random());
+    var isPrime = true;
+    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
+      if (candidate % c === 0) {
+          // not prime
+          isPrime = false;
+          break;
+       }
+    }
+    if (isPrime) {
+      primes.push(candidate);
+    }
+  }
+  return primes;
+}
+ +

Worker では処理の開始を指示するメッセージをリッスンする、および処理が完了したときに "done" メッセージを送ることが必要です。実際に計算を行っている部分のコードは、最初のバージョンのコードと完全に同じです。

+ +

このバージョンはどのように実行されるのでしょう? ラジオボタンを "Use a worker" に切り替えて、新たにプロファイルを記録してください。結果は以下のようになるでしょう:

+ +

+ +

このプロファイルでは、ボタンを 3 回押しています。ウォーターフォールの概要で元のバージョンと比べると、ボタンを押したときにはとても短い橙色のマーカーが 2 個あることがわかります:

+ + + +

これら 2 つの関数の間で Worker は素数の判定を行っていますが、メインスレッドの応答性には少しも影響を与えていないように見受けられます。これはあり得ないと思うかもしれませんが、Worker は別のスレッドで実行しますのでマルチコアプロセッサの利点を享受できます。これはシングルスレッドの Web サイトでは得られません。

+ +

Web Worker の主な制限は、Worker で実行するコードでは DOM API を使用できないことです。

diff --git a/files/ja/tools/performance/ui_tour/index.html b/files/ja/tools/performance/ui_tour/index.html new file mode 100644 index 0000000000..ed58a0c021 --- /dev/null +++ b/files/ja/tools/performance/ui_tour/index.html @@ -0,0 +1,125 @@ +--- +title: UI ツアー +slug: Tools/Performance/UI_Tour +translation_of: Tools/Performance/UI_Tour +--- +
{{ToolsSidebar}}

パフォーマンスツールの UI は、大きく 4 つに分けられます:

+ +

+ + + +

ツールバー

+ +

ツールバーには、以下のボタンがあります:

+ + + +

+ +

記録ペイン

+ +

記録ペインでは、現在のセッションで取得した記録やインポートした記録を含む、読み込み済みの全記録を一覧表示します。

+ +

+ +

いつでも記録を選択すると、その記録の情報を他のペインに表示します。記録ペインで別の項目をクリックすると、その記録を選択できます。"保存" をクリックすると、記録を JSON ファイルとして保存できます。

+ +

記録の概要

+ +

ここでは、X 軸を時間として記録全体の概要を表示します。

+ +

+ +

ここにはタイムラインの概要とフレームレートのグラフという、2 つの要素があります。

+ +

タイムラインの概要

+ +

ここでは、タイムラインをコンパクトに表示したビューを提供します:

+ +

+ +

記録した処理は、タイムラインビューと同じ方式で色分けされます。

+ +

フレームレートのグラフ

+ +

フレームレートは、記録している間のブラウザの応答性を概観します:

+ +

+ +

フレームレートの個別記事をご覧ください。

+ +

イベントを関連づける

+ +

複数の要素が同期しているため、ある要素のイベントと別の要素のイベントに関連性を見いだせる場合があります。

+ +

例えば以下のスクリーンショットでは、長時間の描画操作 (タイムラインの概要では緑色のバーで表示) とフレームレートの落ち込みに関連性があります:

+ +

+ +

拡大

+ +

記録を詳しく調査するため、概要ビューで記録の一部分を選択できます。一部分を選択すると、その部分だけを含むようにメインビューを更新します。以下のスクリーンショットではフレームレートが落ち込んだ部分を選択して、長時間の描画操作を詳しく見ています:

+ +

+ +

詳細ペイン

+ +

詳細ペインでは、選択したツールの情報を表示します。ツールを切り替えるには、ツールバーのボタンを使用してください。

+ +

タイムライン

+ +

タイムラインでは、記録中にブラウザが実行した操作 (JavaScript を実行、CSS を更新、ページのレイアウトを更新、再描画を実行など) を表示します。X 軸は時間を表し、記録した操作を滝のように、またブラウザが実行した操作の連続性を反映するように配置します。

+ +

+ +

タイムラインについて詳しくは、タイムラインのページをご覧ください。

+ +

呼び出しツリー

+ +

呼び出しツリーは、ページで実行している JavaScript のサンプリングプロファイラです。これは JavaScript エンジンの状態を定期的にサンプリングして、その時点のコード実行のスタックを記録します。統計的に、個々の関数を実行しているときに取得したサンプル数はブラウザが実行にかけた時間に対応しますので、コード内のボトルネックを発見できます。

+ +


+ 呼び出しツリーについて詳しくは、コールツリーのページをご覧ください。

+ +

フレームチャート

+ +

呼び出しツリーが記録中にサイトのどの関数で、もっとも多くの実行時間がかかったかを示すものであるなら、フレームチャートは実行中のある時点のコールスタックを示すものです:

+ +

+ +

フレームチャートについて詳しくは、フレームチャートのページをご覧ください。

+ +

メモリ割り当て

+ +
+

メモリ割り当てビューは、Firefox 46 の新機能です。

+
+ +

メモリ割り当てビューは呼び出しツリービューと似ていますが、こちらはメモリ割り当てに特化したビューです。プロファイルの中でページ内のどの関数がもっとも多くのメモリ割り当てを行ったかを表示します。

+ +

+ +

メモリ割り当てビューは、プロファイルを記録する前にパフォーマンスツールの設定で "メモリ割り当てを記録" にチェックを入れた場合に限り表示します:

+ +

{{EmbedYouTube("Le9tTo7bqts")}}

+ +

メモリ割り当てビューについて詳しくは、メモリ割り当てビューのページをご覧ください。

diff --git a/files/ja/tools/performance/waterfall/index.html b/files/ja/tools/performance/waterfall/index.html new file mode 100644 index 0000000000..738de4cd72 --- /dev/null +++ b/files/ja/tools/performance/waterfall/index.html @@ -0,0 +1,478 @@ +--- +title: タイムライン +slug: Tools/Performance/Waterfall +translation_of: Tools/Performance/Waterfall +--- +
{{ToolsSidebar}}
+

タイムラインは、サイトやアプリの実行でブラウザが行ったさまざまなことについて知見を得るものです。これは、サイトを実行するときにブラウザが行ったことはさまざまな種類 (JavaScript を実行、レイアウトを更新など) に分類でき、またある時点でブラウザはそれらのいずれかを行っているという考え方に基づいています。

+ +

よって、例えばフレームレートが落ち込むなどパフォーマンスの問題の兆候があるときはタイムラインを開いて、記録中のある時点でブラウザが何を行っていたかを知ることができます。

+
+ +

+ +

X 軸に沿って時間を表します。記録した操作はマーカーと呼び、ブラウザが実行した操作の連続性を反映する滝のような配置で、水平方向のバーとして表示します。

+ +

マーカーを選択すると、詳細情報を右側のサイドバーで表示します。そこではマーカーの長さや、マーカーの種類に特有の詳細情報を表示します。

+ +

マーカー

+ +

操作を示すマーカーは、色分けおよび名前付けされています。以下の操作を記録します:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名称および説明詳細情報
+

DOM イベント

+ +

DOM イベントへの応答として実行する JavaScript コード。

+
+
+
イベント種別
+
例えば "click" や "message" など。
+
+ +
+
フェーズ
+
例えば "ターゲット" や "キャプチャ" など。
+
+
+

ページ内で実行される JavaScript 関数は、関数が呼び出された理由に応じて名前付けします:

+ +

Script Tag
+ setInterval
+ setTimeout
+ requestAnimationFrame
+ Promise Callback
+ Promise Init
+ Worker
+ JavaScript URI
+ Event Handler

+
+
+
スタック
+
関数につながるコールスタック。
+
+
+

HTML パース

+ +

ページの HTML をパースするために費やした時間。

+
+
+
スタック
+
関数につながるコールスタック。
+
+
+

XML パース

+ +

ページの XML をパースするために費やした時間。

+
+
+
スタック
+
関数につながるコールスタック。
+
+
+

CSS 再計算

+ +

ページの要素に適用する算出スタイルを算出する。

+
+
+
CSS 再計算のヒント
+
どのようなスタイル再適用が必要かを示す文字列。以下のいずれかを手がかりとして提示します:
+ Self
+ Subtree
+ LaterSiblings
+ CSSTransitions
+ CSSAnimations
+ SVGAttrAnimations
+ StyleAttribute
+ StyleAttribute_Animations
+ Force
+ ForceDescendants
+
+
+

レイアウト

+ +

ページの要素の位置やサイズを計算する。この操作は、"リフロー" と呼ばれることがあります。

+
 
+

描画

+ +

スクリーンにピクセルを描画する。

+
 
+

ガベージコレクション

+ +

ガベージコレクションイベント。ノンインクリメンタル GC イベントには "(非インクリメンタル)" を付加する。

+
+
+
発生源
+
GC を実行した理由を示す文字列。
+
非インクリメンタル GC の発生源
+
GC がインクリメンタルではない場合に、ノンインクリメンタル GC を実行した理由を示す文字列を表示。
+
+ +
+

Firefox 46 の新機能: GC イベントがメモリ割り当ての圧力によって発生した場合は、"Show Allocation Triggers" というリンクを表示します。このリンクをクリックすると、GC イベントの原因になったメモリ割り当てのプロファイルを表示します。

+ +

詳しくはメモリ割り当てとガベージコレクションをご覧ください。

+
+
+

サイクルコレクション

+ +

C++ の参照カウントを持つデータ構造を回収します。

+ +

ガベージコレクションに似ていますが、こちらは C++ のオブジェクト向けです。Kyle Huey のサイクルコレクションに関するブログ記事をご覧ください。

+
+
+
種別
+
常に "Collect" になります。
+
+
+

CC グラフ削減

+ +

サイクルコレクションの準備や事前の最適化です。

+
+
+
種別
+
常に "ForgetSkippable" になります。
+
+
+

コンソール

+ +

console.time() および console.timeEnd() を呼び出した間の時間に合致する。

+
+
+
タイマー名
+
console に渡した引数。
+
スタック開始
+
関数につながるコールスタック console.time()
+
スタック終了
+
(Firefox 41 の新機能) console.timeEnd() 時点のコールスタック。Promise 由来のコールバック内にある場合は、"Async stack" とも表示します。
+
+
+

タイムスタンプ

+ +

console.timeStamp() を 1 回呼び出す。

+
+
+
Label
+
timeStamp() に渡した引数。
+
+
+

DOMContentLoaded

+ +

ドキュメントの DOMContentLoaded イベント。

+
 
+

Load

+ +

ドキュメントの load イベント。

+
 
+

メインスレッドの Worker イベント

+ +

メインスレッドが Worker にメッセージを送信したとき、または Worker からメッセージを受け取ったときに表示します。

+
+

以下のいずれか:

+ +
+
メインスレッドでデータをシリアライズ
+
メインスレッドは、Worker に送信するメッセージをシリアライズします。
+
メインスレッドでデータをデシリアライズ
+
メインスレッドは、Worker から受け取ったメッセージをデシリアライズします。
+
+
+

Worker スレッドの Worker イベント

+ +

Worker がメインスレッドからメッセージを受け取ったとき、またはメインスレッドにメッセージを送信したときに表示します。

+
+

以下のいずれか:

+ +
+
Worker でデータをシリアライズ
+
Worker は、メインスレッドに送信するメッセージをシリアライズします。
+
Worker でデータをデシリアライズ
+
Worker は、メインスレッドから受け取ったメッセージをデシリアライズします。
+
+
+ +

マーカーとその色はタイムラインツールとタイムラインの概要で同じであり、双方を関連づけることが容易になります。

+ +

マーカーのフィルタリング

+ +

ツールバーのボタンを使用して、表示するマーカーを制御できます:

+ +

+ +

タイムラインのパターン

+ +

タイムラインがどう見えるかは、サイトで行っていることの種類に強く依存します。JavaScript を多く使用するサイトでは橙色が多く表示され、視覚的に動的なサイトでは紫色や緑色が多くなるでしょう。それでもパフォーマンスの問題がある可能性を警告する、一般的なパターンがあります。

+ +

タイムラインの描画

+ +

タイムラインビューでよく見るパターンは、以下のようなものです:

+ +

+ +

これは、ブラウザがイベントへの応答としてページの更新を行うときの基本的なアルゴリズムを視覚しています:

+ +
    +
  1. JavaScript 関数呼び出し: DOM イベントなどのイベントが、ページ内の JavaScript を実行します。JavaScript は、ページの DOM や CSSOM を変更します。
  2. +
  3. スタイルを再計算: ページの要素の算出スタイルが変化したとブラウザが判断した場合は、それらを再計算しなければなりません。
  4. +
  5. レイアウト: 続いて、要素の位置や形状を計算するために算出スタイルを使用します。この操作は "レイアウト" と名付けられていますが、"リフロー" とも呼ばれます。
  6. +
  7. 描画: そして、ブラウザはスクリーンに要素を再描画しなければなりません。最後のステップはこの流れで示していません。ページは複数のレイヤーに分割され、それぞれを独立して描画した後に、"コンポジション" と呼ばれるプロセスで合成されます。
  8. +
+ +

この流れが完了しなければスクリーンを更新できませんので、ひとつのフレーム内に一連の操作を収めなければなりません。毎秒 60 フレームが、アニメーションがスムーズに見えるレートとして広く受け入れられています。毎秒 60 フレームのレートのために、ブラウザが一連の操作を実行する時間として 16.7 ミリ秒が与えられます。

+ +

応答性のために重要なこととして、ブラウザは必ずしもすべてのステップを通らなければならないわけではありません:

+ + + +

CSS プロパティのアニメーションの記事では、さまざまな CSS プロパティのアニメーションによるパフォーマンスの違いを示すとともに、タイムラインがそれらをどのように知らせるかを説明します。

+ +

妨害する JavaScript

+ +

デフォルトで JavaScript を実行するスレッドは、ブラウザがレイアウトの更新、再描画、DOM イベントなどに使用するスレッドと同じです。これは、長い間実行する JavaScript 関数が不応答性 (jank) を引き起こす可能性があるということです。アニメーションがぎこちない、あるいはサイトがフリーズするでしょう。

+ +

フレームレートツールとタイムラインを組み合わせると、長い間実行する JavaScript が応答性の問題を引き起こしていることが簡単にわかります。以下のスクリーンショットでは、フレームレートの落ち込みを引き起こしている JS 関数を拡大表示しています:

+ +

+ +

集約的な JavaScript の記事では、長大な JavaScript 関数によって引き起こされる応答性の問題をタイムラインがどのように目立たせるか、またメインスレッドの応答性を維持するために非同期メソッドをどのように使用できるかを説明します。

+ +

高コストな描画

+ +

box-shadow など負担が大きい描画効果があり、特に毎フレーム計算が必要なトランジションに適用した場合に顕著です。特に、グラフィックを集中的に扱う操作でフレームレートの落ち込みがみられる場合は、タイムラインで緑色のマーカーがないか確認してください。

+ +

ガベージコレクション

+ +

タイムラインで赤色のマーカーはガベージコレクション (GC) のイベントを表しており、このとき SpiderMonkey (Firefox の JavaScript エンジン) は到達不能なメモリを探すためにヒープを確認して、そのようなメモリを解放します。GC を実行している間は JavaScript エンジンを一時停止しなければならないので、プログラムが休止して完全に応答しない状態になるため、GC はパフォーマンスと関係性があります。

+ +

一時停止する時間を短縮するため、SpiderMonkey はインクリメンタル GC を実装しています。これはガベージコレクションを少しずつ実行でき、合間にプログラムを実行することが可能になります。それでも時にはノンインクリメンタルガベージコレクションが必要であり、この場合プログラムは完了するまで待たなければなりません。

+ + + +

GC イベント、特にノンインクリメンタル GC イベントを避けようとして、特定の JavaScript エンジンの実装に最適化しようとすることは賢くありません。SpiderMonkey は GC がいつ必要か、および特にノンインクリメンタル GC がいつ必要かを検出するために、複雑に組み合わせた発見方法を使用しています。ただし、一般に以下のことが言えます:

+ + + +

タイムラインで GC マーカーを記録するときは、以下の情報を示します:

+ + + +

console API でマーカーを追加する

+ +

console API を呼び出すことで直接制御できるマーカーが 2 つあります。"コンソール" と "Timestamp" です。

+ +

コンソールマーカー

+ +

これは、記録内の特定のセクションにマークをつけるものです。

+ +

コンソールマーカーを作成するにはセクションの始めで console.time() を、セクションの終わりで console.timeEnd() を呼び出します。これらの関数は、セクションの名前として使用される引数を取ります。

+ +

例えば、以下のようなコードで考えてみましょう:

+ +
var iterations = 70;
+var multiplier = 1000000000;
+
+function calculatePrimes() {
+
+  console.time("calculating...");
+
+  var primes = [];
+  for (var i = 0; i < iterations; i++) {
+    var candidate = i * (multiplier * Math.random());
+    var isPrime = true;
+    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
+      if (candidate % c === 0) {
+          // not prime
+          isPrime = false;
+          break;
+       }
+    }
+    if (isPrime) {
+      primes.push(candidate);
+    }
+  }
+
+  console.timeEnd("calculating...");
+
+  return primes;
+}
+ +

タイムラインの出力は、以下のようになります:

+ +

+ +

マーカーは console.time() に渡した引数で名付けられており、マーカーを選択すると右側のサイドバーでプログラムスタックを確認できます。

+ +

Async stack

+ +

Firefox 41 の新機能

+ +

Firefox 41 より、右側のサイドバーに終了時点、すなわち console.timeEnd() を呼び出した時点のスタックも表示します。console.timeEnd()Promise の成功によって呼び出された場合は、"(非同期: Promise)" と表示します。これは "async stack" を表すものであり、その時点のコールスタックで promise が生成されています。

+ +

例えば、以下のコードで考えてみましょう:

+ +
var timerButton = document.getElementById("timer");
+timerButton.addEventListener("click", handleClick, false);
+
+function handleClick() {
+  console.time("timer");
+  runTimer(1000).then(timerFinished);
+}
+
+function timerFinished() {
+  console.timeEnd("timer");
+  console.log("ready!");
+}
+
+function runTimer(t) {
+  return new Promise(function(resolve) {
+    setTimeout(resolve, t);
+  });
+}
+ +

タイムラインでは time()timeEnd() の間をマーカーで表示します。このマーカーを選択すると、サイドバーに async stack が表示されるでしょう:

+ +

+ +

Timestamp マーカー

+ +

タイムスタンプで、記録中にその場でマークすることができます。

+ +

タイムスタンプマーカーを作成するには、console.timeStamp() を呼び出します。タイムスタンプのラベルを引数として渡すことができます。

+ +

例えば前出のコードで繰り返し 10 回ごとにタイムスタンプを生成して、繰り返し回数を名前として付加します:

+ +
var iterations = 70;
+var multiplier = 1000000000;
+
+function calculatePrimes() {
+  console.time("calculating...");
+
+  var primes = [];
+  for (var i = 0; i < iterations; i++) {
+
+    if (i % 10 == 0) {
+      console.timeStamp(i.toString());
+    }
+
+    var candidate = i * (multiplier * Math.random());
+    var isPrime = true;
+    for (var c = 2; c <= Math.sqrt(candidate); ++c) {
+      if (candidate % c === 0) {
+          // not prime
+          isPrime = false;
+          break;
+       }
+    }
+    if (isPrime) {
+      primes.push(candidate);
+    }
+  }
+  console.timeEnd("calculating...");
+  return primes;
+}
+ +

タイムラインは以下のようになります:

+ +

-- cgit v1.2.3-54-g00ecf