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 退出的时间可能达到数百微秒,这对硬实时是不可接受的。
第五是用户空间与内核空间的交互开销。系统调用、页错误、信号处理、读写文件都会带来不可预测的延迟。实时任务如果频繁进入内核,抖动会明显增大。
二、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 和实际任务测试,确认最大延迟、抖动和错过率达标,然后把配置写入启动脚本和内核命令行,形成可复现的工程版本。