Sun Studio 12: パフォーマンスアナライザ

コレクタが収集するデータの内容

コレクタは、プロファイルデータ、トレースデータ、および大域データの 3 種類のデータを収集します。

プロファイルデータとトレースデータの両方が特定のイベントに関する情報を含んでおり、いずれのデータの種類もパフォーマンスメトリックに変換されます。大域データはメトリックに変換されませんが、プログラムの実行を複数のタイムセグメントに分割するために使用できるマーカーを提供します。大域データは、タイムセグメントにおけるプログラム実行の概要を示します。

それぞれのプロファイルイベントやトレースイベントで収集されたデータパケットには、次の情報が含まれます。

スレッドと軽量プロセスについての詳細は、第 7 章「パフォーマンスアナライザとそのデータの内容」を参照してください。

こうした共通の情報のほかに、各イベントに固有のデータパケットには、データの種類に固有の情報が含まれます。コレクタが記録できるデータは、次の 5 種類です。

これらの 5 種類のデータ、それらから派生したメトリック、およびメトリックの使用方法については、あとの項で説明します。6 種類目のデータ、大域標本データには呼び出しスタック情報が含まれないため、メトリックに変換できません。

時間データ

時間ベースのプロファイル時に収集されるデータは、オペレーティングシステムが提供するメトリックによって異なります。

Solaris OS での時間ベースのプロファイル

Solaris OS での時間ベースのプロファイルでは、各 LWP の状態が定期的な間隔で格納されます。この間隔はプロファイル間隔と呼ばれます。この情報は整数型の配列に格納され、カーネルの管理する 10 個のマイクロアカウンティング状態のそれぞれに、1 つの配列要素が使用されます。収集されたデータは、各状態で消費された、プロファイル間隔の分解能を持つ時間値に、パフォーマンスアナライザによって変換されます。デフォルトのプロファイル間隔は、約 10 ミリ秒 (10 ms) です。コレクタは、約 1 ミリ秒の高分解能プロファイル間隔と、約 100 ミリ秒の低分解能プロファイル間隔を提供し、OS で許されれば任意の間隔を許可します。引数を付けずに collect コマンドを実行すると、このコマンドが実行されるシステム上で許される範囲と分解能が出力されます。

時間ベースのデータから計算されるメトリックの定義を、次の表に示します。

表 2–1 Solaris タイミングメトリック

メトリック 

定義 

ユーザー CPU 時間 

CPU のユーザーモードで実行中に使用される LWP 時間。 

時計時間 

LWP 1 で使用される LWP 時間。一般的な「時計時間」です。 

LWP 合計時間 

LWP 時間の総合計。 

システム CPU 時間 

CPU のカーネルモードまたはトラップ状態で実行中に使用される LWP 時間。 

CPU 待ち時間 

CPU の待機中に使用される LWP 時間。 

ユーザーロック時間 

ロックの待機中に使用される LWP 時間。 

テキストページフォルト時間 

テキストページの待機中に使用される LWP 時間。 

データページフォルト時間 

データページの待機中に使用される LWP 時間。 

ほかの待ち時間 

カーネルページ待機中に使用される LWP 時間、またはスリープ中か停止中に使用される時間。 

マルチスレッドの実験では、全 LWP にまたがって時計時間以外の時間が集計されます。定義した時計時間は、MPMD (multiple-program multiple-data) プログラムには意味がありません。

タイミングメトリックは、プログラムがいくつかのカテゴリで時間を費やした部分を示し、プログラムのパフォーマンス向上に役立てることができます。

Linux OS での時間ベースのプロファイル

Linux OS で利用できるメトリックは、ユーザー CPU 時間だけです。報告される合計 CPU 使用時間は正確ですが、アナライザは Solaris OS の場合ほど正確に実際のシステム CPU 時間の割合を判別できない場合があります。アナライザは軽量プロセス (LWP) のデータであるかのように情報を表示しますが、現実には Linux OS 上に LWP はなく、表示される LWP ID は実際にはスレッド ID です。

ハードウェアカウンタオーバーフローのプロファイルデータ

