toge's diary

コンピュータ関連の趣味をつらつらと。

Windowsで細かく時間を計測する

この一週間はWindowsなのでgettimeofdayが使えなくて不便なのです。
timeGetTime()ではせいぜいms精度なので、高速モード付きとかで、100fps前後のゲームで使おうとすると・・・ということでQueryPerformanceCounter()を使うことにしました。

QueryPerformanceFrequency()で1秒あたりのカウントが取得できます。この値を使ってQueryPerformanceCounter()とか使うとマイクロ秒単位の精度が出せる・・・はずなのですが、そこまでうまくいかないのよね。
近頃はSpeedStepとかPowerNow!のために動的にクロックが変わります。
QueryPerformanceFrequency()はそんなことお構いなしにWindows起動時の値を返します。

おかげでNotePCだともうぐちゃぐちゃになってしまう・・・らしい。

というわけでQueryPerformanceCounter()はあんまり使われないみたいなのですが、やっぱり使いたくてしょうがないので、工夫してみました。
これで精度が高くなる保障はどこにもないんですけどね。10秒ぐらい計測すればもう少しましになるかも。

// 初期化ルーチン
void init() {
  // 計測開始
  DWORD sampleStart = timeGetTime();
  LONGLONG cntStart;
  QueryPerformanceCounter((LARGE_INTEGER *)&cntStart);

  // 1秒待つ
  Sleep(1000);

  // 計測終了
  DWORD sampleEnd = timeGetTime();
  LONGLONG cntEnd;
  QueryPerformanceCounter((LARGE_INTEGER *)&cntEnd);

  // timeGetTime()の経過時間より、1カウントあたりの秒数を計測する
  secondPerCounter_ = (sampleEnd - sampleStart) / 1000.0 / (cntEnd - cntStart);
}

// 現在の時刻
double now() {
  LONGLONG current;
  QueryPerformanceCounter((LARGE_INTEGER *)¤t);
  // 1カウントあたりの秒数をかければ現在の秒数が出てくる
  return current * secondPerCounter_;
}