「Linux/時計」の版間の差分
提供: Wikinote
< Linux
細 (→2 つの時計) |
細 (→タイマ割り込み処理) |
||
(同じ利用者による、間の5版が非表示) | |||
行36: | 行36: | ||
[ -x /sbin/hwclock ] && action $"Syncing hardware clock to system time" /sbin/hwclock $CLOCKFLAGS | [ -x /sbin/hwclock ] && action $"Syncing hardware clock to system time" /sbin/hwclock $CLOCKFLAGS | ||
+ | |||
+ | === タイマ割り込み処理 === | ||
+ | |||
+ | timer_interrupt() @ arch/i386/kernel/time.c あたりから。 | ||
+ | |||
+ | # xtime_lock のロックを取る。 | ||
+ | # do_timer_interrupt_hook() @ include/asm-i386/mach-default/do_timer.h | ||
+ | #: tick_divider の回数だけ以下の処理を繰り返す。デフォルトは 1 であり、設定しない限り 1 回のみ。 | ||
+ | ## do_timer() @ kernel/timer.c | ||
+ | ### jiffies_64 をインクリメント。 | ||
+ | ### update_times() | ||
+ | #### ticks = jiffies - wall_jiffies | ||
+ | #### wall_jiffies += ticks | ||
+ | #### update_wall_time() | ||
+ | #### calc_load(ticks) — ロードアベレージの計算 | ||
+ | ## update_process_times() @ kernel/timer.c | ||
+ | ### モードによって current のユーザー時間あるいはシステム時間を増加させる。 各 CPU 毎に用意されている cpustat の情報も更新する。 | ||
+ | ### run_local_timers() | ||
+ | #### raise_softirq() — ソフト割り込み | ||
+ | #### softlockup_tick() — soft lockup 検出処理 | ||
+ | #### scheduler_tick() — tick 毎のスケジューラ処理 | ||
+ | ### run_posix_cpu_timers() — タイマー処理 | ||
+ | ## profile_tick() @ kernel/profile.c — プロファイリングのための処理やフックがある。 | ||
+ | # xtime_lock をアンロック。 | ||
+ | |||
+ | ; tick_divider | ||
+ | : カーネルパラメータ divider で設定する。divider=10 を設定すると、タイマ割り込みの回数が 1/10 になる。このため、上記のように 1 回の割り込みで 10 回分のタイマ割り込み処理を行なう必要があるようだ。具体的には、jiffies は通常通り 1 秒間に 1000 増加するが (増加の粒度が荒くなり、10 ずつ一気に増えるイメージ)、/proc/interrupts の timer の値は 1 秒間に 100 しか増加しなくなる。VMware などが 1000Hz の割り込みを再現できず(?) 時計がずれる場合などに有効らしい。なんか強引で気持ち悪いね。 | ||
+ | |||
+ | [root@centos47 stap]# cat /proc/cmdline | ||
+ | ro root=LABEL=/ clock=pmtmr divider=10 | ||
+ | [root@centos47 stap]# while :; do grep timer /proc/interrupts ; sleep 1 ; done | ||
+ | 0: 647556 IO-APIC-edge timer | ||
+ | 0: 647657 IO-APIC-edge timer | ||
+ | 0: 647758 IO-APIC-edge timer | ||
+ | [root@centos47 stap]# ./jiffies.stp ← jiffies の値を表示する SystemTap スクリプト | ||
+ | Tue Mar 30 11:35:47 2010 jiffies=6444870 | ||
+ | Tue Mar 30 11:35:48 2010 jiffies=6445870 | ||
+ | Tue Mar 30 11:35:49 2010 jiffies=6446870 | ||
== 関連用語 == | == 関連用語 == | ||
行41: | 行79: | ||
: タイマ割り込みの回数を記録する。jiffies_64 の下位 32 ビットが jiffies。グローバルタイマ割り込みハンドラ do_timer() にてインクリメントされる。 | : タイマ割り込みの回数を記録する。jiffies_64 の下位 32 ビットが jiffies。グローバルタイマ割り込みハンドラ do_timer() にてインクリメントされる。 | ||
; HZ マクロ | ; HZ マクロ | ||
− | : 1 | + | : 1 秒間に発生するタイマ割り込みの回数。通常、RHEL では 1000、SLES では 250 に設定されている模様。 |
; xtime 変数 | ; xtime 変数 | ||
− | : 1970 | + | : 1970 年 1 月 1 日 0 時 0 分 0 秒からの経過秒数。グローバルタイマ割り込みハンドラ do_timer() にて進められる。timespec 型の構造体で、tv_sec には経過秒数が格納され、tv_nsec には tv_sec からのナノ秒単位の経過時間が格納される。 |
+ | |||
+ | == 参考文献 == | ||
+ | * [http://www.cis.udel.edu/~mills/database/rfc/rfc1589.txt RFC 1589: A Kernel Model for Precision Timekeeping] |
2010年3月30日 (火) 20:39時点における最新版
Linux でどのように時計が動いているのか。
2 つの時計
Linux だけでなく PC では、2 つの時計を用いて、電源の供給がない場合でも 時計がずれないように配慮されている。
- ハードウェアクロック (リアルタイムクロック; RTC)
- マザーボードに実装されたチップで、電源の供給がなくてもバッテリで進み続ける。精度はそれほどよくないため、OS 起動中は、基本的には参照されない。
- ソフトウェアクロック (システムクロック)
- カーネルが管理している、タイマ割り込みによって進められる時計 (カウンタ)。もちろん電源オフ時は消滅する。調節すれば、かなりの高精度になる。
- 電源オフ時、RTC のみが時間を刻んでいる。
- 起動時に OS が RTC の時刻を読み取り、以後タイマ割り込みでシステムクロックを刻む。
- NTP 等を利用していて時刻が正確だとわかると、11 分ごとにシステムクロックを RTC に書き戻す。
- シャットダウン時にシステムクロックを RTC に書き戻す。
- 1. に戻る
起動時・終了時の動作
起動時の RTC からシステムクロックへの読み込みは、/etc/rc.d/rc.sysinit で行われる。
- /etc/sysconfig/clock を読み込み
-
$CLOCKFLAGS
に--hctosys
を設定 -
UTC=yes|true
ならば、$CLOCKFLAGS
に--utc
を設定。UTC=no|false
ならば、--localtime
を設定 - 以下で hwclock を実行
[ -x /sbin/hwclock ] && /sbin/hwclock $CLOCKFLAGS action $"Setting clock $CLOCKDEF: `date`" /bin/true
終了時は /etc/rc.d/init.d/halt で、起動時とほぼ同様の動作が行われる。
--hctosys
が --systohc
になるだけである。
[ -x /sbin/hwclock ] && action $"Syncing hardware clock to system time" /sbin/hwclock $CLOCKFLAGS
タイマ割り込み処理
timer_interrupt() @ arch/i386/kernel/time.c あたりから。
- xtime_lock のロックを取る。
- do_timer_interrupt_hook() @ include/asm-i386/mach-default/do_timer.h
- tick_divider の回数だけ以下の処理を繰り返す。デフォルトは 1 であり、設定しない限り 1 回のみ。
- do_timer() @ kernel/timer.c
- jiffies_64 をインクリメント。
- update_times()
- ticks = jiffies - wall_jiffies
- wall_jiffies += ticks
- update_wall_time()
- calc_load(ticks) — ロードアベレージの計算
- update_process_times() @ kernel/timer.c
- モードによって current のユーザー時間あるいはシステム時間を増加させる。 各 CPU 毎に用意されている cpustat の情報も更新する。
- run_local_timers()
- raise_softirq() — ソフト割り込み
- softlockup_tick() — soft lockup 検出処理
- scheduler_tick() — tick 毎のスケジューラ処理
- run_posix_cpu_timers() — タイマー処理
- profile_tick() @ kernel/profile.c — プロファイリングのための処理やフックがある。
- xtime_lock をアンロック。
- tick_divider
- カーネルパラメータ divider で設定する。divider=10 を設定すると、タイマ割り込みの回数が 1/10 になる。このため、上記のように 1 回の割り込みで 10 回分のタイマ割り込み処理を行なう必要があるようだ。具体的には、jiffies は通常通り 1 秒間に 1000 増加するが (増加の粒度が荒くなり、10 ずつ一気に増えるイメージ)、/proc/interrupts の timer の値は 1 秒間に 100 しか増加しなくなる。VMware などが 1000Hz の割り込みを再現できず(?) 時計がずれる場合などに有効らしい。なんか強引で気持ち悪いね。
[root@centos47 stap]# cat /proc/cmdline ro root=LABEL=/ clock=pmtmr divider=10 [root@centos47 stap]# while :; do grep timer /proc/interrupts ; sleep 1 ; done 0: 647556 IO-APIC-edge timer 0: 647657 IO-APIC-edge timer 0: 647758 IO-APIC-edge timer [root@centos47 stap]# ./jiffies.stp ← jiffies の値を表示する SystemTap スクリプト Tue Mar 30 11:35:47 2010 jiffies=6444870 Tue Mar 30 11:35:48 2010 jiffies=6445870 Tue Mar 30 11:35:49 2010 jiffies=6446870
関連用語
- jiffies 変数
- タイマ割り込みの回数を記録する。jiffies_64 の下位 32 ビットが jiffies。グローバルタイマ割り込みハンドラ do_timer() にてインクリメントされる。
- HZ マクロ
- 1 秒間に発生するタイマ割り込みの回数。通常、RHEL では 1000、SLES では 250 に設定されている模様。
- xtime 変数
- 1970 年 1 月 1 日 0 時 0 分 0 秒からの経過秒数。グローバルタイマ割り込みハンドラ do_timer() にて進められる。timespec 型の構造体で、tv_sec には経過秒数が格納され、tv_nsec には tv_sec からのナノ秒単位の経過時間が格納される。