最終更新:ID:TygpIs2TcQ 2011年06月22日(水) 19:54:06履歴
- カーネルの行う時間管理
- 現在日時の保持
- ユーザプログラムからtime(), ftime(), gettimeofday()で取得可能。
- タイマの仕組みの管理
- 特定の時間が経過したことを通知
- 現在日時の保持
- RTC(Real Time Clock)
- ボタン型電池によりPCの電源とは無関係に動作。
- モトローラ146818または同等品に実装。
- 2Hz〜8196Hzの周波数でIRQ8割り込みを発生させる。
- Linuxでは、日時を取得するためだけにRTCを使用。
- TSC(Time Step Counter)
- 80x86はCLK入力ピンで外部オシレータのクロック信号を受信。Pentium以降は64bitのTSCレジスタで取得可能。
- 動作クロックによりTSCの加算周期が変わるが、同じカーネルイメージを使用可能。
- PIT(Programmable Interval Timer)
- カーネルが設定した特定の周期でタイマ割り込みを発生し続ける。
- 割り込みの周期をtickと呼ぶ。
- tickを短くするほどタイマの精度は上がるが、カーネルモードで動作する時間が長くなるというトレードオフがある。
- タイマ割り込みマクロ
- HZ:タイマ割り込み周波数(IBM PC互換機では1,000)
- CLOCK_TICK_RATE:8254チップのオシレータ周波数(1,193,182)
- LATCH:CLOCK_TICK_RATEとHZの比で、PITの設定に使用。
- CPUローカルタイマ(CPU local timer)
- ローカルAPICで実装され、PITと同様に1回もしくは定期的な割り込みを発生するが違いもある。
- PITのタイマカウンタは16bitであるが、APICのタイマカウンタは32bit。そのため、CPUローカルタイマはとても低い頻度で割り込みを発生させるように設定が可能。
- PITはグローバルな割り込みを発生させるが、CPUローカルタイマは対象プロセッサのみに割り込みを送る。
- CPUローカルタイマはバスクロック信号を基に設定するが、PITは独自にクロック信号を持っているためより柔軟に設定が可能。
- HPET(High Precision Event Timer)
- 最大8個の32bitまたは64bitカウンタを持つ。
- クロック信号は10MHz以上で、カウンタは少なくとも100ナノ秒ごとに増加する。
- 比較器がカウンタ値とマッチレジスタ値を比較し、ハードウェア割り込みを発生させる。
- (一般にはまだ普及していないが)PITを置き換えるために設計されている。
- ACPI PMT(ACPI Power Management Timer)
- 周波数は約3.58MHz
- バッテリ節約の目的でCPUの動作クロックを変更する場合は、TSCよりもACPI PMTが便利だが、HPETが利用できる場合は高機能なHPETの方を優先すべき。
- 時間管理の基本的な使い分け(ローカルAPICタイマを持っていないマルチプロセッサシステムなどもある)
- シングルプロセッサシステムでは、PITまたはHPETのグローバルタイマのどちらかの割り込みをきっかけに時間管理の処理を起動する。
- マルチプロセッサシステムでは、グローバルタイマの割り込みをきっかけに全体的な処理を行い、ローカルAPICタイマ割り込みをきっかけにCPU每の処を起動する。
- timer_optsデータ構造体
- mark_offsetメソッド:タイマ割り込みが発生した正確な時刻を適切なデータ構造体に記録する。
- get_offsetメソッド:最後のタイマ割り込みからの経過時間(マイクロ秒)を計算する。
- mark_offsetとget_offsetによりtickよりも正確な現在時刻を求める。(時刻補間 time interpolation)
高精度順のタイマオブジェクト
- timer_hpet:HPET
- timer_tsc:ACPI PMT
- timer_pit:PIT
- timer_nome:汎用のダミータイマ発生源
6.2.1.2 jiffies変数
- システムが起動してからのtick数をカウント
- 80x86系32bitでは約50日で循環するが、マクロによって正しい値が取得できるようになっている。
- 32ビットアーキテクチャでは64ビットの値をアトミックに扱えないため、tickが1ミリ秒であれば数億年循環しないjiffies_64の下位32bitを参照している。
6.2.1.3 xtime変数
- xtime変数
- tv_sec:1970/01/01 00:00:00(UTC)からの経過秒数を保持
- tv_nsec:現在秒からのナノ秒単位での経過時間を保持
- tick每に更新。精度はtickによる?
- シングルプロセッサシステムでは、IRQ0のPIT割り込みをきっかけに実行。
6.2.2.1 時間管理の仕組みの初期化
- xtime変数の初期化や使用可能なクロック回路・タイマ回路を判定して設定。(詳細は略)
6.2.2.2 タイマ割り込みハンドラ
- jiffies_64の増加などを行う。(統計情報の算出などは後の章で説明。その他の詳細は略。)
- PITまたはHPHEとローカルCPUタイマを利用する。
6.2.3.1 時間管理の仕組みの初期化
- APIC初期化など。
6.2.3.2 グローバルタイマ割り込みハンドラ
- シングルプロセッサ用といくつか違いがある。
6.2.3.3 ローカルタイマ割り込みハンドラ
- カーネルコードのプロファイル処理とそのCPU上で実行しているカレントプロセスの実行時間確認などの特定のCPUに関連する時間管理処理を実行。
- update_times()関数でxtime変数を更新。
- wall_jiffies変数にxtimeを最後に更新した時刻を格納しておくことで、tick毎にxtime変数を更新しなくてもいいようになっている。最終的にはxtimeは正確なシステム時刻になる。
- ユーザモードであればaccount_userr_time()関数を呼び出し、カーネルモードであればaccount_system_time()を呼び出す。
- カレントディスクリプタのutime/stimeメンバを更新。
- CPU時間の合計が制限値に達していれば、SIGXCPUまたはSIGKILLシグナルを送る。
- プロセスのタイマを確認する。
- kstat上のカーネル統計情報を更新する。
- ローカルCPUにTIMER_SOFTIRQの起動を要求する。
- RCUで保護されている古くなったデータを回収する必要があれば、rcu_taskletの起動を要求する。
- カレントプロセスがクォンタムを使い切ったかどうか確認する。
- ロードアベレージを算出。TASK_RUNNINGかTASK_UNINTERRUPTIBLEのプロセス数をカウントする。
- 0:実行中のプロセスは存在しない。
- 1:1つのプロセスがCPUを使用している。
- 1以上:複数の実行状態のプロセスがCPUを共有している。
- readprofileと呼ばれるコードプロファイラでカーネルのホットスポットを監視。
- モンテカルロアルゴリズムで実装。カーネルモードで実行中にタイマ割り込みがあったら、eipの値で実行中の処理を識別。
- 有効化するにはブートパラメータを設定する。
- タイマがタイムアウトはjiffiesを比較することにより行う。
- タイマ関数はタイムアウトしてから最大数百ミリ秒の遅延で実行されるため、リアルタイムアプリケーションには向いていない。
- 動的タイマ:カーネルが使用するタイマ。
- インターバルタイマ:ユーザモードで使用するタイマ。
- 遅延関数:指定された時間のあいだ、小さい命令の繰り返しを行う。
- 削除可能な資源を処理する動的タイマなどは、タイマを止めてから資源の開放を行う。ただし、マルチプロセッサシステムでは、del_timer_sync()関数によって別のCPUでタイマ関数が実行されていないかを確認する。
- 稼動状態のタイマのタイマ期限を変更する際などにもスピンロックで競合状態を避けるといった必要がある。
- expireの値によりtick単位にいくつかのブロックに分けてタイマを管理している。0-255, 2^14-1, 2^20-1, 2^16-1, 2^32-1以内にタイムアウトする動的タイマの配列を管理。
- カレントプロセスをTASK_INTERRUPTIBLEに変更。
- タイムアウトのtickを設定して他のプロセスを実行。
- 起床したらタイマを削除。
- I/O待ちなどのtick単位よりも短いタイムアウトを使用したい場合、udelay()関数またはndelay()関数を使用する。
- udelay()はloopの数をマイクロ秒で指定し、ndelay()はナノ秒で指定する。
- time():1970/01/01 00:00:00(UTC)からの経過秒数を返す。(古いシステムコール)
- gettimeofday():1970/01/01 00:00:00(UTC)からの経過秒数とマイクロ秒を返す。
- ftime():1970/01/01 00:00:00(UTC)からの経過秒数を返す。(古いシステムコールで、ライブラリとして実装)
- do_gettimeofday()は、xtime変数の値と使用可能なタイマ回路によって現在時刻を算出する。
- settimeofday(), stime()システムコールで現在日時を設定できるが、RTCレジスタは変更されない。
- システム時刻はクロックドリフトによりずれていくが、急激な時刻の修正は障害を発生させる。
- adjtimex()システムコールでtickごとに微修正を行うことができ、NTPなどが利用している。
- setitimer(), alarm()システムコールはユーザモードプロセスから利用可能なインターバルタイマ。
- シグナルを送る周期(1回だけの場合は0)と次のシグナルを送るまでの残り時間を設定。
- setitimer()の経過時間算出方式
- ITIMER_REAL:実経過時間。CPUでプロセスを実行していないときにもシグナルを送る必要があるため、動的タイマを利用して実装されている。
- ITIMER_VIRTUAL:ユーザモードで動作した時間。タイマ割り込みハンドラで実行。
- ITIMER_PROF:ユーザモードおよびカーネルモードで動作した時間。
- alarm()システムコールはプロセスディスクリプタの動的タイマを利用し、経過時間でシグナルを送る。
- POSIX 1003.1bで導入されたタイマをPOSIXタイマと呼ぶ。
- ITIMER_REALとの相違点。
- POSIXタイマではSIGALARMだけではなく任意のシグナルを送ることができる。
- マルチスレッドアプリケーション全体に対しても、シングルスレッドに対してもシグナルを送ることができる。
- アプリケーションのスレッドの通知関数を強制的に実行することもできるし、何もしないこともできる。
- Linuxが提供するPOSIXタイマ
- CLOCK_REALTIME:xtime変数を基にしたリアルタイムクロックであり、tickが1000Hzで動作していれば精度は999,848ナノ秒となる。
- CLOCK_MONOTONIC:xtime変数から外部の時刻源との同期による時刻補正分を取り除いたリアルタイムクロック。精度はCLOCK_REALTIMEと同じ。
最新コメント