ハードウェアカウンタは、キャッシュミス、キャッシュストールサイクル、浮動小数点演算、分岐予測ミス、CPU サイクル、および実行対象命令といったイベントの追跡に使用されます。ハードウェアカウンタオーバーフローのプロファイルでは、LWP が動作している CPU の特定のハードウェアカウンタがオーバーフローしたときに、コレクタはプロファイルパケットを記録します。この場合、そのカウンタはリセットされ、カウントを続行します。プロファイルパケットには、オーバーフロー値とカウンタタイプが入っています。

各種の CPU ファミリが 2 〜 18 個の同時ハードウェアカウンタレジスタをサポートしています。コレクタは、複数のレジスタ上でデータを収集できます。各レジスタごとに、オーバーフローを監視するカウンタの種類を選択し、カウンタのオーバフロー値を設定することができます。ハードウェアカウンタには、任意のレジスタを利用できるものもあれば、特定のレジスタしか利用できないものもあります。このことは、1 つの実験であらゆるハードウェアカウンタの組み合わせを選択できるわけではないことを意味します。

パフォーマンスアナライザは、ハードウェアカウンタのオーバーフロープロファイルデータをカウントメトリックに変換します。循環型のカウンタの場合、報告されるメトリックは時間に変換されます。非循環型のカウンタの場合は、イベントの発生回数になります。複数の CPU を搭載したマシンの場合、メトリックの変換に使用されるクロック周波数が個々の CPU のクロック周波数の調和平均となります。プロセッサのタイプごとに専用のハードウェアカウンタセットがあり、またハードウェアカウンタの数が多いため、ハードウェアカウンタメトリックはここに記載していません。次の項で、どのような種類のハードウェアカウンタがあるかについて調べる方法を説明します。

ハードウェアカウンタの用途の 1 つは、CPU に出入りする情報フローに伴う問題を診断することです。たとえば、キャッシュミス回数が多いということは、プログラムを再構成してデータまたはテキストの局所性を改善するか、キャッシュの再利用を増やすことによってプログラムのパフォーマンスを改善できることを意味します。

一部のハードウェアカウンタは、同様の情報または関連情報を示します。たとえば、分岐予測ミスが発生すると、間違った命令が命令キャッシュに読み込まれ、これらの命令を正しい命令と置換しなければならなくなるため、分岐予測ミスと命令キャッシュミスが関連付けられることがよくあります。置換により、命令キャッシュミス、命令変換ルックアサイドバッファー (ITLB) ミス、またはページフォルトが発生する可能性があります。

多くの場合、ハードウェアカウンタオーバーフローは、イベントと対応するイベントカウンタにオーバーフローを発生させた命令のあとに 1 つまたは複数の命令をはさんで送られます。これは「スキッド」と呼ばれ、カウンタオーバーフロープロファイルの解釈を困難にします。原因となる命令を正確に識別するためのハードウェアサポートがないと、候補の原因となる命令の適切なバックトラッキング検索が行われる場合があります。

そのようなバックトラッキングが収集中にサポートされて指定されると、ハードウェアカウンタプロファイルパケットにはさらに、ハードウェアカウンタイベントに適した候補の、メモリー参照命令の PC (プログラムカウンタ) と EA (有効アドレス) が組み込まれます。解析中の以降の処理は、候補のイベント PC と EA を有効にするのに必要です。メモリー参照イベントに関するこのような追加情報があると、各種のデータ指向解析が容易になります。

候補のイベント PC と EA のバックトラッキングおよび記録も、時間プロファイルで指定できます。

ハードウェアカウンタのリスト

ハードウェアカウンタはプロセッサ固有であるため、どのカウンタを利用できるかは、使用しているプロセッサによって異なります。パフォーマンスツールには、よく使われると考えられるいくつかのカウンタの別名が用意されています。コレクタから特定システム上で利用できるハードウェアカウンタの一覧を取り出すには、引数を付けないで collect をそのシステム上の端末ウィンドウに入力します。プロセッサとシステムがハードウェアカウンタプロファイルをサポートしている場合、collect コマンドは、ハードウェアカウンタに関する情報が入った 2 つのリストを出力します。最初のリストには「既知の」(別名を持つ) ハードウェアカウンタが入っており、2 番目のリストには、raw ハードウェアカウンタが入っています。

