2010-02-21

chronoって、コンパイル時定数にできない場合、どうするのだろう

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: