Linux RT 分析Linux 6.12.107

11 · 性能全景(ARM64):构成模型、微基准、负载矩阵与测量

结论:RT 的收益只体现在「最坏延迟」一个维度——ARM64 上 cyclictest 最大值从非 RT 的数百 µs 到数 ms,降到调优后的 5–50 µs(Neoverse/A76+)或 30–100 µs(A53/A55);平均延迟持平甚至略差。吞吐则按机制退化:CPU 密集几乎无损,锁/中断/softirq/分配密集负载下降 10%–40%。对自动驾驶负载:控制/规划回路受益最大,传感器接入簇付出最多吞吐,感知(GPU/NPU 绑定)基本不受影响。本章先给延迟的构成模型,再逐机制给微基准量级,然后是负载矩阵与延迟预算,最后是复测方法。所有数字除注明外均为公开测试/文献的示意量级,需按 11.6 在目标板实测。

11.1 延迟的构成模型

一次「事件 → 高优先级线程开始执行」的延迟由六段相加:

内容 非 RT RT 决定因素(ARM64)
① 硬件中断延迟 设备 → GIC → CPU 收到异常 相同 相同 GIC 优先级、当前 PSTATE.I/PMR、WFI 唤醒、深度 idle 退出(PSCI,100–300 µs)
② hardirq 停留 从异常入口到 handler 结束 驱动 handler 全部 + softirq 循环(10 µs – 2 ms) 唤醒桩(几 µs) 第 03/04 章;伪 NMI 入口序列;Spectre-BHB 入口循环
③ 不可抢占区剩余 被中断的代码若在关抢占区,要等它结束 spinlock 临界区 / RCU 读区 / bh 段(10 µs – ms) raw 区 / 显式关抢占(< 10 µs) 第 01/02/07 章
④ 调度决策 need_resched__schedule() 选核选任务 相同 相同(TTWU_QUEUE 关,少一次 IPI 延后) 运行队列长度、RT push/pull
⑤ 上下文切换 保存/恢复寄存器、切页表、TLB/缓存 相同 相同 A53 3–5 µs,A72 2–3 µs,A78 1–1.5 µs,N2 ~1 µs;SVE 状态、KPTI 页表切换额外
⑥ 冷启动 目标线程的 L1/L2 冷、TLB 冷 相同 略差(更多切换) 分区可减少

RT 只压缩 ②③,但 ②③ 恰恰是最坏情况的主导项;①⑤⑥ 靠固件/分区/绑核处理。分区 + RT 后,控制线程的最坏延迟 ≈ ① + arch timer hardirq + ④ + ⑤,A78 上通常 10–30 µs。

11.2 各机制微基准(ARM64,示意)

