Linux RT 分析Linux 6.12.107

PREEMPT_RT 对内核性能的影响

结论先行:PREEMPT_RT 用「几乎处处可抢占」换取有界的最坏延迟——6.12.107 上从毫秒级压到几十微秒;代价是锁、中断、softirq、定时器、内存分配这些热路径都从「关抢占 + 自旋」变成「可抢占 + 睡眠锁 + 线程化」,单次更贵、吞吐下降 0–40%、内核线程更多、能力边界缩小。 它不是让系统「更快」,而是让「最慢的那一次」可预测。

平台聚焦:ARM64。抢占返回路径、`preempt_count` 布局、GIC / arch timer、固件干扰源(EL3 安全世界、PSCI idle、SCMI)、big.LITTLE 与页大小等都按 arm64 描述;`arch/arm64/Kconfig:105` 是 6.12.107 里 arm64 能选 `PREEMPT_RT` 的依据。x86 特有参数(`intel_idle`、`tsc=`、SMI)只作对照,不作建议。

总:全文结构

本分析按 总—分—总 组织:本页给结论与地图;第 01–12 章沿一条因果链逐层展开,每章内部同样「结论 → 第一层图 → 第二层图 → 性能影响 → 源码 → 调优 → 小结」;第 13 章专讲 housekeeping(CPU 分区的内核实现与友商做法),第 14 章把方法落到自动驾驶 SoC;第 15 章是源码索引,第 16 章把全文收拢为一句话、一张表和一个决策。

一个根本改变如何层层展开为 12 个差异点
一个根本改变如何层层展开为 12 个差异点

因果链:抢占模型(01) 是根 → 锁替换(02) 是让「处处可抢占」成立的手段 → 锁能睡了就不能在中断里用,于是 中断、softirq、定时器(03–05) 搬进线程 → 搬进线程后失去「关抢占」的隐含保护,分配器与 per-CPU 数据(06–07) 改用 local_lock + migrate_disable → RCU 与 printk(08–09) 是最后两块拼图 → Kconfig(10) 划定边界 → 基准(11) 量化 → 部署(12) 落地 → housekeeping(13) 讲清分区的内核实现与友商做法 → 自动驾驶 SoC(14) 给出分区样板与参数集。

分:十二个差异点一览

# 差异点 非 RT 机制 RT 机制 最坏延迟 吞吐 / 开销 章节
01 抢占模型 持锁 / softirq / 关中断区不可抢占 仅 raw_spinlock、hardirq 桩、显式 preempt_disable 区不可抢占 ms → 几十 µs 普通任务被更频繁抢占(6.12 尚无 PREEMPT_LAZY) 01
02 spinlock_t / rwlock_t / mutex qspinlock 自旋 + 关抢占 rt_mutex 睡眠锁 + 优先级继承 消除持锁不可抢占 每次 lock/unlock 多 migrate_disable + cmpxchg;争用时睡眠/唤醒 02
03 中断处理 驱动 handler 整个跑在 hardirq primary 只唤醒 irq/N-name 线程(FIFO 50) hardirq 停留时间 → 几 µs 每个中断多一次线程切换;高中断率设备吞吐下降 03
04 softirq / 网络 irq_exit 上就地跑,最长 2ms 不可抢占 在 irq 线程 / ksoftirqd 里跑,local_bh_disable 变 per-CPU 锁 消除 2ms 黑洞 小包 pps 下降;backlog NAPI 恒线程化 04
05 定时器 所有 hrtimer 在 hardirq 到期 只有 *_HARD 留在 hardirq,其余进 softirq 线程 普通回调不再挡 RT 任务 非 RT 任务定时器多一次切换 05
06 内存分配 SLUB 无锁快路径;pcp 关抢占 快路径失效,全程 local_lock;migrate_disable + trylock 分配器可被抢占 kmalloc/kfree 密集负载退化;THP / NUMA balancing 不可用 06
07 per-CPU 数据 preempt_disable() local_lock = per-CPU 睡眠锁 + migrate_disable() 临界区可抢占 锁开销;被钉住的任务干扰负载均衡 07
08 RCU 读端关抢占;回调在 softirq 读端可抢占 + RCU_BOOST;回调在 rcuc/N;禁加急 GP 读区不再挡任务 宽限期变长、回收滞后;expedited 变慢 08
09 printk 调用者亲自刷串口 pr/legacy / nbcon pr/<con> 线程输出 消除日志风暴造成的 ms 级抖动 日志到达变晚 09
10 Kconfig THP / NUMA_BALANCING / i915 / PREEMPT_DYNAMIC 等不可选 特性集缩小 10
11 量化 cyclictest 5–50 µs(调优后) 吞吐 60%–100% 视负载 11
12 部署调优(ARM64) 所有 CPU 共享 固件/idle 收口 + CPU 分区 + 优先级栅格 达到 10 µs 级的前提 12
13 housekeeping CPU 家务撒在所有核 九类家务集中到 housekeeping 核,隔离核只剩 arch timer / IPI 隔离核不再被打扰 housekeeping 核吞吐牺牲 13
14 自动驾驶 SoC 落地 感知/中断/中间件/控制混跑 三簇分区 + 中断亲和 + 完整参数集 控制回路抖动 ms → < 100 µs 接入簇吞吐 -10%–30% 14

