From 6ef1fa4618e08426b874529619a66adbd3d1fcf0 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:07:59 +0100 Subject: unslug ja: move --- .../tools/performance/call_tree/index.html | 114 ++++++++++++++++ files/ja/conflicting/tools/performance/index.html | 145 +++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 files/ja/conflicting/tools/performance/call_tree/index.html create mode 100644 files/ja/conflicting/tools/performance/index.html (limited to 'files/ja/conflicting/tools/performance') diff --git a/files/ja/conflicting/tools/performance/call_tree/index.html b/files/ja/conflicting/tools/performance/call_tree/index.html new file mode 100644 index 0000000000..858b944015 --- /dev/null +++ b/files/ja/conflicting/tools/performance/call_tree/index.html @@ -0,0 +1,114 @@ +--- +title: プロファイラのチュートリアル +slug: Tools/Performance/Profiler_walkthrough +translation_of: Tools/Performance/Call_Tree +translation_of_original: Tools/Performance/Profiler_walkthrough +--- +
{{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/conflicting/tools/performance/index.html b/files/ja/conflicting/tools/performance/index.html new file mode 100644 index 0000000000..c05f177c25 --- /dev/null +++ b/files/ja/conflicting/tools/performance/index.html @@ -0,0 +1,145 @@ +--- +title: JavaScript プロファイラ +slug: Tools/Profiler +tags: + - Debugging + - Firefox + - Guide + - Profiler + - Profiling + - Tools +translation_of: Tools/Performance +translation_of_original: Tools/Profiler +--- +
{{ToolsSidebar}}

プロファイラツールを使用して、JavaScript コードのボトルネックを見つけましょう。プロファイラは周期的に、サンプルについて現在の JavaScript コールスタックやコンパイルの統計情報を抽出します。

+ +

"Web 開発" メニューから "プロファイラ" を選択することで、プロファイラを起動できます。"Web 開発" メニューは、Linux や OS X では "ツール" メニューの配下に、Windows では "Firefox" メニューの直下にあります。

+ +

ツールボックスが開いて、プロファイラが選択されます。

+ +

サンプリング型プロファイラ

+ +

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

+ +
function doSomething() {
+  var x = getTheValue();
+  x = x + 1;                   // -> サンプル A
+  logTheValue(x);
+}
+
+function getTheValue() {
+  return 5;
+}
+
+function logTheValue(x) {
+ console.log(x);               // -> サンプル B、サンプル C
+}
+
+doSomething();
+ +

プロファイラをアクティブにしてこのプログラムを実行したら、実行時にプロファイラは上記のインラインコメントで示したように 3 つのサンプルを取得します。

+ +

これらはすべて doSomething() の内部から取得されますが、2 番目の 2 つは doSomething() から呼び出された logTheValue() 関数の内部です。よってプロファイルは、以下のように 3 つのスタックトレースで構成されます:

+ +
サンプル A: doSomething()
+サンプル B: doSomething() > logTheValue()
+サンプル C: doSomething() > logTheValue()
+ +

これは私たちに何も伝えられない不十分なデータであることが明らかですが、より多くのサンプルにより、logTheValue() がコード内のボトルネックであると断定できるかもしれません。

+ +

プロファイルの作成

+ +

プロファイラでストップウォッチのボタンをクリックして、サンプルの記録を始めます。プロファイラが記録を行っている間は、ストップウォッチのボタンがハイライトされます。ボタンを再度押すと記録を停止して、新たなプロファイルを保存します:

+ +

+ +

"終了" をクリックすると、新しいプロファイルが自動的に開きます:

+ +

+ +

このペインは 2 つのパーツに分かれています:

+ + + +

プロファイルの分析

+ +

プロファイルは 2 つのパーツに分かれています:

+ + + +

プロファイルのタイムライン

+ +

プロファイルのタイムラインは、プロファイル表示の上部を占めています:

+ +

横軸は時間、縦軸はサンプルにおけるコールスタックのサイズを表します。コールスタックは、サンプルを取得したときにアクティブであった関数の量を表します。

+ +

チャートで赤色のサンプルは、そのときにブラウザが応答していなかったことを示しており、ユーザはアニメーションや応答性が止まったことに気づいたかもしれません。プロファイルに赤色のサンプルがある場合は、そのコードをいくつかのイベントに分解することを検討したり、requestAnimationFrameWorker の使用について調べたりしましょう。

+ +

タイムラインでクリックアンドドラッグすることで、プロファイル内の特定の範囲を調査できます:

+ +

+ +

タイムラインの上に "サンプリング範囲 [AAA, BBB]" というラベルがついた、新たなボタンが現れます。そのボタンを押すとプロファイルがズームされて、そのタイムスライスの詳細なビューが下部に表示されます:

+ +


+

+ +

プロファイルの詳細

+ +

プロファイルの詳細は、プロファイル表示の下部を占めています:

+ +

始めに新しいサンプルを開くと、サンプルペインには上のスクリーンショットのように "(total)" という名前の行があります。"(total)" の隣にある三角印をクリックすると、サンプル内にあるすべてのトップレベル関数がリストアップされます。

+ +

+ +

実行時間は当該関数が現れたサンプルの総数を示し1、その後ろにプロファイル内で当該関数が現れた全サンプルのパーセント値があります。最上段の行はプロファイル全体で 2021 のサンプルがあることを表し、また 2 行目は 1914 サンプルすなわち全体の 94.7% が、detectImage() 関数内にいたことを表します。

+ +

滞在 は当該関数そのものを実行する間に取得したサンプル数を示しており、関数を呼び出しているときではありません。前出のシンプルな例では、doSomething()実行時間が 3 (サンプル A、B、C) ですが、滞在の値は 1 (サンプル A) になるでしょう。

+ +

3 列目は関数名およびファイル名と行数 (ローカルの関数) またはベースネームとドメイン名を表示します。灰色の関数はブラウザ組み込みの関数です。黒色の関数がページで読み込んだ JavaScript を表します。行にマウスポインタを乗せると、関数の識別名の右側に矢印が現れます: 矢印をクリックすると関数のソースを表示します。

+ +

コールツリーの展開

+ +

ある行で、この関数から呼び出された関数に滞在している間のサンプルが存在する場合 (すなわち、実行時間がその行の滞在より大きい場合) は、関数名の左側に三角印が表示され、コールツリーを展開できます。

+ +

前出のシンプルな例では、完全に展開したコールツリーは以下のようになります:

+ + + + + + + + + + + + + + + + + + + +
実行時間滞在 
3            100%1doSomething()
2              67%2logTheValue()
+ +

より実際的な例を見ましょう: 前出のスクリーンショットで、上から 2 行目を見ると detectImage() 関数の内部で 1914 サンプルかかっていることがわかります。しかし、そのすべては detectImage() から呼び出された関数でかかっています (滞在 セルが 0 です)。コールツリーを展開して、ほとんどのサンプルがかかっていたとき実際に実行していた関数は何かを明らかにできます:

+ +

+ +

これは、detectAtScale() を実際に実行しているときに 6 サンプル、getRect() の実行に 12 サンプルかかっていたことなどを表します。

+ +

脚注

+ +
    +
  1. 関数がさまざまなソースから複数回呼び出される場合、プロファイラの出力にも複数回現れます。よって、forEach など汎用的な関数はコールツリー内に複数回現れるでしょう。
  2. +
-- cgit v1.2.3-54-g00ecf