次に、カウンタリストに含まれるエントリの表示例を示します。既知と考えられるカウンタはリストの最初に表示され、そのあとに raw ハードウェアカウンタのリストが表示されます。この例の出力行はすべて、印刷用に書式が整えられています。


Well known HW counters available for profiling:
cycles[/{0|1}],9999991 (’CPU Cycles’, alias for Cycle_cnt; CPU-cycles)
insts[/{0|1}],9999991 (’Instructions Executed’, alias for Instr_cnt; events)
dcrm[/1],100003 (’D$ Read Misses’, alias for DC_rd_miss; load events)
...
Raw HW counters available for profiling:
Cycle_cnt[/{0|1}],1000003 (CPU-cycles)
Instr_cnt[/{0|1}],1000003 (events)
DC_rd[/0],1000003 (load events)

既知のハードウェアカウンタリストの形式

既知のハードウェアカウンタリストでは、最初のフィールド (たとえば、cycles) は、collect コマンドの -h counter... 引数に使用できる別名を示します。この別名は、 er_print コマンド内で使用する識別子でもあります。

リストの 2 番目のフィールドには、そのカウンタに使用可能なレジスタ、たとえば、[/{0|1}] が示されます。既知のカウンタの場合は、合理的なサンプルレートを提供するためにデフォルト値が選択されています。実際のレートは、かなり変化するため、デフォルト以外の値を指定する必要がある場合もあります。

3 番目のフィールドは、たとえば 9999991 など、カウンタのデフォルトのオーバーフロー値です。

4 番目のフィールドは、括弧で囲まれ、タイプ情報を含んでいます。これは、簡単な説明 (CPU Cycles など)、raw ハードウェアカウンタ名 (Cycle_cnt など)、およびカウントされる単位の種類 (CPU-cycles など) を提供し、最大 2 ワードまで含めることができます。

タイプ情報の最初のワードが、

タイプ情報の 2 番目または唯一のワードが、

例に示した既知のハードウェアカウンタリストでは、タイプ情報に 1 ワードが含まれており、最初のカウンタの場合は CPU-cycles で、2 番目のカウンタの場合は、events となっています。3 番目のカウンタでは、タイプ情報に load events という 2 ワードが含まれています。

raw ハードウェアカウンタリストの形式

raw ハードウェアカウンタリストに含まれる情報は、既知のハードウェアカウンタリストに含まれる情報のサブセットです。それぞれの行には、cpu-track(1) によって使用された内部カウンタ名、そのカウンタを使用できるレジスタ番号 (単数または複数)、デフォルトのオーバーフロー値、およびカウンタ単位が含まれており、カウンタ単位は CPU-cyclesEvents です。

カウンタがプログラムの実行に関連のないイベントを測定する場合、タイプ情報の最初のワードは not-program-related になります。そのようなカウンタの場合、プロファイリングで呼び出しスタックが記録されませんが、その代わりに、擬似関数 collector_not_program_related で使用された時間が示されます。スレッドと LWP ID は記録されますが、意味がありません。

raw カウンタのデフォルトのオーバーフロー値は 1000003 です。この値は、ほとんどの raw カウンタでは最適ではないため、raw カウンタを指定するときにタイムアウト値を指定する必要があります。

同期待ちトレースデータ

マルチスレッドプログラムでは、たとえば、1 つのスレッドによってデータがロックされていると、別のスレッドがそのアクセス待ちになることがあります。このため、複数のスレッドが実行するタスクの同期を取るために、プログラムの実行に遅延が生じることがあります。これらのイベントは同期遅延イベントと呼ばれ、Solaris または pthread のスレッド関数の呼び出しをトレースすることによって収集されます。同期遅延イベントを収集して、記録するプロセスを同期待ちのトレースといいます。また、ロック待ちに費やされる時間を待ち時間といいます。現在、同期待ちトレースは、Solaris OS を実行しているシステムにのみ利用できます。

ただし、イベントが記録されるのは、その待ち時間がしきい値 (ミリ秒単位) を超えた場合だけです。しきい値 0 は、待ち時間に関係なく、あらゆる同期遅延イベントをトレースすることを意味します。デフォルトでは、同期遅延なしにスレッドライブラリを呼び出す測定試験を実施して、しきい値を決定します。こうして決定された場合、しきい値は、それらの呼び出しの平均時間に任意の係数 (現在は 6) を乗算して得られた値です。この方法によって、待ち時間の原因が本当の遅延ではなく、呼び出しそのものにあるイベントが記録されないようになります。この結果として、同期イベント数がかなり過小評価される可能性がありますが、データ量は大幅に少なくなります。

Java プログラムの同期トレースは、スレッドが Java モニターを取得しようとしたときに生成されるイベントに基づいています。マシンと Java の呼び出しスタックの両方がこれらのイベントに関して収集されますが、JavaTM 仮想マシン (JVM) ソフトウェア内で使用される内部ロックに関しては、同期トレースデータは収集されません。マシン表現では、スレッド同期が _lwp_mutex_lock への呼び出しに委譲され、これらの呼び出しはトレースされないので同期データは表示されません。

同期待ちトレースデータは、次のメトリックに変換されます。

表 2–2 同期待ちトレースメトリック

メトリック 

定義 

同期遅延イベント

待ち時間が所定のしきい値を超えたときの同期ルーチン呼び出し回数。 

同期待ち時間

所定のしきい値を超えた総待ち時間。 

この情報から、関数またはロードオブジェクトが頻繁にブロックされるかどうか、または同期ルーチンを呼び出したときの待ち時間が異常に長くなっているかどうかを調べることができます。同期待ち時間が大きいということは、スレッド間の競合が発生していることを示します。競合は、アルゴリズムの変更、具体的には、ロックする必要があるデータだけがスレッドごとにロックされるように、ロックを構成し直すことで減らすことができます。

ヒープトレース (メモリー割り当て) データ

正しく管理されていないメモリー割り当て関数やメモリー割り当て解除関数を呼び出すと、データの使い方の効率が低下し、プログラムパフォーマンスが低下する可能性があります。ヒープトレースでは、C 標準ライブラリメモリー割り当て関数 mallocreallocvallocmemalign、および割り当て解除関数 free 上で割り込み処理を行うことによって、コレクタはメモリーの割り当てと割り当て解除の要求をトレースします。mmap への呼び出しはメモリー割り当てとして扱われ、これによって Java メモリー割り当てのヒープトレースイベントを記録することが可能になります。Fortran 関数 allocate および deallocate は C 標準ライブラリ関数を呼び出すので、これらのルーチンも間接的にトレースされます。

Java プログラムのヒーププロファイリングはサポートされません。

ヒープトレースデータは、次のメトリックに変換されます。

表 2–3 メモリー割り当て (ヒープトレース) メトリック

メトリック 

定義 

割り当て 

メモリー割り当て関数の呼び出し回数。 

割り当てバイト数 

メモリー割り当て関数の各呼び出しで割り当てられたバイト数の合計。 

リーク 

対応する割り当て解除関数の呼び出しを持たなかったメモリー割り当て関数の呼び出し回数。 

リークバイト数 

割り当てられたが割り当て解除されなかったバイト数。 

ヒープトレースデータを収集すれば、プログラム内のメモリーリークを見つけたり、十分なメモリーが割り当てられていない場所を確認したりできます。

メモリーリークのもう 1 つの定義は、dbx デバッグツールなどでよく使用されているもので、それによると、メモリーリークとは、プログラムのデータ空間内のどこにもポインタが存在しない、動的に割り当てられるメモリーブロックです。ここで使用されるリークの定義にはこの代替定義を含みますが、ポインタが存在するメモリーも含みます。

MPI トレースデータ

コレクタは、Message Passing Interface (MPI) ライブラリの呼び出しに関するデータを収集できます。現在、MPI トレースは、Solaris OS を実行しているシステムにのみ利用できます。データ収集の対象となる関数を次に示します。

MPI_Allgather

MPI_Allgatherv

MPI_Allreduce

MPI_Alltoall

MPI_Alltoallv

MPI_Barrier

MPI_Bcast

MPI_Bsend

