このページの目次
クロックとタイマー
カバー範囲: timer wheel → hrtimer (赤黒木) → clockevent/clocksource → tick (周期性/dyntick/nohz) → POSIX timer → itimer カーネルバージョン: 2.6 ~ 6.x
概要
カーネルには、2つのタイマーシステムが共存しています。
- timer wheel (低精度): jiffy グランularity (1/HZ 秒、通常 1ms/4ms)、
mod_timer()/del_timer() - hrtimer (高精度): ナノ秒単位、赤黒木によるソート、
hrtimer_start()/hrtimer_cancel()
この二重構造は歴史的経緯によるものです。timer wheel は初期の実装であり、hrtimer は 2.6.16 で導入された高精度な代替手段です。現在、両者は共存しており、timer wheel はネットワークタイムアウトなどの低精度かつ大量のタイマーを処理し、hrtimer は POSIX timer や tick モックなどの高精度イベントを処理します。
Jiffies と HZ
// include/linux/jiffies.h
extern unsigned long volatile jiffies; // 起動からの tick 数
// HZ = 1秒あたりのtick数 (カーネルビルド時に設定):
// CONFIG_HZ=100 → 10ms の精度 (サーバー、CPUオーバーヘッド低)
// CONFIG_HZ=250 → 4ms の精度 (デフォルト)
// CONFIG_HZ=1000 → 1ms の精度 (デスクトップ/リアルタイム、より滑らかだが割込みが多い)
// jiffies のラップ:
// 32-bit: 2^32 / HZ ≈ 497日 (HZ=100 の場合)
// 64-bit: ラップは宇宙の寿命を超える
// time_after(a, b) / time_before(a, b) マクロがラップ比較を処理する
Timer Wheel: 低精度タイマー
// kernel/time/timer.c
// 期限切れ時間に基づいてバケットに分類 (水時計に類似)
// バケットサイズ: 1 jiffy, 8 jiffies, 64 jiffies, 512 jiffies, ...
;
// 登録:
; // 500ms 後にトリガー
// 削除:
; // 同期削除
; // 実行中のハンドラが完了するのを待つ
// タイマーは softirq コンテキスト (TIMER_SOFTIRQ) で実行される
// → スリープ不可、mutex の取得不可
hrtimer: 高精度タイマー
// kernel/time/hrtimer.c
// ナノ秒単位の精度、赤黒木によるソート
// ハードウェアのサポートが必要 (HPET, TSC, または APIC タイマー)
;
// 使用例:
;
timer.function = my_callback;
;
// → 1ms 後にコールバック
// hrtimer の期限切れ → 割込みコンテキストでコールバック (HRTIMER_SOFTIRQ)
// スリープが必要な場合 → schedule_hrtimeout() を使用
Clock Event と Clock Source
// kernel/time/clockevents.c + kernel/time/clocksource.c
// clocksource: 現在時刻を提供 (TSC, HPET, ACPI PM timer を抽象化)
// read() → cycle_t (monotonic counter) を返す
// → mult/shift を介してナノ秒に変換
// clockevent: 未来のイベントプログラミングを提供 (Local APIC timer, HPET を抽象化)
// set_next_event(delta_ns) → delta_ns 後にハードウェアで割込みを発生させるようプログラミング
// → これが tick および hrtimer のハードウェア基盤
// tick デバイス:
// 各 CPU には、tick デバイスとして clockevent が1つ存在する
// per-CPU (Local APIC timer) または グローバルブロードキャスト (HPET) となり得る
Tick 管理: periodic / dyntick / nohz
// 3つの tick モード:
// 1. Periodic tick (旧式):
// 各 CPU で 1/HZ 秒ごとに timer interrupt を発生させる
// → 時刻の更新 (jiffies)、スケジューラの tick、プロセス統計に使用
// → ただし、多くの tick は無駄である (CPU idle 時には tick が不要)
// 2. Dynamic tick (dyntick / CONFIG_NO_HZ_IDLE, 2.6.21以降):
// CPU が idle の場合: tick を停止 → CPU を深いスリープ状態 (C-state) に移行
// → 次のタイマー期限切れ時間に基づいて clockevent を1回限りのウェイクアップ用にプログラミング
// → 省電力: ワットあたりの処理量が増加
// 3. Full nohz (CONFIG_NO_HZ_FULL, 3.10以降):
// CPU に実行可能なタスクが1つのみ存在する場合: tick を停止
// → tick 割込みがレイテンシに敏感なタスク (HPC/リアルタイム) に与える干渉を軽減
// → ただし、RCU およびスケジューラの統計には適応が必要 → より複雑
POSIX Timer と itimer
// kernel/time/posix-timers.c
// ユーザーランドのタイマー API:
// POSIX timer (プロセス単位):
;
;
// → カーネルが hrtimer を作成 → 期限切れ時にシグナル送信 (SIGALRM, SIGEV_SIGNAL)
// POSIX interval timer (itimer):
; // SIGALRM
; // SIGVTALRM (ユーザーランド時間のみ)
; // SIGPROF (ユーザー+カーネル時間)
// timerfd (2.6.25以降):
int fd = ;
;
// → fd が読み取り可能 → タイマー期限切れ (poll/epoll 可能、非常に便利)
デバッグ
# 現在の tick モード
# timer wheel の統計 (/proc/timer_list)
|
# hrtimer の統計
|
# HZ の値
参照と補足
- カーネルドキュメント:
Documentation/timers/ - LWN: "The timer wheel", "hrtimers and the tick", "NOHZ full"
- ソースコード:
kernel/time/timer.c— timer wheelkernel/time/hrtimer.c— hrtimerkernel/time/tick-common.c— tick 管理kernel/time/tick-sched.c— dyntick/nohzkernel/time/clocksource.c— clocksourcekernel/time/clockevents.c— clockeventkernel/time/posix-timers.c— POSIX timer
キーワード: timer wheel, hrtimer, jiffies, HZ, clockevent, clocksource, dyntick, nohz, POSIX timer, timerfd