時間ベースのプロファイリングのイベント固有のデータは、プロファイル間隔カウント値からなる配列で構成されています。Solaris OS の場合は、間隔カウンタが提供されます。プロファイル間隔の最後で適切な間隔カウンタが 1 増分され、別のプロファイル信号がスケジューリングされます。この配列が記録され、リセットされるのは、Solaris LWP スレッドが CPU ユーザーモードに入った場合だけです。配列のリセット時には、ユーザー CPU 状態の配列要素が 1 に設定され、ほかの全状態の配列要素が 0 に設定されます。配列データが記録されるのは、配列がリセットされる前にユーザーモードに入るときです。したがって、配列には、Solaris LWP ごとにカーネルが保持する 10 個のマイクロステートのそれぞれについて、ユーザーモードに前回入って以降の各マイクロステートのカウントの累計値が含まれます。Linux OS ではマイクロステートは存在せず、利用できる間隔カウンタはユーザー CPU 時間だけです。
呼び出しスタックは、データと同時に記録されます。プロファイル間隔の最後で Solaris LWP がユーザーモードでない場合は、LWP またはスレッドが再びユーザーモードになるまで、呼び出しスタックの内容は変わりません。すなわち、呼び出しスタックには、各プロファイル間隔の最後のプログラムカウンタの位置が常に正確に記録されます。
表 7–2 に、各マイクロステートとメトリックの、Solaris OS における対応関係をまとめます。
表 7–2 カーネルのマイクロステートとメトリックの対応関係
カーネルのマイクロステート |
内容の説明 |
メトリック名 |
---|---|---|
LMS_USER |
ユーザーモードで動作 |
ユーザー CPU 時間 |
LMS_SYSTEM |
システムコールまたはページフォルトで動作 |
システム CPU 時間 |
LMS_TRAP |
上記以外のトラップで動作 |
システム CPU 時間 |
LMS_TFAULT |
ユーザーテキストページフォルトでスリープ |
テキストページフォルト時間 |
LMS_DFAULT |
ユーザーデータページフォルトでスリープ |
データページフォルト時間 |
LMS_KFAULT |
カーネルページフォルトでスリープ |
ほかの待ち時間 |
LMS_USER_LOCK |
ユーザーモードロック待ちのスリープ |
ユーザーロック時間 |
LMS_SLEEP |
ほかの理由によるスリープ |
ほかの待ち時間 |
LMS_STOPPED |
停止 (/proc、ジョブ制御、lwp_stop のいずれか) |
ほかの待ち時間 |
LMS_WAIT_CPU |
CPU 待ち |
CPU 待ち時間 |
タイミングデータは統計データとして収集されます。 このため、ほかの統計的な標本収集手法と同様に、あらゆる誤差の影響を受けます。プログラムの実行時間が非常に短い場合は、少数のプロファイルパケットしか記録されず、多くのリソースを消費するプログラム部分が、呼び出しスタックに反映されないことがあります。このため、目的の関数またはソース行について数百のプロファイルパケットを蓄積するのに十分な時間または十分な回数に渡って、プログラムを実行するようにしてください。
統計的な標本収集の誤差のほかに、データの収集・関連付け方法、システムにおけるプログラムの実行の進み具合を原因とする誤差もあります。次に示す環境などでは、タイミングメトリックでデータに不正確さやひずみが生じる可能性があります。
Solaris LWP または Linux スレッドが作成されるとき、最初のプロファイルパケットが記録されるまでの時間はプロファイル間隔より短いですが、プロファイル間隔全体の時間が、最初のプロファイルパケットに記録されるマイクロステートに帰せられます。多数の LWP またはスレッドが作成される場合、誤差はプロファイル間隔の数倍になることがあります。
Solaris LWP または Linux スレッドが破壊されるとき、最後のプロファイルパケットが記録されてから、少し時間が費やされます。多数の LWP またはスレッドが破壊される場合、誤差はプロファイル間隔の数倍になることがあります。
プロファイル間隔中に LWP またはスレッドの再スケジューリングが行われることがあります。このため、LWP について記録された状態に、プロファイル間隔の大半を費やしたマイクロステートが反映されないことがあります。Solaris LWP または Linux スレッドの方がそれらを実行するプロセッサの個数より多いほど、誤差は大きくなる可能性があります。
プログラムがシステムクロックと相関関係を持つ形で動作することがあります。この場合、Solaris LWP または Linux スレッドが費やされた時間のごく一部を表す状態にあるときに、常にプロファイル間隔の時間切れになり、プログラムの特定部分について記録された呼び出しスタックの出現回数が実際より多くなります。マルチプロセッサシステムでは、プロファイルシグナルによって相関関係が生じる場合があります。つまり、プログラム用の LWP の実行中にプロファイルシグナルによって中断されたプロセッサが、マイクロステートが記録されたときにトラップ CPU マイクロステートになる可能性があります。
カーネルは、プロファイル間隔の時間切れになったときにマイクロステート値を記録します。システムが過負荷状態の場合、この値に、プロセスの本当の状態が反映されないことがあります。Solaris OS では、この結果、トラップ CPU または CPU 待ちマイクロステート値が実際より大きくなることがあります。
システムクロックと外部ソースとの同期がとられている場合、プロファイルパケットに記録されるタイムスタンプはプロファイル間隔を反映しませんが、システムクロックに対して施された調整結果は組み込まれます。システムクロック調整の結果、プロファイルパケットが失われたかのように見える可能性があります。その時間は通常数秒間であり、調整は一定の増分単位で行われます。
これらの不正確さのほかにも、データ収集処理そのものが原因でタイミングメトリックが不正確になります。記録はプロファイルシグナルによって開始されるため、プロファイルパケットの記録に費やされた時間が、プログラムのメトリックに反映されることはありません。これは、相関関係の別の例です。記録に費やされたユーザー CPU 時間は、記録されるあらゆるマイクロステート値に配分されます。この結果、ユーザー CPU 時間のメトリックが実際より小さくなり、その他のメトリックが実際より大きくなります。デフォルトのプロファイル間隔の場合、一般に、データの記録に費やされる時間は CPU 時間の 2、3% 未満です。
時間ベースの実験のプロファイリングで得られたタイミングメトリックと、その他の方法で得られた時間を比較する場合は、次の点に注意する必要があります。
シングルスレッドアプリケーションの場合、通常 1 つのプロセスについて記録された Solaris LWP または Linux スレッド合計時間は、同じプロセスについて gethrtime(3C) によって返される値と比較すると、数十分の 1 パーセントの精度になります。CPU 時間の場合は、同じプロセスについて gethrvtime(3C) によって返される値と比較して、数パーセント程度異なることがあります。負荷が大きい場合は、差がさらに大きくなることがあります。ただし、CPU 時間の差は規則的なひずみを表すものではなく、関数、ソース行などについて報告される相対時間に大きなひずみはありません。
Solaris OS の非結合スレッドを使用するマルチスレッドアプリケーションの場合、gethrvtime() によって返される値の差が無意味であることがあります。これは、gethrvtime() は LWP について値を返し、スレッドは LWP ごとに異なることがあるからです。
パフォーマンスアナライザの報告する LWP 時間が、vmstat の報告する時間とかなり異なることがあります。 これは、vmstat が CPU 全体にまたがって集計した時間を報告するためです。たとえば、ターゲットプロセスの LWP 数が、そのプロセスが動作するシステムの CPU 数よりも多い場合、アナライザは、vmstat が報告する時間よりもずっと長い待ち時間を報告します。
パフォーマンスアナライザの「統計」タブと er_print 統計ディスプレイに表示されるマイクロステート時間値は、プロセスファイルシステムの /proc 使用報告に基づいており、この報告には、マイクロステートで費やされる時間が高い精度で記録されます。詳細は、proc (4) のマニュアルページを参照してください。これらのタイミング値と <合計> 関数 (プログラム全体を表す) のメトリックを比較することによって、集計されたタイミングメトリックのおおよその精度を知ることができます。ただし、「統計」タブに表示される値には、<合計> の時間メトリック値に含まれないその他の寄与要素が含まれることがあります。その原因は、データ収集が一時停止される期間によるものです。
ユーザー CPU 時間とハードウェアカウンタサイクル時間は異なります。なぜなら、ハードウェアカウンタは、CPU モードがシステムモードへ切り替えられたときにオフにされるからです。詳細は、「トラップ」を参照してください。