durationのtemplate parameterである、Periodは、コンパイル時定数である。Periodは、Rep1カウントあたりの経過秒数を、秒単位で表現する。つまり、ミリ秒の分解能を持っているならば、std::milli(typedef ratio<1, 1000> milli;)が使える。
しかし、現実のハードウェアタイマーは、そんな分かりやすい分解能を持っていない。しかも、プログラムが実行される環境のハードウェアが、実行時にしか分からない場合もある。一体どうするのか。
いや、そもそも、そんなに使いづらい、ハードウェアの限界の分解能を使うだろうか、ミリ秒だとか、マイクロ秒だとか、分かりやすい単位にした方がいいのではないか。
たとえば、HPETを有効にした私のWindows環境では、QueryPerformanceFrequencyは、14318180を返す。
これは、一秒間に、14318180回のカウントができると言うことを意味する。すなわち、1クロックは、約70ナノ秒である。
しかし、私の環境でHPETを無効にすると、QueryPerformanceFrequencyは、3579545を返す。これは、1クロックあたり、約279ナノ秒である。
HPETの有無は、実行時にしか分からない。ということは、通常のx86なWindows環境に置いては、マイクロ秒単位が、安全なのだろうか。まあ、そういうきりの良い数字なら、コンパイル時に指定できるし。
なんとなく、Windows環境で動くhigh_resolution_timerを書いてみたけど、std::ratioとstd::chrono::durationとstd::chrono::time_pointがないために、実行できない。
namespace std { namespace chrono { struct Freq { LARGE_INTEGER freq ; Freq() { QueryPerformanceFrequency( &freq ) ; } } ; class high_resolution_clock { static Freq freq ; public: typedef std::int64_t rep; typedef std::micro period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<high_resolution_clock , duration> time_point; static const bool is_monotonic = false ; static time_point now() { LARGE_INTEGER count ; //if ( QueryPerformanceCounter( &count ) == 0 ) //{// エラーの場合、どうすればいいのだろう。規格は何も言及してない。 // count.QuadPart = 0 ; // return time_point( duration.zero() ) ; //} QueryPerformanceCounter( &count ) ; rep tick = static_cast(double(count.QuadPart) / (double(freq.freq.QuadPart) / 1000000.0) ) ; //rep tick = count.QuadPart / (freq.freq.QuadPart / 1000000) ; return time_point( duration(tick) ) ; } } ; Freq high_resolution_clock::freq ; } }
No comments:
Post a Comment