このページの目次

時間管理

カバー範囲: timekeeping → CLOCK_MONOTONIC/CLOCK_REALTIME/CLOCK_BOOTTIME → NTP → PTP → vsyscall/vDSO → TSC/HPET/ACPI などのハードウェアクロック カーネルバージョン: 2.6 ~ 6.x

概要

カーネルの時間管理は、以下の3つの問いに答えます。「今何時か?」「どれだけの時間が経過したか?」「いつウェイクアップするか?」。一見単純に見えますが、複数のクロックソースの選択と仲裁、NTP による時刻合わせ、およびユーザー空間での高速な時間アクセスが含まれます。

重要な概念は、REALTIME(壁掛け時計の時刻、NTP によって調整可能、うるう秒の影響を受ける)と MONOTONIC(起動からの信頼性の高い測定、単調増加)を区別することです。


クロックの種類

// include/uapi/linux/time.h

// CLOCK_REALTIME: 壁掛け時計の時刻 (Unix エポック)
//   NTP によって調整され、過去に戻ることがある (うるう秒、settimeofday)
//   → delta 測定向けではない

// CLOCK_MONOTONIC: 起動からの時刻
//   単調増加し、NTP による調整を受けず、過去に戻らない
//   → 時間間隔の測定に適している

// CLOCK_MONOTONIC_RAW: 生ハードウェアカウント
//   NTP による周波数調整の影響を受けない (MONOTONIC よりも歪められにくい)
//   → 精密なベンチマークに適している

// CLOCK_BOOTTIME: サスペンド時間を含む
//   MONOTONIC と似ているが、システムのサスペンド時間を含む
//   → 「壁掛け時計としての実際の経過時間」が必要なシナリオに適している

// CLOCK_TAI: 国際原子時
//   UTC と 37 秒のオフセットがある (2024年時点)
//   うるう秒の影響を受けない

timekeeping コア

// kernel/time/timekeeping.c
// 主要なデータ構造:
struct timekeeper {
    struct clocksource          *clock;  // 現在選択されている clocksource
    u64                         cycle_interval;  // NTP tick に対応するサイクル数
    u64                         xtime_sec;       // REALTIME の秒数
    unsigned long               xtime_nsec;      // REALTIME のナノ秒部分
    ktime_t                     offs_real;       // REALTIME のオフセット (NTP 調整)
    ktime_t                     offs_boot;       // BOOTTIME のオフセット
    ktime_t                     offs_tai;        // TAI のオフセット
    struct timespec64           wall_to_monotonic; // REALTIME → MONOTONIC への変換
    struct timespec64           total_sleep_time;  // 累積サスペンド時間
};

// timekeeping_advance():
//   各 tick (または hrtimer 割り込み) ごとに1回呼び出される
//   1. clocksource を読み取る
//   2. delta cycles → delta_ns を計算する
//   3. delta_ns を xtime_nsec に累積する (繰り上げを処理)
//   4. NTP 周波数補正を適用する (mult 調整)
//   5. すべての派生時間 (MONOTONIC, BOOTTIME, TAI) を更新する

NTP による時刻合わせ

// kernel/time/ntp.c
// カーネル NTP デーモン:
//   ユーザー空間の ntpd/chronyd ではない — これらは制御側である
//   カーネルの NTP コードが実際の周波数および位相の調整を実行する

// adjtimex() システムコール:
//   ユーザー空間の ntpd は adjtimex を通じてカーネルに以下を指示する:
//     1. 現在のオフセット (位相誤差、ナノ秒単位)
//     2. 現在の周波数 (周波数誤差、PPM)
//     3. 最大誤差
//   カーネル: timekeeper->mult (周波数) と offset (位相) を調整する

// PTP (Precision Time Protocol):
//   Linux は SO_TIMESTAMPING を介してハードウェアタイムスタンプをサポートする
//   PHC (PTP Hardware Clock) ドライバー → /dev/ptp*
//   → ナノ秒単位の時間同期 (データセンター/金融取引向け)

vDSO: 高速な時間アクセス

// arch/x86/entry/vdso/
// 問題: clock_gettime() が syscall を使用する場合 → 1回あたり約100ns (syscall + コンテキストスイッチ)
//       高頻度呼び出し (プロファイリングなど) ではオーバーヘッドが大きすぎる

// vDSO (virtual Dynamic Shared Object):
//   カーネルは各プロセスのアドレス空間に少量のコードを注入する
//   → clock_gettime() がユーザー空間で実行される → カーネルを経由しない!
//   → clocksource を読み取り、timekeeper のオフセットと mult を適用して時間を返す
//   → レイテンシ: 約20ns (syscall の場合の約100nsに対して)

// vsyscall (旧方式、廃止済み) と vDSO (新方式):
//   vsyscall: 固定アドレス、セキュリティリスク (ROP 攻撃が容易)
//   vDSO:    ASLR によるランダムアドレス、標準的な ELF .so

x86 vDSO 実装

// arch/x86/entry/vdso/vclock_gettime.c
// ユーザー空間での clock_gettime(CLOCK_MONOTONIC):
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) {
    // 1. TSC を読み取る (RDTSC 命令、約10サイクル)
    cycles = __arch_counter_get_cntvct();

    // 2. clocksource 変換を適用する (vvar ページ内)
    ns = (cycles - vd->cycle_last) * vd->mult + vd->xtime_nsec;

    // 3. seqlock の整合性を処理する
    //    vd->seq は 偶→奇→偶 のシーケンス番号
    //    読み取り前に seq を記録し、読み取り後に seq が変わっていないことを検証 → データ整合性
}

ハードウェアクロックソース

クロックソース精度レイテンシ安定性シナリオ
TSC (rdtsc)約0.3ns約10サイクル高い (constant/invariant TSC)デフォルトの優先候補
HPET約100ns約500サイクル高い旧式システムまたは TSC が不安定な場合
ACPI PM Timer約280ns約1μs中程度上記と同様
ARM Generic Timer約10ns約10サイクル高いARM64 のデフォルト
KVM pvclock約20ns約200サイクルホストに依存仮想化環境
# 現在使用されている clocksource を表示
cat /sys/devices/system/clocksource/clocksource0/current_clocksource

# 利用可能なリストを表示
cat /sys/devices/system/clocksource/clocksource0/available_clocksource

参照と拡張

  • カーネルドキュメント⁠: Documentation/timers/timekeeping.rst
  • LWN: "The vDSO and time", "Timekeeping in the Linux kernel"
  • ソースコード⁠:
    • kernel/time/timekeeping.c — timekeeping コア
    • kernel/time/ntp.c — NTP
    • arch/x86/entry/vdso/ — x86 vDSO
    • arch/arm64/kernel/vdso/ — ARM64 vDSO
    • kernel/time/clocksource.c — clocksource 管理

キーワード: CLOCK_MONOTONIC, CLOCK_REALTIME, timekeeper, NTP, PTP, vDSO, TSC, HPET, clocksource