2. 实时内核基础
Linux 内核的实时能力取决于其抢占模型。抢占模型决定了内核在何种时机、何种开销下能够打断当前执行的任务,转而执行更高优先级的任务。理解不同抢占模型的差异,是进行实时性能调优的基石。
从主线内核到 PREEMPT_RT,抢占模型经历了四个主要阶段:PREEMPT_NONE、PREEMPT_VOLUNTARY、PREEMPT 和 PREEMPT_RT。它们的核心区别在于内核态代码的抢占点密度和临界区长度。
核心概念:抢占延迟 = 中断关闭时间 + 内核临界区长度。抢占模型越激进,临界区越短,系统响应越快,但吞吐量可能下降。
2.1 抢占模型演进与配置
在 Linux 内核编译配置中,通过 Kernel Features 菜单选择抢占模型。下表总结了四种模型的关键特征:
| 模型名称 | 配置选项 | 抢占点密度 | 适用场景 | 最坏情况延迟 |
|---|---|---|---|---|
| PREEMPT_NONE | CONFIG_PREEMPT_NONE |
极低(仅在系统调用返回时) | 服务器、批处理、科学计算 | 高(可达数十毫秒) |
| PREEMPT_VOLUNTARY | CONFIG_PREEMPT_VOLUNTARY |
低(在显式调度点处) | 桌面、轻度交互系统 | 中等(毫秒级) |
| PREEMPT | CONFIG_PREEMPT |
高(在大多数内核路径中) | 嵌入式、软实时、多媒体 | 较低(亚毫秒级) |
| PREEMPT_RT | CONFIG_PREEMPT_RT |
极高(几乎全部内核路径,含中断) | 工业控制、航空航天、硬实时 | 极低(微秒级) |
配置检查命令:在运行中的系统上,可以通过
zcat /proc/config.gz | grep PREEMPT 或检查 /boot/config-$(uname -r) 文件来确认当前内核使用的抢占模型。
2.2 模型一:PREEMPT_NONE(无抢占)
这是最原始的 Linux 内核模型,也称为 服务器内核。内核在执行系统调用时,除非显式调用 schedule() 或返回用户空间,否则不会被抢占。这意味着一个低优先级的系统调用可以长时间阻塞高优先级任务。
- 优点:吞吐量最大化,上下文切换开销最小。
- 缺点:调度延迟不可预测,最坏情况延迟可能达到几十毫秒。
- 典型场景:数据库服务器、Web 服务器、批处理作业。
2.3 模型二:PREEMPT_VOLUNTARY(自愿抢占)
此模型在 PREEMPT_NONE 的基础上,在内核代码中显式插入了一些 抢占点(如 cond_resched())。当内核执行到这些点时,会检查是否有更高优先级的任务需要运行。这降低了最坏情况延迟,但并未覆盖所有内核路径。
- 优点:相比 NONE 模型,交互响应有所改善。
- 缺点:抢占点不全面,长路径仍可能阻塞。
- 典型场景:桌面 Linux、通用嵌入式系统。
2.4 模型三:PREEMPT(低延迟桌面/嵌入式)
此模型允许在大多数内核代码路径中发生抢占,只要内核没有持有自旋锁。它通过增加 preempt_count 计数来管理,当计数为 0 时允许抢占。这是许多通用发行版(如 Ubuntu、Fedora)的默认选项。
- 优点:调度延迟显著降低,适合多媒体和软实时应用。
- 缺点:自旋锁保护的临界区仍不可抢占,中断上下文不可抢占。
- 典型场景:音频处理、视频播放、机器人控制。
2.5 模型四:PREEMPT_RT(完全实时抢占)
PREEMPT_RT 是实时 Linux 的基石。它通过以下关键机制实现了几乎完全的可抢占性:
- 自旋锁替换:将大部分自旋锁替换为
rt_mutex支持的 可睡眠锁(sleeping spinlocks)。 - 中断线程化:将中断处理程序(尤其是下半部)作为内核线程运行,允许被高优先级任务抢占。
- 高精度定时器:使用
hrtimer提供纳秒级定时精度。 - 优先级继承:实现 PI(Priority Inheritance)协议,防止优先级反转。
性能权衡:PREEMPT_RT 将最坏情况延迟降低到微秒级,但代价是吞吐量下降约 5%-15%,上下文切换开销增加。对于非实时负载,不建议启用。
2.6 抢占模型对比总结
选择哪种抢占模型,取决于应用对 延迟确定性 和 吞吐量 的权衡。下表从多个维度进行了量化对比:
| 对比维度 | PREEMPT_NONE | PREEMPT_VOLUNTARY | PREEMPT | PREEMPT_RT |
|---|---|---|---|---|
| 最坏情况中断延迟 | 10-100 ms | 1-10 ms | 100-500 µs | 5-50 µs |
| 调度延迟抖动 | 高 | 中 | 低 | 极低 |
| 上下文切换开销 | 最低 | 低 | 中 | 较高 |
| 吞吐量影响 | 基准 | 下降约 1-3% | 下降约 3-8% | 下降约 5-15% |
| 中断线程化 | 否 | 否 | 否 | 是 |
| 可睡眠锁 | 否 | 否 | 否 | 是 |
| 优先级继承 | 仅限 futex | 仅限 futex | 仅限 futex | 全局支持 |
调优建议:对于实时测量工具链的开发,目标系统必须运行在 PREEMPT_RT 内核上。如果硬件不支持,至少应启用 PREEMPT 模型,并关闭所有动态电源管理功能(如 CPU 空闲状态、动态调频),以减少延迟不确定性。