1. 实时性工程导入

在工业控制、运动控制、电力电子和边缘网关等场景中,TI Sitara 系列处理器(如 AM335x、AM437x、AM57x、AM64x)被广泛用作主控平台。这类平台通常运行 Linux,因为 Linux 具备完善的网络协议栈、文件系统、驱动框架和开发工具链。但 Linux 的设计目标首先是“吞吐量”和“公平性”,而不是“确定性”。当应用要求“每次都在 100 μs 内响应外部中断”时,默认配置的 Linux 往往无法稳定满足,这就是实时性工程要解决的核心矛盾。

一、Sitara 平台上的实时性挑战来自哪里

实时性问题很少是单一原因造成的,它通常是多个层次叠加的结果。在 Sitara 平台上,最典型的挑战可以归纳为以下几类。

第一是中断延迟。Linux 默认会把中断处理分成“上半部”和“下半部”,上半部在关中断状态下执行,下半部(softirq、tasklet、workqueue)可能被推迟。如果驱动中关中断时间过长,或者中断被迁移到 CPU 上繁忙的软中断上下文之后,外部事件从到达引脚到被应用感知的时间就会抖动。Sitara 的 GPIO、eCAP、eQEP、PRU-ICSS 等外设都可能触发中断,其中 PRU 固件产生的中断尤其需要关注。

第二是调度延迟。Linux 的 CFS 调度器追求公平,普通进程可能被内核线程、内存回收、日志刷写等任务抢占。即使使用 SCHED_FIFO,如果优先级设置不当,或者存在优先级反转,高优先级任务仍可能被阻塞。Sitara 多为单核或双核 Cortex-A 加 Cortex-M/PRU 的异构结构,任务在哪个核上运行、是否发生核间迁移,都会影响延迟。

第三是内存与缓存带来的不确定性。DDR 访问、Cache 未命中、TLB Miss、DMA 与 CPU 争抢总线,都会让同一段代码的执行时间产生数倍差异。Sitara 的 EMIF、L3/L4 互连和 PRU 共享内存访问尤其需要规划。

第四是电源管理与频率调整。cpufreq、cpuidle 在节能的同时会引入唤醒延迟。如果系统在低功耗状态被中断唤醒,从 idle 退出的时间可能达到数百微秒,这对硬实时是不可接受的。

第五是用户空间与内核空间的交互开销。系统调用、页错误、信号处理、读写文件都会带来不可预测的延迟。实时任务如果频繁进入内核,抖动会明显增大。

Sitara Linux 实时性延迟来源与优化路径 外部事件源 GPIO 中断 eCAP / eQEP PRU-ICSS 事件 网络报文 定时器到期 DMA 完成 延迟产生链(从事件到任务响应) ① 硬件中断延迟 关中断时间 / 中断控制器 ② 软中断/下半部 softirq / tasklet / workqueue ③ 调度延迟 CFS 抢占 / 优先级反转 ④ 内存与缓存 DDR 争抢 / Cache Miss ⑤ 电源管理 cpuidle 唤醒 / cpufreq ⑥ 用户/内核交互 系统调用 / 页错误 端到端响应时间 = 各段延迟之和 + 抖动 实时性关注的是最坏情况(WCET),不是平均值 优化手段 PREEMPT_RT 补丁 中断线程化 CPU 隔离与绑核 内存锁定 mlockall 关闭节能与调频 PRU 卸载硬实时

二、Linux 实时性指标到底怎么定义

讨论实时性时,必须先把指标说清楚,否则“优化”没有方向。工程上最常用的指标有以下几个。

中断延迟(Interrupt Latency):从硬件中断信号到达 CPU 引脚,到中断服务程序第一条指令开始执行的时间。它主要受关中断临界区长度影响。在 Sitara 上,可以用 GPIO 翻转加示波器测量,也可以用 cyclictest 配合内核 trace 观察。

调度延迟(Scheduling Latency):从高优先级任务被唤醒,到它真正获得 CPU 开始执行的时间。它反映调度器和中断关闭的综合影响。

