Linux RT 分析Linux 6.12.107

16 · 全文小结:一句话、一条因果链、一个决策

结论先行(ARM64):PREEMPT_RT 不让系统更快,它让「最慢的一次」可预测。6.12.107 上它把最坏调度延迟从毫秒级压到几十微秒(调优后 5–50 µs),代价是热路径普遍变贵:吞吐型负载损失 0–40%,内核线程更多,能力边界缩小(无 THP、无 NUMA balancing、无 i915)。

全文结构:一个根本改变如何层层展开为 12 个差异点
全文结构:一个根本改变如何层层展开为 12 个差异点

一条因果链

12 个差异点不是并列的,而是从一个改变层层推出来的:

  1. 根本改变(01):内核几乎处处可抢占——不可抢占区只剩 raw_spinlock_t、hardirq 桩、显式 preempt_disable()
  2. 手段(02):要做到这一点,持锁必须能睡 → spinlock_t/rwlock_t/mutex/rwsem 全部换成带 PI 的 rt_mutex。
  3. 延伸(03–05):能睡的锁不能在 hardirq 里用 → 驱动逻辑、softirq、定时器回调统统搬进线程。
  4. 副作用(06–07):搬进线程后,「关抢占」这层隐含保护没了 → 分配器与 per-CPU 数据改用 local_lock + migrate_disable,SLUB 无锁快路径失效。
  5. 收尾(08–09):RCU 读端可抢占 + 回调线程化 + boost;printk 输出交给线程——6.12 的最后一块拼图。
  6. 边界(10):Kconfig 把不兼容的特性直接砍掉,把一批参数固定成常量。
  7. 量化与落地(11–14):延迟赢一个数量级、吞吐让出一到四成;要真正拿到 10 µs 级,还得固件/idle 收口 + CPU 分区(第 13 章 housekeeping)+ 优先级栅格 + 应用侧配合;第 14 章把这套方法落到自动驾驶 SoC 的具体分区样板与参数集。

收益与代价总表

差异点 延迟收益 吞吐 / 开销代价 关键源码
01 抢占模型 不可抢占区 ms → 几十 µs 抢占更频繁(无 LAZY) include/linux/preempt.h:157-162
02 锁 消除持锁不可抢占、无界反转 无争用 2–4 倍;争用睡眠/唤醒 kernel/locking/spinlock_rt.c:46-52
03 中断 hardirq 停留 → 几 µs;优先级可配 每中断多一次切换 include/linux/interrupt.h:516-525
04 softirq 2 ms 黑洞消失 小包 pps 60%–90% kernel/softirq.c:156-264
05 定时器 普通回调不挡 RT 任务 普通任务定时器多一次切换 kernel/time/hrtimer.c:1616-1623
06 内存 分配器可抢占 快路径失效;无 THP/NUMA mm/slub.c:193-205
07 per-CPU 临界区可抢占 锁开销;均衡失真 include/linux/local_lock_internal.h:121-170
08 RCU 读区不挡任务;无 IPI GP 变长;expedited 变慢 kernel/rcu/tree.c:105-109
09 printk 日志风暴不再抖动 日志到达变晚 kernel/printk/internal.h:24-35
10 Kconfig 特性集缩小 kernel/Kconfig.preempt:70-73
13 housekeeping 隔离核只剩 arch timer / IPI housekeeping 核承担全部家务,吞吐牺牲 kernel/sched/isolation.c:118-253
14 自动驾驶 SoC 控制回路抖动 ms → < 100 µs 接入簇吞吐 -10%–30%,靠硬件合并补回 arch/arm64/kernel/entry-common.c:270drivers/cpuidle/Kconfig.arm:27-33

ARM64 上要额外记住的六件事

  1. arm64 不走通用入口:中断返回抢占在 arch/arm64/kernel/entry-common.c:270-302preempt_count 是 u64 union、need_resched 在高 32 位。
  2. 开了伪 NMI(irqchip.gicv3_pseudo_nmi=1)后,伪 NMI 返回不抢占、关中断改走 ICC_PMR_EL1;硬死锁检测又依赖它——按需取舍。
  3. arch timer PPI 与 IPI 不可线程化,是 arm64 RT 上仅剩的常驻 hardirq。
  4. 6.12.107 没有任何串口驱动转成 nbcon,pl011/8250 仍是 legacy;panic 原子输出要等 6.13+。
  5. 固件噪声是 EL3 安全世界、PSCI 深度 idle(分层布局下 RT 拿不到 cluster 态)、DVFS/SCMI、SDEI——用 hwlatdetect 抓。
  6. big.LITTLE:RT 线程钉大核、sched_energy_aware=0;THP 缺失可用 16K/64K 页补偿。
  7. 安全缓解措施有代价:KPTI(仅 kpti_safe_list 之外且 CSV3=0 的核,如 A75)、Spectre-BHB 入口序列(A72–A78 均受影响)每次 syscall/中断多几十到几百 ns;mitigations=/nospectre_bhb 要过安全评审。
  8. 自动驾驶 SoC 的额外噪声:非一致性 DMA 的缓存维护、CMA 迁移、SMMU TLB 失效、GPU/NPU 驱动的锁假设、hypervisor vGIC——6.12.107 没有 MPAM,带宽 QoS 靠 SoC 寄存器。

决策:什么时候该用 RT

用 RT:你的指标是「最坏延迟」而不是「平均吞吐」——运动控制、工业总线(EtherCAT/PROFINET)、音频、软件无线电、高频采集;能接受 10%–40% 的吞吐损失;能做 CPU 分区并管理线程优先级。

不用 RT:指标是吞吐或平均延迟(Web、数据库、存储、通用计算);依赖 THP、NUMA balancing、或 GPU/NPU 厂商驱动尚未通过 RT 验证;没有人力做调优与 24 小时验收——这类场景用 PREEMPT_DYNAMIC + preempt=full 加 CPU 隔离往往更划算。

自动驾驶平台:控制/规划回路必须上 RT;感知(GPU/NPU 绑定)对 RT 不敏感但其驱动必须过 RT 验证;把两者放在不同核簇是第 13/14 章的核心建议。

用 RT 时必做的五件事sched_rt_runtime_us=-1isolcpus/nohz_full/rcu_nocbs/irqaffinity 分区;按业务重排 irq/*rcuc 优先级;应用 mlockall + 预分配 + PI 互斥锁;24 小时 cyclictest 验收。

6.12.107 之后要留意的变化

机制 6.12.107 后续版本 影响
PREEMPT_LAZY 6.13+ 普通任务不再被激进抢占,RT 吞吐改善
ktimerd 线程 6.13+ TIMER_SOFTIRQ 独立线程,可单独调优先级
hrtimer_setup() 6.13+ API 变化,行为不变
SLUB hardirq 分配运行时检查 无(仅注释) 6.15+ 违规驱动会被立刻抓到
更多架构 ARCH_SUPPORTS_RT x86/arm64/riscv 逐步扩展

未尽事项