本页目录
时间管理
覆盖: timekeeping → CLOCK_MONOTONIC/CLOCK_REALTIME/CLOCK_BOOTTIME → NTP → PTP → vsyscall/vDSO → TSC/HPET/ACPI 等硬件时钟 内核版本: 2.6 ~ 6.x
概述
内核时间管理回答三个问题:"现在几点?"、"过了多久?"、"什么时候唤醒?"。看似简单,但涉及多个时钟源的选择与仲裁、NTP 校时、以及用户空间的快速时间访问。
关键概念是区分 REALTIME (挂钟时间,可被 NTP 调整,受闰秒影响) 和 MONOTONIC (自启动以来的可靠测量,单调递增)。
时钟类型
// include/uapi/linux/time.h
// CLOCK_REALTIME: 挂钟时间 (Unix epoch)
// 受 NTP 调整, 可以往回跳 (闰秒, settimeofday)
// → 不适合做 delta 测量
// CLOCK_MONOTONIC: 自启动以来的时间
// 单调递增, 不受 NTP 调整, 不会往回跳
// → 适合测量时间间隔
// CLOCK_MONOTONIC_RAW: 原始硬件计数
// 不受 NTP 频率调整 (比 MONOTONIC 更难被扭曲)
// → 适合精确基准测试
// CLOCK_BOOTTIME: 包含 suspend 时间
// 与 MONOTONIC 类似,但包含系统睡眠的时间
// → 适合需要"墙上的真实流逝时间"的场景
// CLOCK_TAI: International Atomic Time
// 与 UTC 偏移 37 秒 (截至 2024)
// 不受闰秒影响
timekeeping 核心
// kernel/time/timekeeping.c
// 核心数据结构:
;
// timekeeping_advance():
// 每个 tick (或 hrtimer interrupt) 调用一次
// 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 daemon:
// 不是用户空间的 ntpd/chronyd — 那是控制者
// 内核 NTP 代码执行实际的频率和相位调整
// adjtimex() 系统调用:
// 用户空间 ntpd 通过 adjtimex 告诉内核:
// 1. 当前 offset (相位误差, 多少纳秒)
// 2. 当前 freq (频率误差, 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 → 每次 ~100ns (syscall + context switch)
// 高频调用 (如 profiling) 开销太大
// vDSO (virtual Dynamic Shared Object):
// 内核把一小段代码注入每个进程的地址空间
// → clock_gettime() 在用户态执行 → 不经过内核!
// → 读 clocksource, 应用 timekeeper 的偏移和 mult → 返回时间
// → 延迟: ~20ns (vs ~100ns for syscall)
// vsyscall (旧方式, 已废弃) vs vDSO (新方式):
// vsyscall: 固定地址, 安全风险 (容易 ROP)
// vDSO: ASLR 随机地址, 标准 ELF .so
x86 vDSO 实现
// arch/x86/entry/vdso/vclock_gettime.c
// clock_gettime(CLOCK_MONOTONIC) 在用户态:
notrace int
硬件时钟源
| 时钟源 | 精度 | 延迟 | 稳定性 | 场景 |
|---|---|---|---|---|
| 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 周期 | 由 host 保证 | 虚拟化 |
# 查看当前使用的 clocksource
# 查看可用列表
参考与延伸
- 内核文档:
Documentation/timers/timekeeping.rst - LWN: "The vDSO and time", "Timekeeping in the Linux kernel"
- 源码:
kernel/time/timekeeping.c— timekeeping 核心kernel/time/ntp.c— NTParch/x86/entry/vdso/— x86 vDSOarch/arm64/kernel/vdso/— ARM64 vDSOkernel/time/clocksource.c— clocksource 管理
关键词: CLOCK_MONOTONIC, CLOCK_REALTIME, timekeeper, NTP, PTP, vDSO, TSC, HPET, clocksource