最坏情况执行时间(WCET):任务在 worst-case 输入和系统状态下执行一次所需的最长时间。实时性判断依据是 WCET 是否小于截止时间,而不是平均执行时间。

抖动(Jitter):多次响应时间的最大值与最小值之差。对于周期性控制任务,抖动往往比绝对延迟更关键,因为抖动会直接恶化控制环路的相位裕度。

截止时间错过率(Deadline Miss Rate):在长时间运行中,响应时间超过截止时间的次数占比。硬实时要求该值为 0,软实时允许极低比例。

这些指标之间不是孤立的。例如,关闭 cpuidle 可以降低唤醒延迟,但会增加功耗;把任务绑到隔离核可以降低调度延迟,但会牺牲 CPU 利用率。工程上要做的是在给定硬件和功耗约束下,让最坏情况满足截止时间。

三、课程实战目标

本课程不是泛泛介绍实时 Linux 概念,而是围绕 Sitara 平台完成一条可复现的优化链路。完成课程后,你应该能够:

  • 在 AM335x 或 AM64x 开发板上构建带 PREEMPT_RT 的 Linux 内核,并正确配置内核选项;
  • 使用 cyclictest、ftrace、perf、trace-cmd 等工具定位延迟热点,而不是凭感觉调参;
  • 完成中断线程化、CPU 隔离、优先级分配、内存锁定、电源管理关闭等关键配置;
  • 编写一个周期为 1 ms、截止时间为 200 μs 的示例实时任务,并测量其抖动;
  • 判断优化是否达标,并给出可复现的测试记录。

下面给出一份贯穿课程的实战目标参数表,后续章节会围绕这些参数逐步展开。表中数值属于教学示例设定,不是某块具体板卡的实测结果。

项目 示例目标值 说明
控制周期 1 ms 周期性实时任务触发间隔
截止时间 200 μs 从周期点到任务完成计算
最大抖动 ≤ 50 μs 连续运行 1 小时统计
截止时间错过率 0 硬实时要求
测试时长 ≥ 3600 s 覆盖温度与负载变化
CPU 占用 实时核 ≤ 30% 保留余量应对突发

四、优化路线图

实时性优化不能靠单点技巧,而应按照“测量—定位—修改—复测”的闭环推进。建议的路线如下。

第一步,建立基线。在未做任何实时优化的系统上运行 cyclictest,记录最大延迟和抖动。例如使用 cyclictest -m -p 80 -i 1000 -d 0 -h 400 -n -l 100000,其中 -i 1000 表示 1000 μs 周期,-p 80 表示优先级 80,-m 表示锁定内存。基线数据是后续对比的依据。

第二步,内核实时化。选择与 Sitara BSP 匹配的 PREEMPT_RT 补丁,配置 CONFIG_PREEMPT_RT=y、CONFIG_HIGH_RES_TIMERS=y、CONFIG_NO_HZ_FULL=y 等选项,重新编译并启动。注意 TI SDK 的内核版本与 RT 补丁版本必须对应。

第三步,中断与调度优化。将非关键中断线程化,把实时任务绑到隔离 CPU,设置 SCHED_FIFO 优先级,避免优先级反转。Sitara 上还要注意 PRU 中断与 ARM 中断的协同。

第四步,内存与电源优化。使用 mlockall(MCL_CURRENT | MCL_FUTURE) 锁定内存,关闭 cpuidle 和 cpufreq,禁用不必要的后台服务与日志刷写。

第五步,复测与固化。重复 cyclictest 和实际任务测试,确认最大延迟、抖动和错过率达标,然后把配置写入启动脚本和内核命令行,形成可复现的工程版本。

提示:实时性优化中,最忌讳“先改参数再看结果”。正确顺序永远是先测量、再定位、后修改。没有基线数据的优化,无法判断是否真正有效。
注意:PREEMPT_RT 会改变内核的锁语义和中断处理方式,部分闭源驱动可能不兼容。在 Sitara 上使用 TI 提供的 PRU、SGX、DSP 驱动时,需要确认其是否支持 RT 内核,否则可能出现加载失败或延迟异常。