WindowsにおけるSleep(1)の精度について

WindowsのプログラムでSleep(1)を実行するとその実行にかかる時間は期待する1msとは違って、約10ms、約16ms、約55msのいずれかとなり装置によって異なる。 装置によってSleep(1)の実行時間が異なるのは、OSが使用するタイマーの種類とタイマーへの設定値の違いによるタイマー割り込みの分解能の違いが原因である。
Windowsの時間の制御は周期的なタイマー割り込みを使っている。プログラムをSleep()から復帰させるのはOSのスケジューラの仕事である。スケジューラはタイマー割り込みの分解能よりも短い時間で要求されたSleep()の実行をその時間で完了させることは保障できない。タイマー割り込みの分解能よりも高い精度は出せない。これが「Sleep()は精度が悪い」といわれる事象である。
Windows 9x系においてはPIT (Programmable Interval Timer)の入力信号1.1931817MHzを65,536分周した約18.2Hz (間隔は約54.9ms)による割り込みを使っているためタイマー割り込みの周期は約55msとなる。(1.1931817MHzはNTSCテレビ受信機向け14.31818MHz水晶振動子の出力を3分周した4.77272666…MHz(IBM Personal Computer "The PC"のCPUクロック)をさらに4分周したものとのこと。1.193181666…MHz)
Windows NT系ではHALによりRTC (real-time clock)またはPITのどちらかが使われる。基本的にはPIC (Programmable Interrupt Controller)がAPIC (Advanced Programmable Interrupt Controller)の場合にRTCが使われる。 RTCの場合32.768kHz(時計用32.768kHz水晶振動子が由来)の入力信号を分周して2Hz (512ms)〜256Hz (3.90625ms)の割り込みを設定することができ、そのうちの64Hz (15.625ms)が使われるため約16msとなる。PITの場合は約10msとなる。

タイマー割り込みの周期はtimeBeginPeriod()timeEndPeriod()を使って変更することができる。しかし、RTCを使っている場合に頻繁に間隔を変更する(一時的に高い精度にして必要な処理が終わると元の精度に戻すということを繰り返す)と時計が進んでしまう。それはPITの場合、設定を変更するとそのタイミングからカウントが始まるのに対して、RTCの場合はそうではないからである。RTCは元から2Hz〜256Hzの15通りの割り込み信号がありどれを使うかを選択するようになっている。割り込みのタイミングは始めから決まっているのでどのタイミングで切り替えても次の割り込みの時刻は変わらない。そのため切り替えた最初の割り込みまでの間隔は期待される時間よりも短いことがある。この差分だけ時計が進んでしまう。
タイミング
図の途中たとえば5のあたりでタイマー周期を標準に戻すと、戻した最初の割り込みは切り替えの15.625ms後ではなくもっと短い時間で割り込みが発生する。これが時計が進んでしまう原因である。

Microsoftサポート技術情報 821893 The system clock may run fast when you use the ACPI power management timer as a high-resolution counter on Windows 2000-based, Windows XP-based, and Windows Server 2003-based computers より引用。
This issue may occur if the time increment in a program changes and the Hardware Abstraction Layer (HAL) cannot measure the time interval between successive clock interrupts. This causes the system clock to lose a short period of time. When the HAL misses many time-interval measurements in quick succession, the time loss may be significant.

Note
また、Multimedia Timerを使用するプロセスがあるとSleep()の精度が変わることがある。これはMultimedia Timerが内部的にtimeBeginPeriod()、timeEndPeriod()を使っているからである。

2007-09-03 - お仕事メモ帳 ■[Windows]タイマの精度 より引用。

[]タイマの精度

CEではなくx86のお話。

もう去年になりますか、客先のプログラムの動作がおかしいということで調べてみると、どうやらタイマの精度が正しくないということがわかりました。

対策を立てるために客先からドライバ開発ベンダーMSに問い合わせのメールを送るも誤差が生じているなどあまりにも不明瞭な回答が…*1

こちらでも動かないと埒があかないと思って、問題が発生しているマシンのメーカにも質問を出したら以下のような回答が帰ってきました。

あまりにも他がダメダメだったのでこのサポートの回答には惚れてしまいました。

やはり日本のメーカーだぜとか言いたくもなりますが、ノートPCのようにH/Wの設計をしっかりやっているメーカーはすごいと思わざるをえません。

この動作の原因は、Windows XPハードウェア アブストラクションレイヤ モジュール:HAL.DLL の仕様の違いによるものであり、そのPCが使用しているHALの種類によってタイマ精度が決まります。

タイマ精度 約 10mS となるマシンは halacpi.dll が使用されており、タイマ精度 16mS となるマシンには halaacpi.dll が使用されております。

最近の機種では、割り込みコントローラAPIC (Advanced PIC) を 使用しておりまして、この場合、HAL は halaacpi.dll が使用されます。

また、比較的古い機種の多くは、割り込みコントローラPIC (Programmable Interrupt Controller) を使用しておりまして、 この場合、HAL は halacpi.dll が使用されます。

これらの HAL は PC のタイマハードウェアを制御し、 それぞれのタイマ精度の設定値が異なりますため、 ご指摘いただいております現象となります。

以下の2つの操作で、その違いを見分けることができます。

●操作1

Windows\System32 フォルダにございます HAL.DLLプロパティにて、「正式ファイル名」を参照していただくと、上記のどちらの HAL を使用しているかが分かります。

●操作2

コントロールパネルのシステム アプレットにて、[ハードウェア] タブの[デバイス マネージャ] をクリックし、[コンピュータ] の下に表示されるデバイス名を確認していただきますと、以下のデバイスのどれかが表示されます。

ACPI マルチプロセッサ PC = Halmacpi.dll

ACPI ユニプロセッサ PC = Halaacpi.dll

ACPI (Advanced Configuration and Power Interface) PC = Halacpi.dll

MPS マルチプロセッサ PC = Halmps.dll

MPS ユニプロセッサ PC = Halapic.dll

標準 PC = Hal.dll

Compaq SystemPro マルチプロセッサまたは 100% 互換性がある PC = Halsp.dll

マルチプロセッサおよび APIC の機種でのタイマー精度は、通常約 16ms となります。

(この値も、ハードウェアデバイスドライバの実装に依存するため、保証は難しくなります)

というわけで、Vistaでは変わっているかも知れませんが、16msあたりがタイマの精度のようです。

HALってこういうのも吸収するんじゃないのと思っていたのですが、Windowsな世界の方々は誤差なんでしょうかね。

Permalink | コメント(0) | トラックバック(0) | 16:48 タイマの精度 - お仕事メモ帳 を含むブックマーク はてなブックマーク - タイマの精度 - お仕事メモ帳 タイマの精度 - お仕事メモ帳 のブックマークコメント

*1MSに問い合わせたかはわかりませんが

参照
第3回 なぜ14.31818MHz水晶発振子?
■[Windows]14.318180MHz
楽しいハック講座(1) マルチメディアタイマー
2006-09-10 random staccato Multimedia Class Scheduler Service (MMCSS)
スーパープログラマーへの道 第71回 割り込みイベント処理(timeBeginPeriodの周辺) 99/9/9

もどる