新しくなった Windows Performance Analyzer

こんにちは、JS です。今回は、新しくなった Windows Performance Analyzer (WPA) についてお話をしたいと思います。

 

WPA は以前、K 里さんのエントリ「WPA とか Xperf とか」にて紹介されていましたが、Windows 8 用としてツールが新しくなりましたので、改めて紹介します。

 

WPA は、Windows Performance Toolkit (WPT) というツールキットの中に含まれるプログラムで、名前に Performance とある通り、PC のシステム全体のパフォーマンスを測定します。

 

WPT の概要については、K 里さんの記事にも書かれていますが、ここでも改めて説明します。

最新の WPT は、主に以下の 2 つのコンポーネントで成り立っています:

1. Windows Performance Recorder (WPR) - トレースデータを採取するコンポーネント

2. Windows Performance Analyzer (WPA) - トレースデータを GUI で表すコンポーネント

この 2 つに加えて、xperf 等といった、以前のバージョンからあるレガシー プログラムの殆どが揃っています。

 

WPT では、初めに、アプリやドライバ等のシステム内モジュールの動作をトレースします。トレース方法として、それぞれの動作がどう PC に影響を与えているのかを、カーネル イベント (例えば CPU の使用率や割り込みの頻度など) という情報を記録することで測定します。そして、その結果をグラフ等で視覚化することによって、トレースしていた間の PC の様子がわかるようになります。

使用例として、開発しているソフトウェアがパフォーマンス上に問題があったときに切り分けを行ったり、最適化のための検証をする、などがあります。PC の内部状況を広い範囲でトレースしてくれる上、トレース中も殆どパフォーマンスに影響を与えない為、パフォーマンス状態を詳細かつ忠実に表してくれます。実際、Windows 自体の検証にも WPT が使用されていたりします。

 

元から非常に便利な WPT でありますが、最新のバージョンで様々な変更が施されました。WPA の場合、前バージョンの xperfview から UI がガラッと変わり、より使いやすく効率的な作業ができるような設計になりました。

ということで、今回はその新しい WPA が 昔 (xperfview) と比べてどのように新しくなったのかお見せしたいと思います。

ちなみに、今回は WPA に着目しているので、WPR についてはまた次回の時に紹介させていただきます。

 

WPA のインストール

まず、WPT をダウンロード&インストールしましょう。現在、WPT は Assessment Deployment Kit (ADK) の一部となっているので、ADK のダウンロードサイトから手に入れます。

 

Windows 8.1 Update 用 Windows アセスメント & デプロイメント キット (Windows ADK)

<http://www.microsoft.com/ja-jp/download/details.aspx?id=39982>

ちなみに、ADK 自体は Windows 8.1 Update 用と書いてありますが、WPT は Windows 7 からの OS でサポートされています。

 

ADK には WPT の他に様々なプログラムが含まれている為、下の画像にあるように、今回は他のプログラムをインストールせず WPT だけを選択してインストールしましょう。

Windows 8.1 内でインストールした場合、デフォルトで、以下のパスに保存されます。今回使用する xperf 及び WPA は、両方とも指定したディレクトリ内に同梱されています。

C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit

 

clip_image001

 

トレースファイルの取得

早速 WPA を使ってみたいところですが、その前に、解析の為の .etl (Event Trace Log) トレースファイルが必要です。WPR を使用してもトレースはできますが、今回は xperf を使用して採取します。Xperf でのコマンドの使い方については、冒頭で紹介した K 里さんの記事をご参照ください。
ちなみに、今回私は

xperf -on Latency -stackwalk Profile

コマンドを使用してトレースしたものを見ていきます。

 

トレースファイルを取得したら、次は WPA を使ってみましょう。ファイルを開くと WPA が起動します。

 

WPA の機能について① - グラフと表の使い方

WPA を初めて起動するときは、下の画像にある通り、Graph Explorerというウィンドウと、Analysisというタブが表示されていると思います。

 

clip_image002

 

