LoginSignup
1
1

More than 1 year has passed since last update.

【時間の精度】タイマーや待機処理がなんか変だと思ったら

Posted at

ちょっと待機時間を設けよう。処理の時間計測をしよう。
そんなことはちょいちょいありますよね。
しかし、そのタイマーがこっそり変な動きをしていることがあります。
それはその機能の精度が原因です。

ダメな例

Sleepという、いかにもなWindows APIがあります。
宣言は以下

void Sleep(
  [in] DWORD dwMilliseconds
);

引数に待機時間をミリ秒単位で指定できます。

実験

Sleepが何ミリ秒スリープできているか、確認してみます。

    for (int i = 0; i < 10; i++)
	{
		FILETIME startFileTime = { 0 };
		::GetSystemTimePreciseAsFileTime(&startFileTime);
		
		::Sleep(1);

		FILETIME endFileTime = { 0 };
		::GetSystemTimePreciseAsFileTime(&endFileTime);
		
		ULONG64 startTime = startFileTime.dwLowDateTime + ((ULONG64)startFileTime.dwHighDateTime << 16);
		ULONG64 endTime = endFileTime.dwLowDateTime + ((ULONG64)endFileTime.dwHighDateTime << 16);

		printf("%llu\r\n", endTime - startTime);
	}

10連続で、Sleepにかかった時間を計測して見ます。自分の環境では以下の結果となりました。
スクリーンショット 2023-01-28 184546.png
FileTimeは単位が100ナノ秒なので、ミリ秒に直すと4ms~15msがSleep(1);にかかった時間ということになります。

回答

SleepのMSDNのページに回答はあります。
システムクロックが一定間隔で行われ、そのtickをSleep時間のチェック基準としています。tickの発生間隔が長いほど、その精度が悪くなるということです。
tickの頻度を上げるためにtimeBeginPeriodというWindows APIが提供されています。

実験

for (int i = 0; i < 10; i++)
	{
		::timeBeginPeriod(1);
		FILETIME startFileTime = { 0 };
		::GetSystemTimePreciseAsFileTime(&startFileTime);
		
		::Sleep(1);

		FILETIME endFileTime = { 0 };
		::GetSystemTimePreciseAsFileTime(&endFileTime);
		::timeEndPeriod(1);

		ULONG64 startTime = startFileTime.dwLowDateTime + ((ULONG64)startFileTime.dwHighDateTime << 16);
		ULONG64 endTime = endFileTime.dwLowDateTime + ((ULONG64)endFileTime.dwHighDateTime << 16);

		printf("%llu\r\n", endTime - startTime);
	}

結果は以下
スクリーンショット 2023-01-28 184554.png

1.5ms~1.9msになったので、大分マシになりましたね。

注意喚起

timeBeginPeriodを使っておけば良いというわけではありません。
Sleepのページの注意書きにもある通り、システムクロック、システム電力使用量、スケジューラーに大きな影響を与えるためです。

おまけ

Sleep(0);の場合は、タイマー精度を変更しなくても、ほぼ0msの待機になります。
Sleep(0);は0ms待機という目的で使われるわけではなく、別スレッドにタイムスライスを譲るという意味合いだからです。

その他精度が低いやつ

  • GetTickCount64
    • システムが開始されてから経過したミリ秒数を取得
  • timeGetTime
    • システム時刻をミリ秒単位で取得

タイマーの結果がなんか変だな、と思った方の役に立てれば幸いです。
用途によって、使い分けて行きましょう。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1