3. 实时Linux基础与PREEMPT_RT

在工业控制场景中,“实时”并不等于“快”,而是指系统能够在确定的时间上限内对外部事件作出响应。一个 1 GHz 的处理器如果因为内核临界区不可抢占而延迟 3 ms 才响应编码器中断,它依然不满足 250 μs 周期的运动控制需求;相反,一个 400 MHz 的 Sitara 处理器只要最坏响应时间稳定在 80 μs 以内,就可以胜任大量伺服与 IO 任务。因此,理解实时 Linux,首先要建立正确的指标体系,再理解内核为什么会产生延迟,最后才谈 PREEMPT_RT 如何消除这些延迟。

一、实时性指标:用数字描述“确定性”

评价一个实时系统,通常关注以下四类指标:

  • 中断延迟(Interrupt Latency):从硬件中断信号到达 CPU 引脚,到中断服务程序(ISR)第一条指令执行的时间。它主要受中断关闭(关中断)区间长度影响。
  • 调度延迟(Scheduling Latency):从中断唤醒一个高优先级实时线程,到该线程真正获得 CPU 开始执行的时间。它受内核不可抢占区间、调度器路径长度影响。
  • 最坏情况响应时间(WCRT):从事件发生到实时任务完成关键动作的总时间,是中断延迟、调度延迟、任务自身执行时间的叠加,也是工业验收真正关心的指标。
  • 抖动(Jitter):多次响应时间的最大值与最小值之差。周期控制中,抖动往往比平均延迟更致命,因为它直接造成采样时刻漂移。

举例说明:某 Sitara AM335x 平台运行 1 kHz 控制周期,若实测响应时间分布为最小值 42 μs、最大值 96 μs,则平均延迟约 60 μs,抖动约 54 μs。若控制算法允许的采样偏差为 ±20 μs,则该抖动已超标,需要进一步优化内核配置或调整任务优先级。这里的数据属于教学示例,用于说明指标之间的关系,并非实测结论。

二、内核抢占模型:延迟从哪里来

标准 Linux 内核为追求吞吐量,在大量位置禁止抢占:自旋锁临界区、中断处理上半部、软中断、RCU 读侧临界区等。当高优先级实时任务被唤醒时,如果 CPU 正处于这些不可抢占区间,它只能等待,这段时间就是调度延迟的主要来源。Linux 内核因此提供了几种抢占模型:

  • PREEMPT_NONE:服务器型配置,几乎不允许内核态抢占,吞吐最高,延迟最大。
  • PREEMPT_VOLUNTARY:在显式抢占点允许调度,延迟有所改善,但仍不满足硬实时。
  • PREEMPT:允许内核态被抢占,但自旋锁临界区、中断上下文仍不可抢占。
  • PREEMPT_RT:将绝大多数不可抢占区间转化为可抢占,目标是把最坏延迟压到几十微秒量级。

理解这一点非常关键:PREEMPT_RT 并不是让 CPU 变快,而是通过减少“不可抢占窗口”的长度,把延迟的尾部削平,从而提升确定性。

PREEMPT_RT 抢占模型与延迟来源对比 标准 Linux 内核(PREEMPT) 用户任务 自旋锁临界区 不可抢占 硬中断上半部 不可抢占 实时任务等待 事件到达 延迟累积 不可抢占窗口长 → 调度延迟大 → 抖动大 PREEMPT_RT 内核 用户任务 rt_mutex 可抢占 优先级继承 线程化中断 可被抢占 实时任务立即执行 事件到达 延迟被压缩 不可抢占窗口极短 → 调度延迟小 → 抖动小 关键指标:中断延迟 + 调度延迟 + 任务执行时间 = 最坏响应时间(WCRT);抖动 = 最大响应 − 最小响应

三、PREEMPT_RT 补丁原理:把不可抢占变成可抢占

PREEMPT_RT 的核心思想可以概括为“把内核中所有长延迟的不可抢占路径,改造成可被高优先级任务打断的路径”。主要机制包括:

  1. 自旋锁转为可睡眠的 rt_mutex:普通 spinlock 在持有期间禁止抢占,PREEMPT_RT 将其替换为支持优先级继承的 rt_mutex。当高优先级任务需要同一把锁时,持有锁的低优先级任务会临时继承高优先级,避免优先级反转。
  2. 中断线程化:除少数必须直接处理的“硬中断”外,大部分中断处理程序被转换为内核线程,拥有自己的优先级,可被更高优先级的实时任务抢占。
  3. 软中断与 tasklet 线程化:软中断、tasklet 被移入内核线程上下文执行,不再在中断返回路径上长时间占用 CPU。
  4. RCU 与本地锁优化:将 RCU 读侧临界区、per-CPU 锁等不可抢占区间缩短或改为可抢占。
  5. 高精度定时器与时钟源:配合 hrtimer,使周期任务唤醒时刻更精确,减少定时抖动。

这些机制共同作用后,内核中剩余的不可抢占区间通常只有几微秒量级,实时任务被唤醒后可以迅速获得 CPU。

四、在 Sitara 上的适配要点

Sitara 系列(如 AM335x、AM437x、AM57x)采用 ARM Cortex-A8/A9/A15 内核,适配 PREEMPT_RT 时需要关注以下几点:

  • 内核版本与 RT 补丁匹配:PREEMPT_RT 补丁与主线内核版本严格对应,必须选择 TI SDK 所支持的内核版本,再应用对应版本的 RT 补丁,不能跨版本混用。
  • 配置选项:开启 CONFIG_PREEMPT_RT,同时确认 CONFIG_HIGH_RES_TIMERS、CONFIG_NO_HZ_FULL(按需)、CONFIG_PREEMPT_RT_FULL 等选项正确设置。
  • 中断亲和与隔离:将实时任务绑定到独立 CPU 核,把非实时中断迁移到其他核,减少对实时核的干扰。例如在双核 AM335x 上,可将控制任务绑定到 CPU1,网络与文件系统中断绑定到 CPU0。
  • 时钟源与定时器:确认使用高精度定时器,避免使用低精度 jiffies 定时器导致周期抖动。
  • 驱动实时性:检查所用外设驱动是否存在长临界区或忙等待,必要时替换为支持 RT 的驱动版本。
  • 电源管理与频率调节:关闭 CPU 频率动态调节(cpufreq)或将其固定在高性能档,避免频率切换引入额外延迟。
在 Sitara 上验证实时性时,常用 cyclictest 进行长时间压力测试。例如:cyclictest -m -p 80 -n -i 1000 -l 1000000,表示以 80 优先级、1 ms 周期运行 100 万次,观察最大延迟。若最大延迟稳定在 100 μs 以内,通常可满足多数工业控制需求。

五、从指标到验收:一个可参考的检查清单

在实际项目中,可以按以下清单逐项确认实时性是否达标:

检查项目标值(示例)验证方法
中断延迟< 30 μs示波器测量 GPIO 中断到 ISR 翻转
调度延迟< 50 μscyclictest 最大延迟
周期抖动< ±20 μs长时间 cyclictest 统计
最坏响应时间< 100 μs端到端信号测量
CPU 隔离实时核无干扰查看 /proc/interrupts 与 taskset

需要强调的是,表中数值为教学示例,实际目标应根据具体控制周期、工艺精度和硬件平台确定。PREEMPT_RT 提供的是确定性的基础,而最终能否达标,还取决于任务设计、驱动质量、CPU 隔离和系统负载管理。只有在指标、内核模型、补丁机制和平台适配四个层面都理解清楚,才能在 Sitara 上构建真正可靠的实时 Linux 控制系统。