Graph Explorer ウィンドウは、カーネルのイベント情報を分類しています。例えば、Storage の部分を展開すると、ディスク I/O をはじめとする、ディスクに関する情報を見ることができます。また、それぞれの情報についてのグラフのサムネイルを表示します。機能としては、xperfview の左側に現れる項目リストと似ています。

試しに、Computation の項目をダブルクリックしましょう。下の画像にあるようなグラフが Analysis タブ上に現れると思います。

 

clip_image003

 

この Analysis タブは、複数作ることができる上、名前の変更やフロートウィンドウモードの設定が可能になりましたので、ウィンドウ管理の自由度が大幅に上がりました。

 

clip_image004

 

xperfview でも画像のようなグラフと表がありましたが、今回はそれらが同じウィンドウ上に表示できるようになっています。ちなみに、右上のアイコンでグラフのみ、表のみ表示させることができます。

 

clip_image005

 

また、このグラフと表はシンクロしています。

試しにグラフで時間の範囲を選択してみます。グラフの上でマウスをクリック&ドラッグすると、以下の画像にある通り、時間の範囲が選択されると同時に、表の項目も同時に選択されます。これは、指定した範囲内でどのプロセスが実行中なのかを表してくれているのです。

その上、それぞれのプロセスのリソース消費量を、色の濃さで表しています。これによって、プロセスがパフォーマンスにどのくらいの影響を与えているのかが一目瞭然となります。

例えば、下の 2 つの画像を見比べると、表が選択範囲の変化に反応しているのがわかります。

 

clip_image006

 

clip_image007

 

次に、トレースの表示範囲を絞ってみましょう。任意の時間範囲を選択した後、右クリックし、 [Zoom] をクリックします。この機能は xperfview にもありましたが、今回はグラフだけではなく、表 (と同時に Graph Explorer のサムネイル) もそれにならって更新されます。

 

clip_image008

 

今回使用しているトレースファイルには、スタックの情報も含まれているので、そちらを見てみましょう。

まず、シンボルパスを設定します。 [Trace] メニューから [Configure Symbol Path] をクリックし、Symbol Paths の項目に以下を記入します。

srv* C:\Symbols ***http://msdl.microsoft.com/download/symbols**;

(緑字は任意のパスに設定します)

この「パブリック シンボル」をダウンロードすることで、OS のモジュールに関するスタック情報を見ることができます。

もし、独自に作られたアプリケーションの関数を見てパフォーマンスを解析したい場合は、そのアプリケーションと合わせて作られた .pdb ファイルのあるフォルダも参照する必要があります。

そして、同じく [Trace] メニューにある [Load Symbols] をクリックしたら、シンボルがロードされ始めます。下の画像のように、Progress Bar がウィンドウ上に現れるので、ロードされるまで待ちましょう。

 

clip_image010

 

clip_image012

 

ロードが終わったら、スタックを表示させましょう。表の上部に項目を表示している行がありますが、そこを右クリックし、 [Stack] を選びます。

 

スタックについて

適当にスタックを展開してみると、以下の例 (ここでは、MsMpEng.exe を使っています) のようになっているかと思います:

 

Stack Weight Count

[Root] 2464.552068 2461

  |- ntdll.dll!_RtlUserThreadStart 2404.408036 2401

  |- ?!? 35.014668 35

  |- ntoskrnl.exe!KiSystemServicePostCall 11.000131 11

  | |- ntoskrnl.exe!NtWaitForWorkViaWorkerFactory 8.000000 8

  | | ntoskrnl.exe!IoRemoveIoCompletion 8.000000 8

  | | ntoskrnl.exe!KeRemoveQueueEx 8.000000 8

  | | |- ntoskrnl.exe!KeRemoveQueueEx<itself> 4.000000 4

  | | |- ntoskrnl.exe!KiCommitThreadWait 4.000000 4

  | |- ntoskrnl.exe!NtWaitForSingleObject 2.000000 2

  | |- ntoskrnl.exe!NtRemoveIoCompletion 1.000131 1

  | | ntoskrnl.exe!IoRemoveIoCompletion 1.000131 1

  | | ntoskrnl.exe!KeRemoveQueueEx 1.000131 1

  | | 1.000131 1

  |- mpengine.dll!? 9.129102 9

  |- ntdll.dll!ExpInterlockedPopEntrySListResume 4.000131 4

  |- ntdll.dll!ExpInterlockedPopEntrySListEnd 1.000000 1

 

 

 