MPI_Gather

MPI_Gatherv

MPI_Irecv

MPI_Isend

MPI_Recv

MPI_Reduce

MPI_Reduce_scatter

MPI_Rsend

MPI_Scan

MPI_Scatter

MPI_Scatterv

MPI_Send

MPI_Sendrecv

MPI_Sendrecv_replace

MPI_Ssend

MPI_Wait

MPI_Waitall

MPI_Waitany

MPI_Waitsome

MPI_Win_fence

MPI_Win_lock

 

MPI トレースデータは、次のメトリックに変換されます。

表 2–4 MPI トレースメトリック

メトリック 

定義 

MPI 受信 

データを受信する MPI 関数の受信操作回数 

MPI 受信バイト数 

MPI 関数で受信したバイト数 

MPI 送信 

データを送信する MPI 関数の送信操作回数 

MPI 送信バイト数 

MPI 関数で送信したバイト数 

MPI 時間 

MPI 関数のすべての呼び出しに使用した時間 

ほかの MPI 呼び出し 

ほかの MPI 関数の呼び出し数 

受信または送信したとして記録されたバイト数は、呼び出しにおいて与えられるバッファーサイズです。この数値は、実際に受信または送信したバイト数よりも大きいことがあります。大域通信関数と集合通信関数においては、直接的なプロセッサ間通信が行われるとともにデータ転送やデータ再送の最適化が行われないという前提に基づき、送信または受信されるバイト数が最大値となります。

トレースされる MPI ライブラリの関数を、MPI 送信関数、MPI 受信関数、MPI 送受信関数、およびその他の MPI 関数に分類して表 2–5 にまとめます。

表 2–5 送信、受信、送受信、およびその他の MPI 関数の分類

カテゴリ 

関数 

MPI 送信関数 

MPI_BsendMPI_IsendMPI_RsendMPI_SendMPI_Ssend

MPI 受信関数 

MPI_IrecvMPI_Recv

MPI 送受信関数 

MPI_AllgatherMPI_AllgathervMPI_AllreduceMPI_AlltoallMPI_AlltoallvMPI_BcastMPI_Gather MPI_GathervMPI_ReduceMPI_Reduce_scatterMPI_ScanMPI_Scatter MPI_ScattervMPI_SendrecvMPI_Sendrecv_replace

その他の MPI 関数 

MPI_BarrierMPI_WaitMPI_WaitallMPI_WaitanyMPI_WaitsomeMPI_Win_fenceMPI_Win_lock

MPI トレースデータを収集すると、MPI 呼び出しによって MPI プログラムのパフォーマンスに問題が生じている可能性がある場所を確認できます。発生する可能性のあるパフォーマンスの問題の例には、負荷分散、同期遅延、通信ボトルネックなどがあります。

大域 (標本収集) データ

大域データは、標本パケットと呼ばれるパケット単位でコレクタが記録します。各パケットには、ヘッダー、タイムスタンプ、ページフォルトや I/O データなどのカーネルからの実行統計、コンテキストスイッチ、および各種のページの常駐性 (ワーキングセットとページング) 統計が入っています。標本パケットに記録されるデータは、プログラムにとって大域的であり、パフォーマンスメトリックには変換されません。標本パケットを記録するプロセスのことを、標本収集と呼びます。

標本パケットは、次の状況で記録されます。

パフォーマンスツールは、標本パケットに記録されたデータを使用して、時間期間別に分類します。この分類されたデータを標本と呼びます。特定の標本セットを選択することによってイベントに固有のデータをフィルタできるので、特定の期間に関する情報だけを表示させることができます。各標本の大域データを表示することもできます。

パフォーマンスツールは、標本ポイントのさまざまな種類を区別しません。標本ポイントを解析に利用するには、1 種類のポイントだけを記録対象として選択してください。特に、プログラム構造や実行シーケンスに関する標本ポイントを記録する場合は、定期的な標本収集を無効にし、dbx がプロセスを停止したとき、collect コマンドによってデータ記録中のプロセスにシグナルが送られたとき、あるいはコレクタ API 関数が呼び出されたときのいずれかの状況で記録された標本を使用します。