adjtimexによる時計の調整
あるマシンでetch→lennyとしたところ、いつまで待ってもNTPで時刻同期できない状態になってしまった。こんなときはadjtimexを使えば良かったんだっけと、あまりあてにならない記憶に従ってみた。
# dpkg-reconfigure adjtimex
これは/usr/sbin/adjtimexconfigを実行すると同じようなことで、adjtimexconfigはadjtimex --adjustを実行するとの同じようなことである。adjtimex --adjustは時刻のズレを調整してくれるものであったと考えていたのだが、結果からすると状況を改善することができなかった。
以前にも何度かこの手の格闘をしてきており、その都度、調べたり試したりで状況を治めてきたはずなのに、などと今度も思いつつ、しょうがないからadjtimexのマニュアルをななめに見てからadjtimexconfigをななめに見て、/etc/default/adjtimexに記述されているTICKとFREQを調整すれば良さそうだというところにたどりついた。
TICKとFREQはadjtimexの--tickおよび--frequencyという二つのオプションに対する引数として使われている。
USER_HZ=100の一般的な環境では一秒間に100回の割り込みがあり、システム時計はそのたびに10,000msずつ進められる…… というのが理想的な状態。実際にはそううまくいかないわけで、システム時計の進め幅を調整する必要が出てくる。
--tickオプションはこの進め幅を指定する。単位はmsなので10,000前後の値となる。10,000→10,001と変えたとすると、一秒(割り込み100回)あたり100ms、一日で8.64秒だけシステム時計の進みが速くなる。--tickオプションよりも小さな幅で調整するのが--frequencyオプションで、0を基本として、進めるなら正の値、遅らせるなら負の値を指定する。--frequency 65536とすると、一秒あたり1msだけシステム時計が速く進むようになる。
# vi /etc/default/adjtimex # update-rc.d adjtimex start; ntpdate -bv ntpserver; sleep 100; ntpdate -bv ntpserverなんて感じで、前述の二つの値の上下を繰り返しながら、システム時計の進みを調整し、ようやくNTPによる時刻同期がとれるようになった。
adjtimexの使い方
後になってadjtimex(8)を見直してみると、そんな繰り返しをしなくてもよさそうな機能が備っていることがわかった。当然ともいえる。 まず--compareオプション。これを指定して実行すると、10秒間隔でRTC(ハードウェア上の時計)とシステム時計を読み取って、そのズレの度合いを導き出すことができる。また適切と考えられるTICK/FREQの値も同時に導き出される。このときの基準はRTCだが、adjtimex --log --host ntpserverのように指定して実行すると、ntpdateによりNTP時刻を参照した上で、それとのズレが/var/log/clocks.logに記録される。このファイルの内容はadjtimex --reviewにより参照でき、NTP時刻を基準にした場合のTICK/FREQが導かれる。 ここで--adjustオプションに戻ってみると、これは--compareの結果をそのまま設定してしまうという動作をさせるオプションである。つまり、RTCを信頼してシステム時計を調整するためのオプションである。となると、発端となったホストのRTCはあまり正確ではなく、adjtimex --adjustをしてもシステム時計の進みはおかしなまま。その結果としてNTPが許容できる範囲を越えたシステム時計の進み具合い(または遅れ具合い)となり、同期がとれなくなったものと考えられる。 実際、以下のようにadjtimexを実行すると、RTCがどんどんズレていく様子が見られる。# adjtimex --compare --- current --- -- suggested -- cmos time system-cmos error_ppm tick freq tick freq 1240113783 -0.037287 1240113792 0.063180 10046.7 9999 4807606 1240113801 0.163457 10027.8 9999 4807606 9899 2986972 1240113810 0.263660 10020.3 9999 4807606 9899 3479160 1240113819 0.363839 10017.9 9999 4807606 9899 3635410 1240113828 0.463941 10010.2 9999 4807606 9899 4140098 1240113837 0.564190 10024.9 9999 4807606 9899 3176035 1240113846 0.664455 10026.6 9999 4807606 9899 3066660
adjtimexでシステム時計を調整する
問題のホストとは別のホストでadjtimexによるシステム時計の調整を試みた。
まず、adjtimexconfigを使ってみる。前述の通り、これはadjtimex --adjustを実行するのと同等であり、システム時計の進み具合をRTCの進み具合に合わせるための調整となる。設定された内容はadjtimex --printにより確認できる。
$ adjtimex --print mode: 0 offset: 0 frequency: 5951052 maxerror: 16000000 esterror: 16000000 status: 65 time_constant: 10 precision: 1 tolerance: 32768000 tick: 9999 raw time: 1240109330s 387925us = 1240109330.387925 return value = 5NTP時刻との比較を行ってみたところ、以下のようにこのホストのRTCはなかなか正確であることがわかる。
$ ntpdate -q ntpserver; sleep 100; ntpdate -q ntpserver server 172.16.100.100, stratum 3, offset 0.079893, delay 0.02580 19 Apr 11:45:42 ntpdate[24278]: adjust time server 172.16.100.100 offset 0.079893 sec server 172.16.100.100, stratum 3, offset 0.084867, delay 0.02580 19 Apr 11:47:22 ntpdate[24289]: adjust time server 172.16.100.100 offset 0.084867 sec
adjtimexでシステム時計をNTP時刻に合わせる
次に--logオプションと--hostオプションを使って、NTP時刻を基準にした調整を行ってみる。adjtimexconfigでは調整に70秒の時間をとっているため、ここでも70秒だけおいてみることにした。まずはシステム時計の進み具合いを調査する。# adjtimex --tick 10000 --frequency 0 (上の設定をリセットするために実行) # adjtimex --log --host ntpserver; sleep 70; adjtimex --log --host ntpserver reference time is Sun Apr 19 11:49:11 2009 reference time - system time = 1240109351.090 - 1240109351.000 = 0.090 sec No previous clock comparison in log file Are you sure that, since Thu Jan 1 09:00:00 1970, the real time clock (cmos clock) has run continuously, it has not been reset with `/sbin/hwclock', no operating system other than Linux has been running, and ntpd has not been running? (y/n) [n] (ここで一回目のadjtimexが終了) reference time is Sun Apr 19 11:50:27 2009 reference time - system time = 1240109427.093 - 1240109427.000 = 0.093 sec Last clock comparison was at Sun Apr 19 11:49:11 2009 Kernel time variables are unchanged - good. System clock is currently not disciplined - good. Checking wtmp file... System has not booted since Sun Apr 19 11:49:11 2009 - good. System time has not been changed since Sun Apr 19 11:49:11 2009 - good. Checking /etc/adjtime... /sbin/hwclock has not set system time and adjusted the cmos clock since Sun Apr 19 11:49:11 2009 - good. Are you sure that, since Sun Apr 19 11:49:11 2009, the system clock has run continuously, it has not been reset with `date' or `/sbin/hwclock`, the kernel time variables have not been changed, and the computer has not been suspended? (y/n) [y] The estimated error in system time is -40.6706732 +- 0.0458581 ppm Are you sure that, since Sun Apr 19 11:49:11 2009, the real time clock (cmos clock) has run continuously, it has not been reset with `/sbin/hwclock', no operating system other than Linux has been running, and ntpd has not been running? (y/n) [y] The estimated error in the cmos clock is -52.00 +- 0.05 ppmこれにより得られた情報で設定をする。このために指定するのはやはり--adjustオプションだが、さらに--reviewオプションも指定する。 --reviewは--logにより記録された情報を参照するためのオプションで、記録情報からTICK/FREQを導き出すことができる。これを--adjustとともに使うと、RTCとの比較にからず、記録情報か得られたTICK/FREQを設定できる。
# adjtimex --adjust --review start finish days sys - cmos (ppm) Sun Apr 19 11:49:11 2009 Sun Apr 19 11:50:27 2009 0.0009 13.2 +- 0.2 start finish days cmos_error (ppm) Sun Apr 19 11:49:11 2009 Sun Apr 19 11:50:27 2009 0.0009 -53.83 +- 0.03 start finish days sys_error (ppm) Sun Apr 19 11:49:11 2009 Sun Apr 19 11:50:27 2009 0.0009 -40.67 +- 0.03 least-squares solution: cmos_error = -53.8 +- 0.3 ppm suggested adjustment = 4.6511 sec/day current adjustment = 0.0038 sec/day sys_error = -40.7 +- 0.3 ppm suggested tick = 10000 freq = 2665447 current tick = 10000 freq = 0 note: clock variations and unstated data errors may mean that the least squares solution has a bigger error than estimated here new tick = 10000 freq = 2665447
以上により、NTP時刻を基準としてシステム時計の調整を行うことができたはずである。先程と同様にNTP時刻との比較をしてみる。
$ ntpdate -q ntpwerver; sleep 100; ntpdate -q ntpserver server 172.16.100.100, stratum 3, offset 0.094815, delay 0.02580 19 Apr 11:51:24 ntpdate[24319]: adjust time server 172.16.100.100 offset 0.094815 sec server 172.16.100.100, stratum 3, offset 0.094798, delay 0.02580 19 Apr 11:53:04 ntpdate[24325]: adjust time server 172.16.100.100 offset 0.094798 sec
ここではNTPによる時刻同期をしたわけではないので時刻のズレ自体は問題ではない。時刻のズレの進み具合いが問題となる。adjtimexconfigによる調整では一秒につき(0.084867 - 0.079893)/100 = 49.74msづつNTP時刻よりも進んでいくことがわかる。一方、NTPを使ってadjtimexしたあとでは一秒につき(0.094798 - 0.094815)/100 = -0.17msづつNTP時刻よりも進んでいく(つまり0.17msずつ遅れていく)。
hwclockとの関係
adjtimex --compareや--adjustでは、RTCから値を読み取る際に/etc/adjtimeの内容による補正を行っている。同ファイルはhwclockにより作られるものである。
hwclockは、RTCを書き換えるときに、RTCの値との差分を/etc/adjtimeに記録する。そしてhwclockでシステム時刻を設定する際にはRTCの値そのものではなく/etc/adjtimeに記録されている情報でRTCの値を補正したものを設定する。つまりシステム時計を基準にしたときのRTCのズレ具合いが/etc/adjtimeに記録されているということを意味する。
hwclockによって行われる調整は、RTCからシステム時刻を得るときに使われるものである。これはシステム時計の進み方や遅れ方を調整するものではない。むしろシステム時計が未調整であるならばhwclockの仕組み使った結果としてシステム時刻は適切にズレてしまうことになるとも言える。
簡単なまとめ
RTCは通常、一定の進み方を示すか、一定の遅れ方を示す。この幅が小さければ実用上、時刻のズレで困ることはない。あるいはNTPにより時刻同期が可能である。最近のPCであれば、NTPで対処できないほどにRTCがズレるということもないのではないかと思う。したがってここに書いたようなことをする必要はあまりない。
ただ、NTPでもどうにもならないといったときにはadjtimexの出番となる。adjtimexを使えばシステム時計の進み方や遅れ方を調整できる。