プロセッサー・タイマーのアクセス

非常に短い時間間隔を測定する試みは、 しばしばオペレーティング・システムの一部である断続的なバックグラウンド・アクティビティーによって、 またはシステム時間ルーチンが使用する処理時間によって失敗します。 この問題を解決する 1 つの方法は、 プロセッサー・タイマーに直接アクセスして測定間隔の開始時刻と終了時刻を判別し、 測定を繰り返し実行してから、結果をフィルター処理して、割り込みが介在した期間を除去することです。

POWER ® および POWER2 アーキテクチャーは、プロセッサー・タイマーを特殊目的のレジスターのペアとして実装します。 POWER プロセッサー・ベースの アーキテクチャーは、 TimeBaseと呼ばれる 64 ビット・レジスターを定義します。 このようなレジスターにアクセスできるのはアセンブラー言語プログラムのみです。
注: プロセッサー・タイマーによって測定される時間は、絶対壁時計時刻です。 タイマーへのアクセスと次のアクセスの間に割り込みが発生した場合、 計算される期間には、割り込みの処理だけでなく、 時間を測定中のコードに制御が戻る前にディスパッチされた他の処理が含まれる可能性があります。 プロセッサー・タイマーからの時間は、ローの時間であり、 妥当性テストを受けない状態で使用すべきではありません。

アーキテクチャーに関係なく、3 つのライブラリー・サブルーチンが TimeBase レジスターにアクセスします。 これらのサブルーチンは、以下のものです。

read_real_time()
このサブルーチンは、 適切なソースから現在の時刻を取得し、2 つの 32 ビット値として保管します。
read_wall_time()
このサブルーチンは適切なソースから生の TimeBase レジスター値を取得し、2 つの 32 ビット値として保管します。
time_base_to_time()
このサブルーチンは、TimeBase フォーマットから必要な変換を行って、 時刻値を秒とナノ秒単位にします。

時刻取得関数と時刻変換関数は、 時刻取得のオーバーヘッドを最小化するために分離されています。

以下の例は、コードの特定の部分の経過時間を測定するために、read_real_time() および time_base_to_time() サブルーチンを使用する方法を示しています。
#include <stdio.h>
#include <sys/time.h>

int main(void) {
   timebasestruct_t start, finish;
   int val = 3;
   int w1, w2;
   double time;

   /* get the time before the operation begins */
   read_real_time(&start, TIMEBASE_SZ);

   /* begin code to be timed */
   printf("This is a sample line %d \n", val);
   /* end code to be timed   */

   /* get the time after the operation is complete
   read_real_time(&finish, TIMEBASE_SZ);

   /* call the conversion routines unconditionally, to ensure    */
   /* that both values are in seconds and nanoseconds regardless */
   /* of the hardware platform.                                  */
   time_base_to_time(&start, TIMEBASE_SZ);
   time_base_to_time(&finish, TIMEBASE_SZ);

   /* subtract the starting time from the ending time */
   w1 = finish.tb_high - start.tb_high; /* probably zero */
   w2 = finish.tb_low - start.tb_low;

   /* if there was a carry from low-order to high-order during  */
   /* the measurement, we may have to undo it.                  */
   if (w2 < 0) {
      w1--;
      w2 += 1000000000;
   }

   /* convert the net elapsed time to floating point microseconds */
   time = ((double) w2)/1000.0;
   if (w1 > 0)
      time += ((double) w1)*1000000.0;

   printf("Time was %9.3f microseconds \n", time);
   exit(0);
}

タイマー・ルーチンの呼び出しおよびタイマー・ルーチンからの戻りのオーバーヘッドを最小限に抑えるために、ベンチマーク非共有のバインドを試すことができます ( ダイナミック・リンクおよび静的リンクを使用する場合を参照)。

これが実際のパフォーマンス・ベンチマークの場合は、 このコードが繰り返し測定されることになります。 多くの連続する繰り返しが合計の時間を測定される場合は、 オペレーションの平均時間を計算できますが、 割り込み処理または他の無関係なアクティビティーを含んでいる可能性があります。 多くの繰り返しの時間を個別に測定する場合には、 個別の時間の妥当性を検査できますが、 測定ごとにタイミング・ルーチンのオーバーヘッドが含まれます。 両方の手法を使用して、 結果を比較することが望ましい場合があります。 いずれにしろ、測定方法を選択する場合に、 その目的が何かを考慮する必要があります。