10 · Kconfig 差异:RT 强制了什么、禁用了什么
结论:选中
CONFIG_PREEMPT_RT不只是换一种抢占模型。它要求EXPERT与ARCH_SUPPORTS_RT(6.12.107 只有 x86 / arm64 / riscv),与PREEMPT_DYNAMIC互斥,强制RT_MUTEXES、PREEMPT_RCU、RCU_BOOST,把THP、NUMA_BALANCING、DRM_I915、QUEUED_RWLOCKS、KMSAN、DEBUG_MUTEXES、DEBUG_RWSEMS等直接变成不可选,并把一批运行时参数(use_softirq、rcu_normal_after_boot、threadirqs)固定为常量。本章是全树 34 处 Kconfig 引用的完整清单。
第一层:特性矩阵
先看结论:RT 不是「多一个选项」——它砍掉 11 个特性(THP、NUMA balancing、i915、PREEMPT_DYNAMIC…)并固定一批运行时参数。
第二层:依赖关系
先看结论:入口只有
depends on EXPERT && ARCH_SUPPORTS_RT+select PREEMPTION两行,其余联动靠各子系统自己的default/depends。
入口
kernel/Kconfig.preempt:70-73:
config PREEMPT_RT
bool "Fully Preemptible Kernel (Real-Time)"
depends on EXPERT && ARCH_SUPPORTS_RT
select PREEMPTION
PREEMPTION 再 select PREEMPT_COUNT(:92-94)。ARCH_SUPPORTS_RT 定义于 arch/Kconfig:1359-1360,由 arch/x86/Kconfig:128、arch/arm64/Kconfig:105、arch/riscv/Kconfig:68 选中;32 位 ARM、PowerPC、MIPS、s390、LoongArch 在 6.12.107 不能选 RT。菜单里要先勾 General setup → Configure standard kernel features (expert users),"Fully Preemptible Kernel (Real-Time)" 才会出现在 Preemption Model 里。
不可选(depends on !PREEMPT_RT)
| 符号 | 含义 | 位置 | 原因 |
|---|---|---|---|
PREEMPT_DYNAMIC |
启动参数切换抢占模型 | kernel/Kconfig.preempt:98 |
RT 是独立实现 |
TRANSPARENT_HUGEPAGE |
透明大页 | mm/Kconfig:818 |
折叠/压缩延迟 |
NUMA_BALANCING |
自动 NUMA 迁移 | init/Kconfig:953 |
迁移引起的延迟 |
QUEUED_RWLOCKS |
队列读写锁 | kernel/Kconfig.locks:254 |
rwlock_t 换成 rwbase_rt |
DRM_I915 |
Intel 集显驱动(x86;arm64 无关) | drivers/gpu/drm/i915/Kconfig:6 |
驱动内大量不兼容 RT 的锁用法 |
KMSAN |
未初始化内存检测 | lib/Kconfig.kmsan:15 |
|
DEBUG_MUTEXES / DEBUG_RWSEMS |
经典锁调试 | lib/Kconfig.debug:1456, 1481 |
换 DEBUG_RT_MUTEXES |
DEBUG_VM_IRQSOFF |
DEBUG_VM 的关中断子集 | lib/Kconfig.debug:812 |
RT 下不关中断 |
SOFTIRQ_ON_OWN_STACK |
softirq 独立栈 | arch/Kconfig:1046 |
softirq 在线程栈上 |
HIGHPTE(仅 32 位 arm) |
二级页表放 highmem | arch/arm/Kconfig:1232 |
arm64 无此项 |
LEDS_TRIGGER_CPU |
CPU 活动 LED | drivers/leds/trigger/Kconfig:67 |
原子上下文更新 |
PROVE_LOCKING / LOCK_STAT / DEBUG_LOCK_ALLOC / DEBUG_WW_MUTEX_SLOWPATH 的 select DEBUG_MUTEXES if !PREEMPT_RT(lib/Kconfig.debug:1356, 1358, 1420, 1466, 1490)与 select DEBUG_RT_MUTEXES if PREEMPT_RT(:1467)随之切换。
强制 / 默认改变
| 符号 | RT 下 | 位置 | 说明 |
|---|---|---|---|
RT_MUTEXES |
default y |
init/Kconfig:2026 |
所有睡眠锁的基底 |
PREEMPT_RCU |
default y if PREEMPTION |
kernel/rcu/Kconfig:20 |
|
RCU_BOOST |
default y,且不需要 RCU_EXPERT |
kernel/rcu/Kconfig:200-201 |
|
RCU_NOCB_CPU_CB_BOOST |
default y |
kernel/rcu/Kconfig:282 |
offload 回调用 FIFO |
RCU_EXP_KTHREAD |
默认关 | kernel/rcu/Kconfig:227 |
加急 GP 启动后被禁 |
TASKS_TRACE_RCU_READ_MB |
default PREEMPT_RT |
kernel/rcu/Kconfig:298 |
屏障代替 IPI |
EFI_DISABLE_RUNTIME |
default y |
drivers/firmware/efi/Kconfig:240-249 |
「测量表明某些 EFI 调用耗时过长」 |
COMPACT_UNEVICTABLE_DEFAULT |
0(非 RT 1) | mm/Kconfig:651 |
避免压缩引起缺页 |
DRM_MGAG200_DISABLE_WRITECOMBINE |
RT 专属选项 | drivers/gpu/drm/mgag200/Kconfig:17 |
Write-Combine 干扰其它核上的 RT 任务 |
NET_RX_BUSY_POLL |
default y 仅当无 NETCONSOLE |
net/Kconfig:345 |
编译期固定的运行时行为
| 行为 | 非 RT | RT | 位置 |
|---|---|---|---|
force_irqthreads() |
static key,threadirqs 参数打开 |
恒 true,参数不存在 | include/linux/interrupt.h:516-525;kernel/irq/manage.c:27-35 |
rcutree.use_softirq |
默认 1,可调 | 恒 0,参数不注册 | kernel/rcu/tree.c:105-109 |
rcupdate.rcu_normal_after_boot |
默认 0,可调 | 恒 1(无 NO_HZ_FULL 时不注册) | kernel/rcu/update.c:60-62 |
irqfixup / irqpoll |
可用 | 拒绝 | kernel/irq/spurious.c:450-468 |
thread_backlog_napi |
参数可开 | 恒开 | net/core/dev.c:204-225 |
| 软 IRQ 合并默认 | 开 | 关 | net/core/dev.c:11202-11210 |
TTWU_QUEUE / RT_PUSH_IPI / SCHED_NR_MIGRATE_BREAK |
true / false / 32 | false / true / 8 | kernel/sched/features.h:75-116;kernel/sched/sched.h:2833-2837 |
cgroup v1 soft_limit_in_bytes、cgroup.event_control |
可用 | -EOPNOTSUPP |
mm/memcontrol-v1.c:1946-1947, 2576-2577 |
preempt= 启动参数 |
none/voluntary/full | 无(没有 preempt=rt) |
Documentation/admin-guide/kernel-parameters.txt:4826-4833 |
只是帮助文本提到 RT
drivers/cpuidle/Kconfig.arm:27-33(ARM_PSCI_CPUIDLE):分层 idle 状态布局下 RT 只能用 per-CPU idle 状态。lib/Kconfig.debug:1398-1411(PROVE_RAW_LOCK_NESTING):在非 RT 内核上检查 RT 的锁嵌套规则,默认 n,「已知会有 lockdep splat」。mm/Kconfig:324-328(SLUB_CPU_PARTIAL):「实时系统通常选 N」。
6.12.107 没有的
PREEMPT_LAZY/NEED_RESCHED_LAZY(6.13)。kernel/rcu/Kconfig:94引用的PREEMPT_AUTO全树未定义,该子句无效。Documentation/scheduler/、Documentation/kernel-hacking/locking.rst、Documentation/core-api/local_ops.rst都没有任何PREEMPT_RT说明——后者关于get_cpu_var()的建议在 RT 上已经过时但文件没提。
ARM64 相关的 Kconfig(arch/arm64/Kconfig)
| 符号 / 行 | 含义 | 对 RT 的意义 |
|---|---|---|
:105 select ARCH_SUPPORTS_RT |
arm64 可选 RT | 本文成立的前提 |
:249 select IRQ_FORCED_THREADING |
支持强制线程化 | 第 03 章 |
:237 select HAVE_POSIX_CPU_TIMERS_TASK_WORK |
POSIX CPU 定时器走 task_work | 第 05 章 |
:235 select HAVE_PREEMPT_DYNAMIC_KEY |
DYNAMIC 用静态键 | RT 下无效(DYNAMIC 与 RT 互斥) |
:58-83 ARCH_INLINE_*_LOCK if !PREEMPTION |
非抢占内核内联锁操作 | RT 下全部 out-of-line |
:101 / :191 |
ARCH_SUPPORTS_NUMA_BALANCING / HAVE_ARCH_TRANSPARENT_HUGEPAGE |
两者在 RT 下都被上层 !PREEMPT_RT 砍掉 |
:224-225, 232 |
硬死锁检测器需 HAVE_PERF_EVENTS_NMI if ARM64_PSEUDO_NMI |
要 NMI 看门狗必须开伪 NMI |
:2292-2315 ARM64_PSEUDO_NMI / ARM64_DEBUG_PRIORITY_MASKING |
伪 NMI 与其调试检查 | 调试选项每次开关中断多一次 PMR 读,延迟测试时关掉 |
:1372-1394 页大小 choice |
4K / 16K / 64K | 64K 页补偿 THP 缺失;:1678-1680 ARCH_FORCE_MAX_ORDER 随之变大(13/11/10) |
:1527-1544 SCHED_MC / SCHED_CLUSTER / SCHED_SMT |
调度拓扑 | DynamIQ 集群感知 |
:128 select CPU_PM if (SUSPEND || CPU_IDLE) |
CPU 电源管理 | 与 PSCI idle 配合 |
drivers/cpuidle/Kconfig.arm:17-44 ARM_PSCI_CPUIDLE / _DOMAIN(default y) |
PSCI idle 驱动 | RT 限制(:27-33):分层 idle 布局下只有 per-CPU 状态可用,cluster 级状态不可用 |
drivers/firmware/efi/Kconfig:238-249 |
EFI_DISABLE_RUNTIME default y if PREEMPT_RT |
对 arm64 UEFI 平台同样生效 |
drivers/firmware/Kconfig:31-38 ARM_SDE_INTERFACE |
SDEI(固件→OS 回调,RAS 通知) | 固件侧干扰源 |
kernel/power/Kconfig:362 ENERGY_MODEL;arch/arm64/configs/defconfig:88 |
EAS 默认开 | kernel/sched/topology.c:211, 317-322, 432 sched_energy_aware 可关 |
:1696 UNMAP_KERNEL_AT_EL0、:1708 MITIGATE_SPECTRE_BRANCH_HISTORY |
KPTI 与 Spectre-BHB 缓解 | 入口开销(第 01 章);39 个 ARM64_ERRATUM_*(:461-1142)部分会加屏障 |
:2005 ARM64_PTR_AUTH、:2115 ARM64_BTI、:2158 ARM64_E0PD、:2178 ARM64_MTE、:2249 ARM64_SVE、:2280 ARM64_SME、:2330 RANDOMIZE_BASE、:2381 ARM64_CONTPTE |
安全/向量扩展/大页连续 PTE | MTE 同步模式与 SVE 状态切换有可见开销;其余可忽略 |
kernel/Kconfig.hz:8 default HZ_250;arch/arm64/configs/defconfig:4, 8, 88 |
arm64 默认 HZ=250、NO_HZ_IDLE、PREEMPT=y、ENERGY_MODEL=y |
RT 建议 HZ_1000 + NO_HZ_FULL |
无 HIGHMEM、无 arch/arm64/include/asm/highmem.h |
— | 第 06 章的 kmap_atomic 议题在 arm64 不存在 |
无 select GENERIC_ENTRY |
自有入口代码 | 第 01 章 |
性能影响
净影响:无运行时开销,但决定了能力边界(大页、NUMA、集显、EFI runtime、cgroup v1 软限制)。
Kconfig 差异本身不产生运行时开销,但它决定了能力边界:没有 THP 意味着 TLB 压力只能靠 hugetlbfs;没有 NUMA balancing 意味着跨节点访问要手工 numactl;EFI runtime 关闭意味着 efivarfs、固件更新工具不可用;DEBUG_MUTEXES 换成 DEBUG_RT_MUTEXES 意味着调试构建的开销特征不同。
源码定位
见上表;完整 34 处引用来自 grep -rn "PREEMPT_RT" --include=Kconfig*。
调优要点
- 从 arm64 defconfig 出发做 RT 内核:先
EXPERT=y,选PREEMPT_RT,然后make olddefconfig看哪些符号被静默去掉(THP、NUMA_BALANCING 尤其要注意;多路 Neoverse 服务器失去 NUMA balancing 后要手工numactl)。 - 页大小与
ARM64_PSEUDO_NMI在这一步一起定;ARM64_DEBUG_PRIORITY_MASKING保持关闭。 - 生产 RT 内核关掉
DEBUG_PREEMPT、LOCKDEP、KASAN、DEBUG_RT_MUTEXES——它们各自增加数百 ns 到 µs 级的开销。
小结
- 6.12.107 只有 x86 / arm64 / riscv 能选 RT。
- 不可选清单里对桌面/工控最疼的是
DRM_I915与TRANSPARENT_HUGEPAGE。 threadirqs、rcutree.use_softirq、rcupdate.rcu_normal_after_boot、preempt=在 RT 上都不存在或被固定。- 承上启下:机制与边界都清楚了,第 11 章回答「到底差多少」。