Linux RT 分析Linux 6.12.107

13 · Housekeeping CPU:内核家务的隔离——原理、内核实现与友商做法

结论:housekeeping CPU 是内核里的正式概念(include/linux/sched/isolation.h:10-19kernel/sched/isolation.c):把 CPU 分成两组,隔离核只跑你指定的实时线程,housekeeping 核承担内核的全部「家务」——周期 tick、定时器迁移、unbound workqueue、内核线程、RCU 回调、负载均衡、managed 中断、杂务统计,再加上用 irqaffinity 赶过去的设备中断。RT 内核解决「内核可抢占」,housekeeping 解决「隔离核不被打扰」,两者叠加才有 10 µs 级最坏延迟。它由四条启动参数决定(isolcpus=domain,managed_irq,…nohz_full=rcu_nocbs=irqaffinity=),缺一条就漏一类家务;CPU0 永远是 housekeeping。友商——Red Hat tuned / OpenShift、Ubuntu Real-time、NVIDIA Jetson、百度 Apollo——做的都是这同一套参数的封装,差别只在自动化程度、验证手段,以及厂商 RT 内核是否带齐了所需配置。

第一层:家务落在哪里

先看结论:没有 housekeeping 时,九类家务按各自规则随机落核,任何一颗核都可能被打扰;配置后家务集中到 housekeeping 核,隔离核只剩 arch timer、IPI 和线程自己触发的内核路径。

非 RT九类家务撒在所有 CPU 上
非 RT:九类家务撒在所有 CPU 上
同一场景 · 换成 PREEMPT_RT 内核
PREEMPT_RT家务集中到 housekeeping 核,隔离核只剩 arch timer / IPI
RT:家务集中到 housekeeping 核,隔离核只剩 arch timer / IPI

第二层:内核机制与参数映射

先看结论nohz_full= 一次接管六类家务(tick/timer/RCU-misc/wq/kthread),isolcpus= 管调度域与 managed 中断,rcu_nocbs= 管回调线程,irqaffinity= 管其余设备中断;cgroup cpuset 只能补充任务隔离,管不了 tick 与中断。

非 RT内核里的家务清单——谁产生、默认落在哪
非 RT:内核里的家务清单——谁产生、默认落在哪
同一场景 · 换成 PREEMPT_RT 内核
PREEMPT_RT参数 → HK_TYPE 映射、解析规则、验证与友商封装
RT:参数 → HK_TYPE 映射、解析规则、验证与友商封装

13.1 九类家务与对应的内核机制

include/linux/sched/isolation.h:10-19 定义了 HK_TYPE_TIMER / RCU / MISC / SCHED / TICK / DOMAIN / WQ / MANAGED_IRQ / KTHREAD,每种一个 cpumask(isolation.c:27)。内核各处用 housekeeping_cpumask(type) / housekeeping_any_cpu(type) / housekeeping_test_cpu() 决定家务落点:

家务 谁产生 默认落点 配置后 位置
周期 tick 每 HZ 一次的 tick_sched_timer 每颗核 nohz_full 核上单任务运行时停止 kernel/time/tick-sched.c
定时器迁移 非 pinned 的 timer/hrtimer 到期核选择 本核 优先 HK_TYPE_TIMER kernel/time/hrtimer.c:225, 2275kernel/sched/core.c:1140-1155
unbound workqueue kworker/u*(文件系统回写、驱动延后工作) 任意核 限制到 HK_TYPE_WQ ∩ HK_TYPE_DOMAIN kernel/workqueue.c:7800-7807;延迟工作 :2553-2554
内核线程 kthreadd 及其子线程 任意核 亲和 HK_TYPE_KTHREAD kernel/kthread.c:371, 746
RCU 回调 call_rcu/kfree_rcu 的回调执行 本核(rcuc/softirq) rcu_nocbs 后由 rcuo 线程执行,线程亲和 HK_TYPE_RCU kernel/rcu/tree_plugin.h:1378kernel/rcu/tree_nocb.h
负载均衡 / 调度域 CFS 周期均衡、唤醒选核 全部核 隔离核退出 sched domain kernel/sched/topology.c:1435, 2625, 2717, 2752
managed 中断 多队列 NVMe / 网卡按队列自动分配的中断 每队列一核 只用 HK_TYPE_MANAGED_IRQ kernel/irq/manage.c:258kernel/irq/cpuhotplug.c:198
杂务 vmstat 更新、软/硬死锁检测线程、idle 负载均衡 每颗核 HK_TYPE_MISC/TIMER kernel/watchdog.c:1249kernel/sched/fair.c:12354kernel/cpu.c:1490, 1905
设备中断 GIC SPI / ITS LPI irq_default_affinity(全部核)+ irqbalance 打散 irqaffinity= 设默认;/proc/irq/*/smp_affinity 逐个改 kernel/irq/irqdesc.ckernel-parameters.txt:2436

RT 内核下这些家务大多已经是线程(irq/*ksoftirqdrcuckworker),可抢占;housekeeping 做的是把它们从隔离核上挪走,否则它们即使优先级低,也会带来缓存污染、IPI 与偶发的高优先级唤醒。

13.2 内核实现:kernel/sched/isolation.c

13.3 隔离核上还剩什么

即使四条参数齐全,隔离核上仍会出现:

剩余项 来源 处理
arch timer PPI 隔离核上任务自己的 hrtimer 到期(nohz_full 只是停周期 tick) 正常,属于任务自己的时间
IPI 其它核发来的 TLB 失效(共享 mm 的 munmap)、smp_call_function、内核文本修补(ftrace/static key 切换)、reschedule 隔离核进程用独立地址空间;housekeeping 进程避免频繁 munmap/mprotect;生产环境不动 ftrace/静态键
per-CPU 内核线程 migration/Ncpuhp/Nksoftirqd/Nkworker/N:*、RT 下的 rcuc/N 只要没人 raise softirq / 排 per-CPU work,它们不会跑;用 osnoise 确认
任务自己触发的内核路径 系统调用、缺页、信号 应用侧 mlockall、预分配、热路径无系统调用
伪 NMI / PMU 开启伪 NMI 且 perf 采样时 生产环境关闭采样

osnoise -c <隔离核> 的输出把这些逐项列出(NMI/IRQ/softirq/线程各占多少),是验收隔离质量的标准工具。

13.4 怎么做

  1. 划分:以簇为单位(共享 L3 的核放一起);big.LITTLE 上小核簇做 housekeeping、大核簇隔离;CPU0 必在 housekeeping;经验值 8 核给 2、12 核给 4。
  2. 启动参数(示例 12 核,0-3 housekeeping): isolcpus=domain,managed_irq,4-11 nohz_full=4-11 rcu_nocbs=4-11 irqaffinity=0-3
  3. 运行时脚本:停 irqbalance/proc/irq/default_smp_affinity 与所有 /proc/irq/*/smp_affinity_list 指向 housekeeping;需要留在隔离核的控制设备中断单独指定;RT 线程 taskset/pthread_setaffinity_np 钉到隔离核;其它进程默认留在 housekeeping(isolcpus=domain 保证调度器不往隔离核放)。systemd 服务可用 CPUAffinity=0-3(或 systemd.cpu_affinity= 启动参数)兜底。
  4. 验证/sys/devices/system/cpu/isolated/sys/devices/system/cpu/nohz_full/proc/interrupts 隔离列、ps -eo psr,cls,rtprio,commosnoise/timerlatls /sys/kernel/debug/sched/domains/cpu4/(应为空)。
  5. 预算:housekeeping 核会很忙——所有 irq/*ksoftirqdrcuokworker、中间件线程都挤在这里;它的吞吐是牺牲品,用第 11 章的方法量化。

13.5 友商怎么做

友商 / 产品 机制 参数与做法(公开资料) 特点与启示
Red Hat RHEL for Real Timetuned realtime profile) 一个变量 isolated_cores/etc/tuned/realtime-variables.conf)驱动全部配置 [bootloader] 生成 isolcpus=[managed_irq,]<cores>、禁 P-state、nosoftlockup[sysctl] kernel.sched_rt_runtime_us=-1[sysfs]workqueue/cpumask 与 machinecheck 指向非隔离核;[irqbalance] 黑名单隔离核;[scheduler] 把已存在线程/中断挪走;realtime-virtual-host 再加 nohz_full=rcu_nocbs=irqaffinity=,关 KSM,并给 ksoftirqd/ktimers/rcuc/rcub 设 FIFO 优先级 最成熟的封装:一处变量、启动+运行时一起管、包含 workqueue cpumask 与 irqbalance 这两个常被漏掉的点;把「运行时挪线程」做进 profile 而不是靠人
Red Hat OpenShift(PerformanceProfile / Node Tuning Operator) CR 里声明 cpu.reserved(= housekeeping)与 cpu.isolated 自动生成 nohz=on rcu_nocbs=<iso> tuned.non_isolcpus=<mask> nosoftlockup tsc=nowatchdog iommu=pt systemd.cpu_affinity=<reserved> isolcpus=managed_irq,<iso>balanceIsolated=false 时含 domain),配合 kubelet 静态 CPU 管理与「工作负载分区」把平台守护进程钉到 reserved 明确把用户态守护进程也归入 housekeepingsystemd.cpu_affinity);managed_irqdomain 分开可选——高吞吐容器可以保留负载均衡
Canonical Ubuntu Real-time 文档化的一组启动参数 nohz=on nohz_full=<list> isolcpus=<list> rcu_nocbs=<list> irqaffinity=<list> rcu_nocb_poll;示例 isolcpus=3-5 irqaffinity=0-2,6-N;告诫:boot CPU 不能进 nohz_fullirqaffinity 不能为空、softirq 无法完全排除、运行时用 tuna 调整 与内核文档一致的最小集;rcu_nocb_pollrcuo 轮询而不靠 IPI 唤醒,是隔离核减少 IPI 的补充手段
NVIDIA Jetson(L4T r36.x / JetPack 6,Orin) RT 内核以 OTA Debian 包提供(nvidia-l4t-rt-kernel*),extlinux.conf 切换 官方文档只给安装步骤,并提示 UEFI runtime services 默认开启会增加延迟;未给 isolcpus/nohz_full 指导。社区反馈:OTA RT 内核未启用 NO_HZ_FULL/RCU_NOCB_CPUnohz_full=/rcu_nocbs= 被忽略,需自编译(meta-tegra LINUX_KERNEL_TYPE=preempt-rt);隔离后 cyclictest 50–200 µs 厂商 RT 内核不一定带齐 housekeeping 需要的配置——上手第一步是 zcat /proc/config.gz \| grep -E 'NO_HZ_FULL\|RCU_NOCB';EFI runtime 在 6.12 RT 上默认已禁(第 10 章)
百度 Apollo Cyber RT 用户态协程调度器按数据流分组绑核 example_sched_choreography.confprocess_level_cpuset "0-7,16-23";线程 lidar 绑 CPU1 SCHED_RR 10shm 绑 CPU2 SCHED_FIFO 10;choreography 处理器 8 个绑 0-7 SCHED_FIFO 10,pool 处理器 8 个绑 16-23 SCHED_OTHER;任务按 processor + prio 编排 典型的用户态分区:按数据流把协程调度器钉到 cpuset 并分优先级,与第 14 章「接入/感知 vs 控制」分簇同构;但它不做内核侧 housekeeping,必须配合本章参数才能把内核家务赶走
Intel ECI / TCC(x86 对照) isolcpus + 缓存分区(CAT)+ TCC 缓冲 隔离核 + L2/L3 way 分配给实时任务 缓存/带宽分区是 housekeeping 的下一层;arm64 对应 MPAM,6.12.107 无驱动,只能靠 SoC QoS 寄存器
Xenomai 4 / EVL、Jailhouse / NXP Harpoon 另一条路:把隔离核整个交给另一个内核(EVL 核或 RTOS) Jailhouse cell 独占 CPU + 设备;Harpoon 在隔离核跑 Zephyr/FreeRTOS AMP 方案把「家务」问题从根上消灭,代价是应用不能用 Linux API;自动驾驶 SoC 上通常由 Cortex-R 安全岛承担这一角色
ROS 2 / Apex.AI 实时指南、OSADL QA farm 应用层规范 isolcpus + SCHED_FIFO executor + mlockall + 无动态分配;OSADL 测试机用 shielded CPU 长期跑 cyclictest 与本章一致;OSADL 数据是第 11 章量级的来源之一

共同点:没有人绕开这四条启动参数;差别在 ① 是否把 workqueue cpumask、irqbalance、已存在线程的迁移做成自动化(Red Hat 最完整);② 是否把用户态守护进程也纳入 housekeeping(OpenShift 明确做了);③ 厂商内核是否带齐 NO_HZ_FULL/RCU_NOCB_CPU(Jetson 的教训)。

13.6 对自动驾驶 SoC 的启示

源码定位

主题 位置
HK 类型与标志 include/linux/sched/isolation.h:10-19kernel/sched/isolation.c:12-27
参数解析 kernel/sched/isolation.c:118-253
workqueue / kthread kernel/workqueue.c:2553-2554, 7800-7807kernel/kthread.c:371, 746
定时器 kernel/time/hrtimer.c:225, 2275kernel/sched/core.c:1140-1155
RCU kernel/rcu/tree_plugin.h:1378kernel/rcu/tree_nocb.h
调度域 kernel/sched/topology.c:1435, 2625, 2717, 2752kernel/sched/core.c:8359
managed 中断 kernel/irq/manage.c:258kernel/irq/cpuhotplug.c:198
杂务 / 热插拔 kernel/watchdog.c:1249kernel/sched/fair.c:12354kernel/cpu.c:1490, 1905
cpuset 分区 kernel/cgroup/cpuset.c:126Documentation/admin-guide/cgroup-v2.rst:2449-2505
参数文档 Documentation/admin-guide/kernel-parameters.txt:2436-2470, 3984-3990

小结