このページの目次

クロックとタイマー

カバー範囲: 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, ...

struct timer_list {
    unsigned long       expires;      // 期限切れ jiffies
    void                (*function)(struct timer_list *);
    u32                 flags;
};

// 登録:
mod_timer(&timer, jiffies + msecs_to_jiffies(500)); // 500ms 後にトリガー

// 削除:
del_timer(&timer);         // 同期削除
del_timer_sync(&timer);    // 実行中のハンドラが完了するのを待つ

// タイマーは softirq コンテキスト (TIMER_SOFTIRQ) で実行される
// → スリープ不可、mutex の取得不可

hrtimer: 高精度タイマー

// kernel/time/hrtimer.c
// ナノ秒単位の精度、赤黒木によるソート
// ハードウェアのサポートが必要 (HPET, TSC, または APIC タイマー)

struct hrtimer {
    ktime_t             expires;        // 絶対期限切れ時間 (ktime_t, ns)
    enum hrtimer_restart (*function)(struct hrtimer *);
};

// 使用例:
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = my_callback;
hrtimer_start(&timer, ns_to_ktime(1000000), HRTIMER_MODE_REL);
// → 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 (プロセス単位):
timer_create(CLOCK_MONOTONIC, &evp, &timerid);
timer_settime(timerid, 0, &its, NULL);
// → カーネルが hrtimer を作成 → 期限切れ時にシグナル送信 (SIGALRM, SIGEV_SIGNAL)

// POSIX interval timer (itimer):
setitimer(ITIMER_REAL, &value, NULL);  // SIGALRM
setitimer(ITIMER_VIRTUAL, &value, NULL);  // SIGVTALRM (ユーザーランド時間のみ)
setitimer(ITIMER_PROF, &value, NULL);  // SIGPROF (ユーザー+カーネル時間)

// timerfd (2.6.25以降):
int fd = timerfd_create(CLOCK_MONOTONIC, 0);
timerfd_settime(fd, 0, &its, NULL);
// → fd が読み取り可能 → タイマー期限切れ (poll/epoll 可能、非常に便利)

デバッグ

# 現在の tick モード
cat /sys/devices/system/cpu/cpu0/cpuidle/state*/disable

# timer wheel の統計 (/proc/timer_list)
cat /proc/timer_list | head -100

# hrtimer の統計
cat /proc/timer_list | grep -A5 hrtimer

# HZ の値
getconf CLK_TCK          # ユーザーランドの HZ
grep CONFIG_HZ /boot/config-$(uname -r)  # カーネルビルド時の HZ

参照と補足

  • カーネルドキュメント⁠: Documentation/timers/
  • LWN: "The timer wheel", "hrtimers and the tick", "NOHZ full"
  • ソースコード⁠:
    • kernel/time/timer.c — timer wheel
    • kernel/time/hrtimer.c — hrtimer
    • kernel/time/tick-common.c — tick 管理
    • kernel/time/tick-sched.c — dyntick/nohz
    • kernel/time/clocksource.c — clocksource
    • kernel/time/clockevents.c — clockevent
    • kernel/time/posix-timers.c — POSIX timer

キーワード: timer wheel, hrtimer, jiffies, HZ, clockevent, clocksource, dyntick, nohz, POSIX timer, timerfd