しかし、このスタックの表記方法、初見ではどういう構成になっているのかわかりづらいかと思われます…

なので、話がすこしずれますが、ここでスタックの読み方についてもう少し詳しく説明したいと思います。

 

まず、プロセスのスタックは一番上にある [Root] が原点となっています。スタックは下に向かっており、ハイレベルでの階層は縦棒 (|) によって分けられています。

特定の関数が複数の関数を呼ぶ場合、呼ばれる関数の前にハイフン (-) が足されます。例えば、上で紹介したスタックにあるKiSystemServicePostCall 関数は、以下の 3 つの関数を呼んでいます:

1. NtWaitForWorkViaWorkerFactory

2. NtWaitForSingleObject

3. NtRemoveIoCompletion

これの裏付けとして、Count の項目を見ます。(この数字は、トレース中、サンプルを採取するときにその関数を実行していた回数を表しています)KiSystemServicePostCall の場合、Count が 11 と書いてありますが、この数字は先ほど紹介した 3 つの関数の Count を足した数になります。要するに、NtSystemServicePostCall から始まるスタックは、合計で 11 回、サンプルを取った時に実行中であるのを確認した、ということです。

逆に、特定の関数が一つの関数しか呼ばない場合、ハイフンがつきません。上のスタックからの例を挙げると、NtWaitForWorkViaWorkerFactory 関数は IoRemoveIoCompletion を呼び、IoRemoveIoCompletion がKeRemoveQueueEx 関数を呼ぶ、といった構図となっています。

 

Stack 項目にて表示される関数は [ モジュール名 ] ! [ 関数名 ] という形式で表記してありますが、名前が分からない場合は ? マークで表されます。

この例では、モジュール名がわかるが関数名が分からないもの (mpengine.dll!?) と、どちらも不明なもの (?!?) があります。一見、WPA が驚いているように見えますが、決してそういうわけではないのでご心配なく。

もしシンボルをロードしないと、大体の関数が ? マークで表示されてしまうので、解析の前は忘れずにシンボルをロードしましょう。

 

また、<itself> という表記が関数の後についているものがあります (KeRemoveQueueEx<itself>)。他の関数を呼ぶ関数が、その他の関数を呼んでいないときにサンプルが取られた場合、<itself> としてコールスタックに追加されます。Count の計算方法に一貫性を持たせる為、厳密には同じ関数であっても、<itself> のついている関数はついていない方に呼ばれたという扱いになっています。

関数名のない (空白な) 行は、単に 1 Count のインスタンスを表しています。なので、例えば Count が 4 ある最下層の関数を展開すると、4 行の空白が現れます。

 

以上、長々と説明しましたが、上の表を図にまとめるとしたら、こういう風になります:

 

 clip_image014

 

これでスタックについての説明は一通り終わりましたが、最後にいくつかの注意点をお伝えしたいと思います:

· この例では途中までしか展開していないため、このコールスタックがこのプロセスの全てというわけではありません。

· この表は、Weight の大きい順に表示してあります。よって、これらの関数の順番は実際に実行された順番とまったく関係ありません。

· それぞれの関数は、「合計」として一つに纏められている為、いつ 何回呼ばれたかについては別途 調べる必要があります。

 

では、以上の点を踏まえ、機能の紹介に話を戻しましょう。

スタックの項目では、先ほどお話しました通り、それぞれのプロセスのスタック構造を見ることができます。(下の画像ではタスクマネージャーのスタックの一部を例として見せています)

 

clip_image015

 

ここでまた新しい機能があります。表での情報の配置によって、その情報がどう使用されるのかを変更することができます。

