4. 子系统裁剪(上):进程调度、内存管理、中断子系统的核心选项与裁剪策略
嵌入式 Linux 内核的裁剪工作,核心在于理解各子系统的功能边界与资源消耗。本章聚焦于三个最基础的子系统:进程调度、内存管理和中断子系统。这些子系统在内核中无处不在,其配置选项直接影响系统的实时性、内存占用和响应速度。错误的裁剪可能导致系统崩溃或功能缺失,而精准的裁剪则能显著降低内核体积并提升启动性能。
4.1 进程调度子系统裁剪
进程调度器负责决定哪个任务获得 CPU 使用权。Linux 内核支持多种调度类(Scheduling Classes),每种调度类对应不同的调度策略和适用场景。对于嵌入式系统,通常只需要其中一到两种。
4.1.1 核心调度选项
| 配置选项 | 默认值 | 裁剪建议 | 说明 |
|---|---|---|---|
CONFIG_SCHED_DEBUG | y | n | 调度器调试信息,生产环境必须关闭 |
CONFIG_SCHEDSTATS | y | n | 调度统计,增加运行时开销 |
CONFIG_SCHED_CORE | y | n | 核心调度(Core Scheduling),仅多租户场景需要 |
CONFIG_FAIR_GROUP_SCHED | y | n | CFS 组调度,无多用户/容器需求可关闭 |
CONFIG_RT_GROUP_SCHED | y | n | 实时组调度,无严格优先级分组需求可关闭 |
CONFIG_CGROUP_SCHED | y | n | cgroup 调度控制,无容器场景可关闭 |
裁剪要点:对于单用户、单任务的深度嵌入式系统,可以关闭所有与组调度和调试相关的选项。这通常能减少约 10-15 KB 的内核映像大小,并降低调度路径上的分支预测开销。
4.1.2 调度类选择
Linux 内核支持以下主要调度类,每个调度类都对应一个 CONFIG_ 选项:
- CFS (Completely Fair Scheduler) —
CONFIG_SCHED_CFS:通用调度器,默认开启,通常保留。 - RT (Real-Time) —
CONFIG_SCHED_RT:实时 FIFO/RR 调度,硬实时场景必须保留。 - DL (Deadline) —
CONFIG_SCHED_DEADLINE:EDF 调度器,非实时系统可关闭。 - IDLE —
CONFIG_SCHED_IDLE:空闲调度类,通常保留。
裁剪策略:如果系统不需要硬实时任务,可以关闭
CONFIG_SCHED_RT 和 CONFIG_SCHED_DEADLINE。这能减少约 8 KB 的代码段。但需注意,关闭 RT 调度后,sched_setscheduler() 系统调用将无法设置 SCHED_FIFO/SCHED_RR 策略。
4.1.3 进程调度裁剪流程图
4.2 内存管理子系统裁剪
内存管理子系统是内核中代码量最大的模块之一。对于内存受限的嵌入式系统,精细裁剪可以释放数百 KB 的代码和数据空间。
4.2.1 页面分配器与伙伴系统
| 配置选项 | 默认值 | 裁剪建议 | 说明 |
|---|---|---|---|
CONFIG_COMPACTION | y | n | 内存碎片整理,无长时间运行需求可关闭 |
CONFIG_MIGRATION | y | n | 页面迁移,与 COMPACTION 联动 |
CONFIG_KSM | y | n | 内核同页合并,仅虚拟化场景需要 |
CONFIG_TRANSPARENT_HUGEPAGE | y | n | 透明大页,嵌入式小内存系统无收益 |
CONFIG_CMA | y | 按需 | 连续内存分配器,DMA 设备需要时保留 |
4.2.2 SLUB 分配器调优
内核对象缓存分配器(SLUB)是内存管理的关键路径。以下选项直接影响性能和内存占用:
# 针对小内存系统的 SLUB 优化配置
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG=n # 关闭调试,减少约 4 KB
CONFIG_SLUB_MEMCG_SYSFS=n # 关闭 memory cgroup 接口
CONFIG_SLUB_CPU_PARTIAL=y # 保留 CPU 部分空闲列表,提升性能
CONFIG_SLAB_FREELIST_HARDENED=n # 关闭 freelist 加固,节省约 2 KB
注意:关闭
CONFIG_SLAB_FREELIST_HARDENED 会降低内核对抗堆溢出攻击的能力。仅在完全可信的执行环境中执行此操作。
4.2.3 内存管理裁剪前后对比
4.3 中断子系统裁剪
中断子系统是系统响应外部事件的基石。其配置直接影响中断延迟和 CPU 开销。嵌入式系统通常只需要支持有限的中断控制器类型。
4.3.1 中断控制器驱动选择
内核支持多种中断控制器(IRQ Chip)驱动。通过 make menuconfig 进入 Device Drivers -> Interrupt controllers 进行选择:
| 驱动选项 | 适用硬件 | 裁剪建议 |
|---|---|---|
CONFIG_ARM_GIC | ARM Generic Interrupt Controller | ARM 平台必须保留 |
CONFIG_ARM_GIC_V3 | GICv3/v4 | ARMv8 平台必须保留 |
CONFIG_IMX_IRQSTEER | i.MX 中断转向控制器 | 仅 i.MX 平台需要 |
CONFIG_RENESAS_IRQC | Renesas IRQC | 仅 Renesas 平台需要 |
CONFIG_TI_SCI_INTA_IRQCHIP | TI SCI INTA | 仅 TI 平台需要 |
裁剪策略:只保留目标平台对应的中断控制器驱动。例如,对于 i.MX6ULL 平台,只保留
CONFIG_ARM_GIC 和 CONFIG_IMX_IRQSTEER,关闭所有其他厂商的驱动。这能减少约 20-30 KB 的内核映像。
4.3.2 软中断与 tasklet 配置
软中断(SoftIRQ)和 tasklet 是中断下半部的主要机制。以下选项控制其行为:
# 中断下半部相关选项
CONFIG_IRQ_WORK=y # 必须保留,用于 RCU 和 perf
CONFIG_TASKLET_STATISTICS=n # 关闭 tasklet 统计,减少开销
CONFIG_IRQ_TIME_ACCOUNTING=n # 关闭中断时间统计,节省约 2 KB
CONFIG_IRQ_DOMAIN_DEBUG=n # 关闭中断域调试
4.3.3 中断响应路径优化
中断响应路径上的每个分支都会增加延迟。以下配置可以精简路径:
- 关闭中断嵌套:
CONFIG_IRQ_PREFLOW_FASTEOI=n— 减少中断控制器交互次数。 - 使用线性中断域:
CONFIG_IRQ_DOMAIN_HIERARCHY=y但确保只注册必要的层级。 - 关闭稀疏中断:
CONFIG_SPARSE_IRQ=n— 对于固定中断数量的系统,使用线性表更高效。
4.3.4 中断子系统架构图
4.4 综合裁剪清单与验证
完成上述三个子系统的裁剪后,建议按以下清单进行验证:
- 功能验证:确认系统调用(如
sched_setscheduler、mmap、request_irq)行为符合预期。 - 性能基准:使用
cyclictest测量中断延迟,使用lmbench测量上下文切换时间。 - 内存占用:通过
size vmlinux和nm --size-sort vmlinux检查各子系统的代码段大小。 - 启动时间:使用
initcall_debug内核参数,观察各子系统初始化耗时。
推荐工具:使用
scripts/bloat-o-meter 脚本对比裁剪前后的内核映像,精确定位每个子系统的体积变化。