Oracle® Solaris Studio 12.4: パフォーマンスアナライザチュートリアル

印刷ビューの終了

更新: 2014 年 12 月
 
 

パフォーマンスアナライザを使用した lowfruit データの検査

このセクションでは、lowfruit サンプルコードから作成された実験のデータを調べる方法を示します。

  1. 前のセクションで作成した実験がまだ開いていない場合は、lowfruit ディレクトリからパフォーマンスアナライザを起動して、次のようにして実験をロードできます。

    % analyzer test.1.er

    実験が開いたら、パフォーマンスアナライザに「概要」画面が表示されます。

    image:メトリックを示す「概要」画面

    この実験では、「概要」には基本的に 100% の「ユーザー CPU 時間」が示されます。プログラムはシングルスレッドであり、その 1 つのスレッドは CPU の制約を受けます。実験は Oracle Solaris システムに記録され、「概要」には記録されたメトリックが 12 個表示されますが、「CPU 時間合計」のみがデフォルトで有効になっています。

    色付きのインジケータがあるメトリックは、Oracle Solaris によって定義された 10 個のマイクロステートで費やされた時間です。これらのメトリックには、さまざまな待ち時間のほかに、一緒にすると「CPU 時間合計」と等しくなる「ユーザー CPU 時間」、「システム CPU 時間」、および「トラップ CPU 時間」が含まれます。「スレッド合計時間」は、すべてのマイクロステートの合計です。

    Linux ではマイクロステートアカウンティングがサポートされないため、Linux マシンでは「CPU 時間合計」のみが記録されます。

    デフォルトでは、「包括的 CPU 合計時間」と「排他的 CPU 合計時間」の両方が選択されています。メトリックの包括的とは、そのメトリックが呼び出すすべての関数またはメソッドで集計されたメソッドを含む、その関数またはメソッドのメトリック値を指します。排他的とは、その関数またはメソッド内で集計されたメトリックのみを指します。

  2. 左側の「ビュー」ナビゲーションバージョンで「関数」ビューをクリックするか、メニューバーから「ビュー」>「関数」を使用して選択します。

    image:「関数」ビューには、アプリケーション内の関数のリストとそれぞれの関数のパフォーマンスメトリックが表示されます。

    「関数」ビューには、アプリケーション内の関数のリストがそれぞれの関数のパフォーマンスメトリックとともに表示されます。リストは、最初は各関数で使用された「排他的 CPU 合計時間」でソートされます。リストには、ターゲットアプリケーションのすべての関数とプログラムで使用するすべての共有オブジェクトが含まれています。最上位の関数 (もっともコストが高い関数) がデフォルトで選択されています。

    右側の「選択の詳細」ウィンドウには、選択した関数について記録されたすべてのメトリックが表示されます。

    関数リストの下にある「呼び出し元/呼び出し回数」パネルは、選択した関数に関する詳細情報を提供し、2 つのリストに分割されています。「呼び出し元」リストには選択した関数の呼び出し元が表示され、メトリック値は、その呼び出し元への関数の合計メトリックの属性を示しています。「呼び出し回数」リストは、選択した関数の呼び出し先を示し、呼び出し先の包括的メトリックが選択した関数の合計メトリックにどのように関係したかを示しています。「呼び出し元/呼び出し回数」パネルのいずれかのリストで関数をダブルクリックすると、その関数が、メインの「関数」ビューで選択した関数になります。

  3. さまざまな関数を選択してみて、選択の変更によって「関数」ビューのウィンドウが更新される方法を確認します。

    「選択の詳細」ウィンドウには、「ロードオブジェクト」フィールドに示されているように、ほとんどの関数が lowfruit 実行可能ファイルから生成されることが示されます。

    また、列ヘッダーをクリックしてみて、ソートを「排他的 CPU 合計時間」から「包括的 CPU 合計時間」に変更したり、「名前」でソートに変更したりすることもできます。

  4. 「関数」ビューで、2 つのバージョンの初期化タスク init_bad()init_good() を比較します。

    2 つの関数では、「排他的 CPU 合計時間」はほとんど同じですが、包括的時間はたいへん異なることがわかります。init_bad() 関数は、呼び出し先で費やす時間が原因で遅くなります。両方の関数が同じ呼び出し先を呼び出しますが、そのルーチンで費やす時間には大差があります。2 つのルーチンのソースを検査することで理由を確認できます。

  5. 関数 init_good() を選択してから、「ソース」ビューをクリックするか、メニューバーから「ビュー」>「ソース」を選択します。

  6. ウィンドウを調整して、コードの領域をさらに確保します。上マージンの下矢印をクリックして「呼び出し元/呼び出し回数」パネルを縮小して、横マージンの右矢印をクリックして「選択の詳細」パネルを縮小します。

    init_bad()init_good() の両方のソースを表示するには、少し上へスクロールしてください。「ソース」ビューは次のスクリーンショットのようになるはずです。

    image:「ソース」ビューには、init_bad 関数と init_good 関数のコードと、各行のメトリックが表示されます。

    init_static_routine() への呼び出しは init_good() のループの外部で行われるのに対して、init_good() にはループ内の init_static_routine() への呼び出しがあります。正しくないバージョンでは、正しいバージョンより約 10 倍長く (ループカウントに対応) かかります。

    この例は、表示されているほどくだらないものではありません。これは、表の行ごとにアイコンが示された表を生成する実際のコードに基づいています。この例では初期化をループ内で行うべきではないことが簡単にわかりますが、実際のコードでは、初期化はライブラリルーチンに組み込まれており、明らかではありませんでした。

    そのコードを実装するために使用されたツールキットでは、2 つのライブラリ呼び出し (API) を使用できました。最初の API では、アイコンが表の行に追加され、2 番目の API では、アイコンのベクトルが表全体に追加されました。最初の API を使用したコーディングの方が簡単ですが、アイコンが追加されるたびに、ツールキットでは、表全体の正しい値を設定するためにすべての行の高さが再計算されました。コードで代替の API を使用して一度にすべてのアイコンを追加したときに、高さの再計算は一度のみ行われました。

  7. 次に、「関数」ビューに戻って、2 つのバージョンの挿入タスク insert_bad()insert_good() を調べます。

    insert_bad() の「排他的 CPU 合計時間」は莫大ですが、insert_good() ではごくわずかです。各エントリをリストに挿入するために呼び出される関数 insert_number() での時間を表す、各バージョンの包括的時間と排他的時間の差は同じです。ソースを検査することで理由を確認できます。

  8. insert_bad() を選択して、「ソース」ビューに切り替えます。

    image:「ソース」ビューには insert_bad 関数が表示されます

    insert_number() への呼び出しを除き、時間は、新しい数値を挿入するために適した場所のリニア検索で表示されるループで使用されます。

  9. 次に、下へスクロールして insert_good() を確認します。

    image:「ソース」ビューには insert_good() 関数が表示されます

    コードは、挿入に適した場所を見つけるためにバイナリ検索を行なっているためより複雑ですが、insert_number() への呼び出しを除き、費やされる合計時間は insert_bad() での時間より大幅に少なくなります。この例は、バイナリ検索はリニア検索より効率的である可能性があることを示しています。

    「タイムライン」ビューでは、ルーチンでの違いをグラフィカルに確認することもできます。

  10. 「タイムライン」ビューをクリックするか、メニューバーから「ビュー」>「タイムライン」を選択します。

    プロファイリングデータは、すべてのスレッドのプロファイリングクロックのティックごとに 1 つ、一連のイベントとして記録されます。「タイムライン」ビューには、それぞれの個別のイベントが、そのイベントで記録された呼び出しスタックとともに表示されます。呼び出しスタックは、呼び出しスタック内のフレームのリストとして表示され、上部にはリーフ PC (イベントの時点で実行する次の指示)、次にこれを呼び出す呼び出し側などが表示されます。プログラムのメインスレッドでは、呼び出しスタックの上部は常に _start です。

  11. 「タイムライン」ツールバーで、関数に色を付けるための「呼び出しスタック関数の色」アイコンをクリックするか、メニューバーから「ツール」>「関数の色」を選択すると、次に示すダイアログボックスが表示されます。

    image:「タイムライン」で関数の色を変更するための「関数の色」ダイアログボックス

    関数の色が変更され、スクリーンショットで正しいバージョンの関数と正しくないバージョンの関数がより明確に区別されます。init_bad() 関数と insert_bad() 関数は両方とも赤色で、init_good()insert_good() は両方とも明るい緑です。

  12. 「タイムライン」ビューをより似た外観にするには、「関数の色」ダイアログボックスで次を行います。

    • 「凡例」で java メソッドのリストを下へスクロールして、init_bad() メソッドを見つけます。

    • init_bad() メソッドを選択して、「見本」で赤色の正方形をクリックし、「選択した関数の設定」ボタンをクリックします。

    • insert_bad() メソッドを選択して、「見本」で赤色の正方形をクリックし、「選択した関数の設定」ボタンをクリックします。

    • init_good() メソッドを選択して、「見本」で緑色の正方形をクリックし、「選択した関数の設定」ボタンをクリックします。

    • insert_good() メソッドを選択して、「見本」で緑色の正方形をクリックし、「選択した関数の設定」ボタンをクリックします。

  13. 「タイムライン」のいちばん上のバーを確認します。

    マウスカーソルを最初の列の上に移動するとツールチップで確認できるように、「タイムライン」のいちばん上のバーは「CPU 使用率標本」バーです。「CPU 使用率標本」バーの各セグメントは、その秒の実行の間のターゲットのリソース使用率を示す 1 秒の間隔を表します。

    この例では、すべての間隔が「ユーザー CPU 時間」の集計に費やされたため、すべてのセグメントは緑です。マイクロステートへの色のマッピングはスクリーンショットに示されていませんが、「選択の詳細」ウィンドウにはこれが示されます。

  14. 「タイムライン」の 2 番目のバーを確認します。

    2 番目のバーはクロックプロファイリング呼び出しスタックのバーで、「1 T:1」というラベルが付いており、プロセス 1 と、この例での唯一のスレッドであるスレッド 1 を意味します。「クロックプロファイリング呼び出しスタック」バーには、プログラムの実行中に発生するイベントのデータの 2 つのバーが示されます。上部のバーは、呼び出しスタックの色分けされた表現を示し、下部のバーは、各イベントでのスレッドの状態を示します。この例の状態は常に「ユーザー CPU 時間」であるため、緑で塗りつぶされた線で表示されます。

    「クロックプロファイリング呼び出しスタック」バー内の任意の場所でクリックして、もっとも近いイベントを選択すると、そのイベントの詳細が「選択の詳細」ウィンドウに表示されます。呼び出しスタックのパターンから、スクリーンショットでは明るい緑で示されている init_good() ルーチンと insert_good() ルーチンでの時間は、赤色で示されている init_bad() ルーチンと insert_bad() ルーチンでの対応する時間よりも大幅に短いことがわかります。

  15. 「タイムライン」で正しいルーチンと正しくないルーチンに対応する領域でイベントを選択して、「選択の詳細」ウィンドウの下にある「呼び出しスタック - タイムライン」ウィンドウで呼び出しスタックを確認します。

    「呼び出しスタック」ウィンドウで任意のフレームを選択してから、「ビュー」ナビゲーションバーの「ソース」ビューを選択して、そのソース行のソースに移動します。また、呼び出しスタックでフレームをダブルクリックして「ソース」ビューに移動することも、呼び出しスタックでフレームを右クリックしてポップアップメニューから選択することもできます。

  16. 「タイムライン」の上部にあるスライダを使用するか、+ キーを使用するか、またはマウスでダブルクリックすることで、イベントでズームインします。

    十分にズームインすると、表示されるデータは連続していなくても、プロファイルティック (この例では約 10 ミリ秒) ごとに 1 つの個別のイベントで構成されていることがわかります。

    image:個々のイベントを表示するためにズームインされた「タイムライン」ビュー

    「タイムライン」ビューに関する詳細情報のヘルプを表示するには、F1 キーを押します。

  17. 「呼び出しツリー」ビューをクリックするか、「ビュー」>「呼び出しツリー」を選択してプログラムの構造を表示します。

    「呼び出しツリー」ビューには、パフォーマンス情報の注釈が付いたプログラムの動的呼び出しグラフが表示されます。

    image:「呼び出しツリー」ビューには、パフォーマンスメトリックの注釈が付いたプログラムの動的呼び出しグラフが表示されます。

パフォーマンスアナライザには、プログラム構造内をナビゲートできる「呼び出し元-呼び出し先」ビューや、記録した実験の詳細が表示される「実験」ビューなどのデータの追加のビューが多数あります。この単純な例では、「スレッド」ビューと「プロセッサ」ビューはあまり興味深いものではありません。

「ビュー」リストで + ボタンをクリックすると、ナビゲーションバーにほかのビューを追加できます。アセンブリ言語のプログラマは、「逆アセンブリ」を調べることもできます。ほかのビューを調べてみてください。

パフォーマンスアナライザは、非常に強力なフィルタリング機能も備えています。時間、スレッド、関数、ソース行、命令、呼び出しスタック断片、およびこれらの任意の組み合わせでフィルタできます。サンプルコードは非常に単純でフィルタリングは必要ないため、フィルタリングの使用はこのチュートリアルの範囲外です。