操作 A53/A55(1.2–2 GHz) A72/A76/A78(1.8–2.5 GHz) Neoverse N1/N2 说明
spin_lock+unlock 无争用(非 RT) 25–40 ns(LL/SC) / 15–25 ns(A55 LSE) 20–35 ns(A72 LL/SC) / 8–15 ns(A76+ LSE) 6–12 ns ARM64_USE_LSE_ATOMICS 决定 CAS vs LL/SC
rt_spin_lock+unlock 无争用(RT) 80–150 ns 40–80 ns 25–50 ns 2× cmpxchg + migrate_disable/enable + RCU 进出
争用锁一次睡眠/唤醒(RT) 15–30 µs 5–10 µs 3–6 µs 两次切换 + PI 链
local_irq_disable/enable 2–5 ns(DAIF) 2–5 ns;伪 NMI 开启后 10–30 ns(PMR + sync) irqflags.h:38-39, 67-68
preempt_disable/enable ~1–2 ns ~1 ns ~1 ns 计数
migrate_disable/enable 20–40 ns 10–25 ns 8–15 ns 函数调用 + rq 计数
local_lock/unlock(RT) 100–180 ns 50–100 ns 30–60 ns = rt_spin_lock + migrate
kmalloc(64)+kfree 60–120 ns → RT 150–300 ns 40–80 ns → RT 100–200 ns 30–50 ns → RT 70–120 ns 无锁快路径失效
系统调用 getpid 300–600 ns 150–300 ns 100–200 ns +KPTI(A75)≈ +300 ns;+Spectre-BHB ≈ +30–80 ns
上下文切换(单次) 3–5 µs 1–3 µs ~1 µs perf bench sched pipe 一次往返 = 2 次切换
中断 → irq 线程开始执行(RT) 8–15 µs 3–6 µs 2–4 µs 唤醒 + 切换 + 冷缓存
softirq 线程化每包额外开销(RT) +1–2 µs +0.5–1 µs +0.3–0.6 µs 线程切换分摊到批处理
hrtimer 唤醒最大偏差(RT 任务,HARD,满负载) 20–60 µs 5–20 µs 3–10 µs 含 ① 与 ⑤
非一致性 DMA 缓存维护 0.3–0.5 ms/MB 0.1–0.2 ms/MB 0.05–0.1 ms/MB dcache_clean_poc 逐行
CMA 分配 4 MB(碎片化后) 1–10 ms 0.5–5 ms 0.3–3 ms 迁移页面
PSCI 深度 idle 退出 100–300 µs 50–200 µs 30–100 µs 固件决定

读法:RT 把「不可抢占区」从毫秒级压到微秒级,代价是每个锁/分配/中断操作贵 2–4 倍;这些操作在热路径里的密度决定吞吐损失。

11.3 吞吐影响细分(ARM64)

负载 RT 相对非 RT 主要机制 ARM64 备注
纯用户态计算(矩阵、编解码) 97%–100% 抢占更频繁(无 LAZY) 大核簇几乎无差
内核编译 / 混合 90%–98% 分配器 + 锁 64K 页可略补
hackbench / 管道 65%–90% 切换 + rt_mutex 争用 A53 端更差(切换贵)
网络小包 pps(雷达 UDP、CAN 网关) 60%–90% 线程化中断 + softirq 线程 + backlog 线程 + busylock + 无软合并 硬件合并、GRO、busy_poll 可回到 85%+
网络大包带宽(10 GbE 回放) 85%–98% 每包开销被摊薄
NVMe / UFS 高 IOPS 70%–95% 中断线程化 记录进程本就在 housekeeping
kmalloc/kfree 密集(DDS 序列化、skb) 70%–90% 无锁快路径失效 预分配/对象池可规避
GPU/NPU 推理吞吐 95%–100% 加速器绑定;驱动中断线程化 +几 µs/帧 前提:驱动 RT 兼容
相机流水线(ISP + V4L2) 85%–98% 每帧中断线程化 + DMA 缓存维护不变 缓存维护是主项,与 RT 无关
日志 / 记录写盘 80%–95% I/O 中断线程化 + 分配 nice 10 + housekeeping

11.4 自动驾驶负载矩阵

负载 特征 RT 对最坏延迟 RT 对吞吐 关键机制 放置
控制回路 100 Hz–1 kHz 单线程、周期唤醒、微秒级抖动要求 ms → < 50 µs(核心收益) 无影响 01/02/05 隔离簇,FIFO 90
规划 10 Hz 计算密集、ms 级 抖动大幅收敛 ≈ 无 01 隔离簇,FIFO 80
定位 / 融合 多传感器时间对齐 时间戳抖动下降 ≈ 无 05 隔离簇或接入簇
感知推理 GPU/NPU 提交与等待 提交延迟更稳,帧间抖动小 95%–100% 03/06 接入簇,FIFO 55
相机接入(8–12 路) 高中断率 + 大 DMA 帧到达用户态更可预测 85%–98% 03/06 接入簇,irq 70
激光雷达 / 雷达 UDP 50k–200k pps 到达抖动下降 60%–90%(调优后 85%+) 04 接入簇,napi 60
CAN-FD 数千 pps,控制相关 帧到控制线程 < 100 µs ≈ 无 03 控制核,irq 92
DDS / ROS 2 中间件 几十线程、UDP 多播、序列化分配 关键流抖动下降 80%–95% 04/06 housekeeping + 关键流分级
记录 / 上传 / 诊断 大块 I/O、周期性 不再干扰其它负载 80%–95% 03/06 housekeeping,nice 10