延迟与吞吐的量级

最坏延迟:不同抢占模型的常见量级(对数轴)
最坏延迟:不同抢占模型的常见量级(对数轴)
吞吐:RT 相对非 RT 的常见区间
吞吐:RT 相对非 RT 的常见区间

两张图都是示意:区间来自公开测试与文献(见第 11 章),用于建立量级直觉。真实数字取决于硬件(固件/安全世界、idle 状态、DVFS、big.LITTLE)、驱动质量与是否做了 CPU 分区。

总:小结与决策

阅读指南

术语

术语 含义
hardirq / 硬中断上下文 CPU 响应中断后、返回前执行的上下文;关中断(或至少本线屏蔽)、不可抢占
softirq / 下半部 延后到中断返回路径或 ksoftirqd 执行的工作(NET_RX、TIMER、RCU…)
preempt_count 每任务的抢占计数:非零则不可抢占(include/linux/preempt.h:27-55
migrate_disable 禁止任务迁移到别的 CPU 但仍允许被抢占(RT 用它替代 preempt_disable)
local_lock 保护 per-CPU 数据的命名锁;非 RT = preempt_disable,RT = per-CPU spinlock_t
PI(优先级继承) 高优先级任务等锁时,把持锁的低优先级任务临时提升到自己的优先级
rt_mutex 带 PI 的睡眠锁;RT 下 spinlock_t / rwlock_t / mutex / rwsem 的底层实现
cyclictest rt-tests 里的标准延迟测试:周期性唤醒并测量实际唤醒时刻与期望时刻之差

章节

  1. 01 · 抢占模型:不可抢占区的消失
  2. 02 · 锁:spinlock_t / rwlock_t / mutex 全部变成 rt_mutex
  3. 03 · 中断线程化:驱动逻辑离开 hardirq
  4. 04 · softirq 与网络栈:从中断返回路径搬到线程
  5. 05 · 定时器:hard / soft 分流与 expiry_lock
  6. 06 · 内存分配器:无锁快路径失效与上下文限制
  7. 07 · per-CPU 数据:preempt_disable → local_lock + migrate_disable
  8. 08 · RCU:可抢占读端、优先级提升与线程化回调
  9. 09 · printk:调用者不再亲自刷串口
  10. 10 · Kconfig 差异:RT 强制了什么、禁用了什么
  11. 11 · 性能全景(ARM64):构成模型、微基准、负载矩阵与测量
  12. 12 · 部署与调优(ARM64):让 RT 内核真正拿到 10 µs 级延迟
  13. 13 · Housekeeping CPU:内核家务的隔离——原理、内核实现与友商做法
  14. 14 · 自动驾驶 SoC 落地(ARM64):干扰源、分区样板与参数集
  15. 15 · 源码索引:6.12.107 中所有 RT 相关位置
  16. 16 · 全文小结:一句话、一条因果链、一个决策