表に黄色のバーと青色のバーが確認できますが、この表は、3 つの分野に分けられています:

· 黄色のバーの左側にある情報は、グラフに表示させるものを情報別に選択することができます。

· 黄色のバーと青色のバーの間にある情報は、指定した時間の範囲内を累計で表しています。

· 青色のバーの右側にある情報は、グラフで測定するもの (Y軸) を指定します。

 

例えば、以下の配置を行ってみます:

・「Stack」を黄色のバーの左側に置く

・「%Weight」をバーの間に置く

・「Count」を青色のバーの右側に置く

すると、以下の画像のようになります。

 

clip_image016

 

元々は CPU の使用率を表示していましたが、今度は Count の数を表示しています。また、とあるスタックを選択するときに、それがどこで使用されたのかがグラフ・表に現れます。

 

なお、指定したスタックだけの情報を表示させたい場合は、そのスタックを選択し、右クリックから [Filter to Selection] をクリックします。ちなみに、他の情報も見える状態に戻したい場合は、右クリックで [ Clear Filter ] を選択します。

 

グラフ自体も、折れ線グラフ以外に棒グラフという表示形式があります。下の画像にある赤枠内のボタンを押すと、選択肢が表示されます。試しに、棒グラフ (Stacked Bars) で表示させてみました。

 

 clip_image017

 

デフォルト (Line) の場合、それぞれのプロセスのグラフが独立していますが、棒グラフではそれぞれのプロセスが重なっていくので、全体の構成を見ることができます。

今回のトレースでは、testApp.exeというモジュールが長い間 CPU の一部を消費しているのが見られます。testApp.exe のスタックを展開してみると、testApp.exe! wmainという関数が殆どの間実行中なのがわかるので、そこに CPU 消費の原因がある、という判断ができます (実態は、お察しの通り、ただ単に実行時間が長い For ループです)。

 

clip_image018

 

 

WPA の機能について② - セッションとプロファイル

新しい WPA では、セッションという形式で作業のスナップショットを保存することができます。セッションを作成すれば、作業状態を保存できるだけではなく、例えば他の人にトレース情報を渡すときに、参考資料として一緒に提供したりすることができます。 [File] メニューから [Export Session…] をクリックし、任意のファイル名・保存場所を指定して保存します。

ちなみに、このセッション ファイル (.wpa ファイル) は、元となったトレースファイルのパスを参照します。他の PC に移したりするときは、元の PC と同じディレクトリ上に設置する必要があります。また、名前の変更等、トレースファイルのパスを変える動作をしないよう気を付けましょう。

 

セッションの他に、プロファイルというものがあります。こちらは、何をトレースするかに合わせて設定するもので、トレース情報の構成を予め決めることができます。

プロファイルを適用する時は、 [Profiles] メニューの [Apply] をクリックすることで、Apply Profileというタブが表示されます。

 

clip_image019

 

たとえば、PC のブートのパフォーマンスを効率よくみたい場合は、タブの中にある [Browse Catalog…] で参照し、FullBoot.Boot.wpaprofile を開きます。

自分で好きなプロファイルも作ることができるので、より自分にあった設定を作ることができます。見たい情報を Analysis タブ上に揃えた後、セッション作成と同じ要領で、 [Profiles] メニューの [Export…] から作成します。

また、スタートアップ プロファイルという、デフォルトで適用されるプロファイルも設定できます。 [Profiles] メニューの [Save Startup Profile] を選択することで、そのプロファイルが WPA 起動時に使われるようになります。よく行う解析方法がある場合、それに合わせたスタートアップ プロファイルがあれば、わざわざ設定などせずにすぐに作業にとりかかることにできます。

 

この様に、xperfview の機能をリニューアルした他に新しい機能も追加された WPA は、ユーザーの使い方に合わせてカスタマイズできるツールへと進化をとげました。今回は、主に WPA の機能について書きましたが、WPR の使い方や WPA の実践例なども追って紹介したいと思います。皆さんも、このツールを使って、パフォーマンスを意識した開発をしていただきたいと思います。