14.318180MHz

Linux のスリープ処理、タイマ処理の詳細を見る
これに触発されてWindowsだとどんなもんなのか、自分の記憶があやふやだったので確認してみた。


処理1(低精度)

DWORD Timestamp[256];
int i;
for ( i = 0; i < 256; ++i ) {
  Timestamp[i] = ::timeGetTime();
  // ここに処理を入れる
  Sleep(1);
}

これの結果は
15, 31, 47, 62, 78, 93
という感じになる。
OSや機種など環境に依存するが、XPだと15msのことが多いようだ。
単に待てばいい処理ならこれでOK。


処理2(精度向上)

timeBeginPeriod( 1 );
Sleep( 1000 );  // 精度向上が反映されるのを待つ
DWORD Timestamp[256];
int i;
for ( i = 0; i < 256; ++i ) {
  Timestamp[i] = ::timeGetTime();
  // ここに処理を入れる
  Sleep(1);
}
timeEndPeriod( 1 );

これの結果は
0, 1, 3, 5, 7, 9
という感じ。
精度が良くなったが、1ms飛んでいる模様。
先頭にSleepが入っている理由は、timeBeginPeriod()で精度を上げることができる(どこまで上げられるかはtimeGetDevCaps()で取得)のだが、いくばくかしないと反映されないため。


処理3(ほぼ1ms精度)

HANDLE event = ::CreateEvent( NULL, FALSE, FALSE, NULL );  // 自動リセットイベント
timeBeginPeriod( 1 );
Sleep( 1000 );
int timer_id = ::timeSetEvent( TIMER_PERIOD, TIMER_PERIOD, (LPTIMECALLBACK)event, 0, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET );
__int64 Timestamp[TIMER_LOOPS];
int i;
for ( i = 0; i < 256; ++i ) {
  ::QueryPerformanceCounter( (LARGE_INTEGER *)( Timestamp + i ) );
  // ここに処理を入れる
  ::WaitForSingleObject( event, 50 );
}
::timeKillEvent( timer_id );
timeEndPeriod( 1 );
::CloseHandle( event );

GetTickCount()やtimeGetTime()ではmsオーダーしかわからないので、QueryPerformanceCounter()で見てみることに。
結果、イベントを使えばほぼ1msの周期処理が可能になることがわかった。


というわけでWindowsでも1ms精度なら可能…と思いきや数値を良く見てみると
0.985321, 0.977219, 0.976381, 1.952762
のように、おおむね0.97ms程度で、41〜42msに一度は1.4ms以上の部分がある。
1.2ms以上のものを除外してみたところ、0.976105msという結果が得られた。
どうやら1000Hzではなく、1024Hzがベースになっていて、たまにつじつまを合わせているようだ。


ところでnaoya氏の記事に出てくるマジックナンバー「1193182」について。これはPIT(8253 or 8254)に対するマスタークロックと説明されているのだが、何でこんな中途半端な値なのかというと、初代IBM-PCが入手しやすいTV用の14.318180MHzの水晶を使ったからだそうな。14.318180MHzを3分周した4.77MHzをCPUのクロック、それをさらに4分周した1.193182MHzをPITのクロックにしたのが今まで残っているという。

それでもって、今のPCに8254なんて載っているのかと思いデータシートを見てみた。基本的にはI/Oコントローラであるサウスブリッジに内蔵されているようなのだが、AMDチップセットには説明があったが、Intelのものには見当たらず。
古いデータシートを見てみたところ、ICH3には記載があるが、ICH4からはなくなっていた。ICH4からはISAのサポートがなくなったとのことで、記載はなくても互換機能が搭載されているのか、外付けになっているのかはわからなかった。

ただ、ICH3のデータシートには「The 8254 unit is clocked by a 14.31818 MHz clock.」とあり、現在でもPITだけでなくFSBPCIなど全ての基本クロックを未だに14.31818MHzから作り出しているらしい。レガシー恐るべし。