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 章把全文收拢为一句话、一张表和一个决策。
因果链:抢占模型(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 |
延迟与吞吐的量级
两张图都是示意:区间来自公开测试与文献(见第 11 章),用于建立量级直觉。真实数字取决于硬件(固件/安全世界、idle 状态、DVFS、big.LITTLE)、驱动质量与是否做了 CPU 分区。
总:小结与决策
- 收益只在一个维度:最坏延迟下降约两个数量级;平均延迟基本持平。
- 代价分布在所有热路径:锁 2–4 倍、每中断一次切换、softirq/定时器进线程、分配器拿锁、RCU 宽限期变长。
- 决策:指标是最坏延迟就用 RT,并做满「限流取消、CPU 分区、优先级栅格、应用锁内存、24 小时验收」五件事;指标是吞吐就别用,
PREEMPT_DYNAMIC+ CPU 隔离更划算。 - 完整版见 16 · 全文小结。
阅读指南
- 每章结构固定:结论 → 第一层图对(非 RT / RT)→ 第二层图对 → 性能影响表 → 源码定位 → 调优要点 → 小结(含与下一章的衔接);每个二级节的第一句都是该节结论。
- 第一层图看「谁在什么上下文里跑、谁在等谁」;第二层图标出具体函数与常量,可与
linux/目录里的源码逐行对照。 - 「源码定位」表里的行号全部来自 6.12.107;升级到其它版本时函数名大多不变,行号会漂移。
- 与 RT 相关但 6.12.107 没有的东西会明确标注(例如
PREEMPT_LAZY、ktimerd线程、hrtimer_setup()都是 6.13+ 才出现)。
术语
| 术语 | 含义 |
|---|---|
| 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 里的标准延迟测试:周期性唤醒并测量实际唤醒时刻与期望时刻之差 |
章节
- 01 · 抢占模型:不可抢占区的消失
- 02 · 锁:spinlock_t / rwlock_t / mutex 全部变成 rt_mutex
- 03 · 中断线程化:驱动逻辑离开 hardirq
- 04 · softirq 与网络栈:从中断返回路径搬到线程
- 05 · 定时器:hard / soft 分流与 expiry_lock
- 06 · 内存分配器:无锁快路径失效与上下文限制
- 07 · per-CPU 数据:preempt_disable → local_lock + migrate_disable
- 08 · RCU:可抢占读端、优先级提升与线程化回调
- 09 · printk:调用者不再亲自刷串口
- 10 · Kconfig 差异:RT 强制了什么、禁用了什么
- 11 · 性能全景(ARM64):构成模型、微基准、负载矩阵与测量
- 12 · 部署与调优(ARM64):让 RT 内核真正拿到 10 µs 级延迟
- 13 · Housekeeping CPU:内核家务的隔离——原理、内核实现与友商做法
- 14 · 自动驾驶 SoC 落地(ARM64):干扰源、分区样板与参数集
- 15 · 源码索引:6.12.107 中所有 RT 相关位置
- 16 · 全文小结:一句话、一条因果链、一个决策