11.5 延迟预算示例:100 Hz 控制回路(10 ms 周期)

阶段 预算 RT + 分区后的典型值(A78) 主要来源
CAN 帧到达 → irq 线程(FIFO 92) 30 µs 5–15 µs ① + hardirq 桩 + 切换
irq 线程 → 控制线程唤醒(FIFO 90) 30 µs 5–15 µs 调度 + 切换
控制计算 2 ms 0.5–1.5 ms 算法;缓存冷启动
指令发出(CAN 发送 / 共享内存) 30 µs 5–20 µs 驱动路径;TSN 时看门控
周期唤醒抖动(clock_nanosleep 50 µs 5–20 µs HARD sleeper + ①
合计抖动上限 < 100 µs 20–60 µs 满足

非 RT 未分区时,同一回路的抖动上限由「最长 softirq/驱动路径」决定,常见 0.5–5 ms,无法满足。

11.6 复测方法

前提

延迟:cyclictest(rt-tests)

stress-ng --cpu $(nproc) --io 4 --vm 2 --vm-bytes 1G --timeout 3600 &
hackbench -l 100000 -g 20 &
iperf3 -c <peer> -t 3600 -u -b 0 -l 64 -P 4 &          # 模拟雷达小包
cyclictest -m -Sp90 -i200 -h400 -D1h -q > all-cpus.txt   # 每 CPU 一线程
cyclictest -m -a8-11 -t4 -p90 -i200 -h400 -D1h -q        # 只看隔离簇

Max Latencies;直方图尾部决定成败。

尖峰归因:osnoise / timerlat / hwlatdetect

osnoise -a 50 -c 8-11 -d 10m            # 谁打断了隔离 CPU(NMI/IRQ/softirq/线程)
timerlat top -c 8-11 -a 50 -T 50        # IRQ 延迟 + 线程延迟拆解,超 50µs 停下打印栈
hwlatdetect --duration=1h --threshold=20  # 固件/安全世界停顿(内核 trace 看不见)
trace-cmd record -p function_graph -e irq -e sched --max-graph-depth 3 cyclictest -m -p90 -i200 -D60 -b50

吞吐

perf bench sched pipe -l 1000000          # 上下文切换(需 arm_pmu;无 PMU 时用 -l 结果的 wall time)
perf bench sched messaging -g 20 -l 10000
hackbench -l 100000 -g 20
iperf3 -c <peer> -t 60 -P 8               # 大包
iperf3 -c <peer> -t 60 -u -b 0 -l 64 -P 8 # 小包 pps(看 lost/total)
fio --name=r --rw=randread --bs=4k --iodepth=64 --numjobs=4 --time_based --runtime=60 --filename=/dev/nvme0n1 --direct=1
# 自动驾驶专项:相机流水线帧率与丢帧、雷达 UDP 丢包、GPU 提交延迟分布(厂商工具 / 自定义探针)

每项重复 5 次取中位数,两侧内核交替跑避免热漂移。

锁、切换与中断分布

perf lock contention -a -- sleep 30       # RT 上显示 rt_mutex 争用
perf stat -e context-switches,cpu-migrations -a sleep 30
cat /proc/interrupts                      # 隔离列应只剩 arch timer;IPI 被 IRQ_HIDDEN 隐藏
ps -eo pid,cls,rtprio,psr,comm | grep -E 'irq/|ksoftirqd|rcuc|napi/|pr/'

一键脚本

doc/tools/bench/rt-bench.sh run [minutes] 按上述顺序跑完并写到 results/<uname -r>/rt-bench.sh compare A B 出表。

11.7 解读要点

小结