2 using System.Collections.Generic;
7 /// パフォーマンスカウンタを使用した高精度タイマ。
11 /// (A) 正確に同一の時刻を複数の処理で共有できるように、現在時刻をキャプチャしてから取得する方法。
12 /// 1. 最初に「現在のカウントをキャプチャする()」を呼び出し、その時点での時刻を内部に保存する。
13 /// 2. キャプチャされたカウントを、「現在のキャプチャカウントを……取得する()」を呼び出して、希望する単位で取得する。
14 /// (次に1.を行うまで、2.はずっと同じ時刻を返し続ける。)
15 /// (B) 常に現時刻(メソッド呼び出し時点の時刻)を取得する方法。
16 /// a. 「現在のリアルタイムカウントを……取得する()」を呼び出して、希望する単位で取得する。
18 /// b. 「生カウントを取得する()」を呼び出して、生カウンタを取得する。
20 /// 時刻の単位としては、[カウント], [秒], [100ナノ秒] を用意する。
23 /// "カウント" …………………… タイマインスタンスの生成時(または前回のリセット時)から「前回キャプチャされた時点」までの、パフォーマンスカウンタの差分(相対値)。
24 /// "リアルタイムカウント" …… タイマインスタンスの生成時(または前回のリセット時)から「現時点」までの、パフォーマンスカウンタの差分(相対値)。
25 /// "生カウント" ………………… パフォーマンスカウンタの生の値。::QueryPerformanceCounter() で取得できる値に等しい。システム依存の絶対値。
30 /// カウントが無効であることを示す定数。
32 public const long 未使用 = -1;
36 var dummy = QPCTimer.周波数; // プロパティの get() 内で qpc周波数 を更新させるためのダミーアクセス。
37 var now = QPCTimer.生カウント;
38 this.bs_前回リセットした時点の生カウント = now;
39 this.最後にキャプチャされたカウント = now;
40 this.稼働中に一時停止した時点のキャプチャカウント = now;
44 public static long 周波数
48 if( 0 > QPCTimer.qpc周波数Hz )
50 // 初めてのアクセスならシステムから値を取得する。
51 QPCTimer.qpc周波数Hz = System.Diagnostics.Stopwatch.Frequency;
53 return QPCTimer.qpc周波数Hz;
56 public static long 生カウント
57 => System.Diagnostics.Stopwatch.GetTimestamp();
58 public static double 生カウント相対値を秒へ変換して返す( long 生カウント相対値 )
59 => (double) 生カウント相対値 / (double) QPCTimer.qpc周波数Hz;
61 public long 現在のカウントをキャプチャする()
65 this.最後にキャプチャされたカウント = QPCTimer.生カウント;
66 return this.最後にキャプチャされたカウント;
70 public long 現在のキャプチャカウント
76 long count = ( 0 != this.一時停止回数 ) ?
77 ( this.稼働中に一時停止した時点のキャプチャカウント - this.bs_前回リセットした時点の生カウント ) : // 停止中
78 ( this.最後にキャプチャされたカウント - this.bs_前回リセットした時点の生カウント ); // 稼働中
83 public double 現在のキャプチャカウント秒単位
84 => ( (double) this.現在のキャプチャカウント / (double) QPCTimer.周波数 );
85 public long 現在のキャプチャカウント100ns単位
86 => ( 1000 * 1000 * 10 * this.現在のキャプチャカウント / QPCTimer.周波数 );
88 public long 現在のリアルタイムカウント
94 long count = ( 0 != this.一時停止回数 ) ?
95 ( this.稼働中に一時停止した時点のキャプチャカウント - this.bs_前回リセットした時点の生カウント ) : // 停止中
96 ( QPCTimer.生カウント - this.bs_前回リセットした時点の生カウント ); // 稼働中
101 public double 現在のリアルタイムカウント秒単位
102 => ( (double) this.現在のリアルタイムカウント / (double) QPCTimer.周波数 );
103 public long 現在のリアルタイムカウント100ns単位
104 => ( 1000 * 1000 * 10 * this.現在のリアルタイムカウント / QPCTimer.周波数 );
106 public long 前回リセットした時点の生カウント
112 return this.bs_前回リセットした時点の生カウント;
123 return ( 0 != this.一時停止回数 ) ? true : false;
133 return ( 0 == this.一時停止回数 ) ? true : false;
142 this.bs_前回リセットした時点の生カウント = QPCTimer.生カウント;
145 public void リセットする( long 新しいカウント )
149 this.bs_前回リセットした時点の生カウント = QPCTimer.生カウント - 新しいカウント;
156 if( 0 == this.一時停止回数 ) // 稼働中である
158 this.稼働中に一時停止した時点のキャプチャカウント = this.最後にキャプチャされたカウント;
167 if( 0 != this.一時停止回数 ) // 停止中である
171 if( 0 == this.一時停止回数 )
173 this.最後にキャプチャされたカウント = QPCTimer.生カウント;
174 this.bs_前回リセットした時点の生カウント = this.最後にキャプチャされたカウント - this.稼働中に一時停止した時点のキャプチャカウント;
180 private static long qpc周波数Hz = -1; // キャッシュ
181 private long bs_前回リセットした時点の生カウント = 0;
182 private long 最後にキャプチャされたカウント = 0;
183 private long 稼働中に一時停止した時点のキャプチャカウント = 0;
184 private int 一時停止回数 = 0;
185 private readonly object 排他利用 = new object();