3. Android 调度器演进:从CFS到HMP、EAS的引入

Android 内核调度器的演进,本质上是为应对移动设备独特的功耗与性能平衡挑战。从桌面 Linux 的完全公平调度器(CFS)开始,到针对大小核架构的 HMP 调度器,再到引入能量感知调度(EAS),每一步都深刻影响着系统的响应速度与续航表现。本章将梳理这一演进路径,并剖析各阶段的核心机制与性能权衡。

3.1 起点:CFS 在移动端的局限

CFS(Completely Fair Scheduler)是 Linux 内核默认调度器,其核心思想是使用红黑树维护任务,保证每个任务获得公平的 CPU 时间片。然而,CFS 在设计之初主要面向服务器和桌面环境,在移动端暴露出两个关键问题:

  • 功耗盲区:CFS 仅关注 CPU 时间分配的公平性,完全不考虑不同 CPU 核心的功耗差异。在大小核(big.LITTLE)架构上,它可能将后台任务调度到大核上,造成不必要的功耗浪费。
  • 迁移延迟:CFS 的任务迁移决策基于负载均衡,但缺乏对核心类型(大核/小核)的感知,导致任务在大小核之间频繁迁移,增加缓存失效和迁移开销。
关键指标:在 CFS 调度下,Android 设备后台应用的平均功耗比理想值高出 15%-25%,且 UI 线程的调度延迟(sched_latency)波动较大,直接影响滑动流畅度。

3.2 HMP 调度器:异构多核的初步适配

HMP(Heterogeneous Multi-Processing)调度器是 ARM 为 big.LITTLE 架构设计的调度方案。它不再将 CPU 视为同质资源,而是引入 CPU 容量(capacity) 的概念,将大核与小核区分对待。

3.2.1 HMP 的核心机制

  • CPU 容量模型:每个 CPU 核心被赋予一个容量值(通常大核为 1024,小核为 400-600),调度器根据任务负载与 CPU 容量的匹配度进行调度。
  • 负载跟踪:使用 PELT(Per-Entity Load Tracking)跟踪每个任务的运行时间,计算其平均负载。
  • 迁移决策:当任务负载超过小核容量阈值时,将其迁移到大核;反之则迁移回小核。
HMP 的典型配置:在 Android 内核中,HMP 通过 /sys/kernel/hmp/ 下的参数进行调优,例如 down_threshold(下迁阈值)和 up_threshold(上迁阈值),控制任务在大小核之间的迁移时机。

3.2.2 HMP 的不足

HMP 虽然解决了大小核识别问题,但其调度决策仍然基于 负载阈值,而非真正的功耗模型。这导致以下问题:

问题 表现 影响
阈值震荡 任务负载在阈值附近波动时,频繁在大小核间迁移 增加迁移开销,降低性能
功耗估算粗糙 仅通过 CPU 频率和核心类型估算功耗,未考虑电压、温度等因素 功耗优化不精确
缺乏全局视角 每个 CPU 独立决策,未考虑整个系统的功耗预算 多任务场景下功耗失控

3.2.3 HMP 调度流程 SVG

HMP 调度器任务迁移流程 任务队列 PELT 负载跟踪 负载 > up_threshold? 或 < down_threshold? 大核 (big) 小核 (LITTLE) 负载高 → 上迁 负载低 → 下迁 说明 HMP 通过固定阈值 决定任务迁移方向

3.3 EAS 调度器:能量感知的调度革命

EAS(Energy Aware Scheduling)是继 HMP 之后的重大演进,它从 Linux 4.x 开始合入主线,并在 Android 内核中得到广泛采用。EAS 的核心思想是:在保证性能满足需求的前提下,选择能耗最低的 CPU 核心执行任务。

3.3.1 EAS 的三大支柱

组件 功能 关键数据
CPU 容量模型 量化每个 CPU 核心的最大计算能力 通过 /sys/devices/system/cpu/cpu*/cpu_capacity 暴露
能量模型(EM) 提供每个 CPU 在不同频率下的功耗数据 通过 /sys/devices/system/cpu/cpu*/energy_model 暴露
负载跟踪(PELT) 精确跟踪每个任务的 CPU 利用率 以毫秒级粒度更新,反映任务真实需求

3.3.2 EAS 的调度决策过程

  1. 任务唤醒:当任务被唤醒时,EAS 遍历所有可用的 CPU 核心。
  2. 性能预估:根据任务的 PELT 负载,预估将其调度到每个核心上所需的 OPP(Operating Performance Point,即频率/电压组合)。
  3. 能耗计算:利用能量模型,计算每个候选核心在对应 OPP 下的预估功耗。
  4. 最优选择:选择满足性能需求且能耗最低的核心。
注意:EAS 的能耗计算依赖于平台提供的能量模型数据。如果能量模型不准确(例如未考虑漏电流或温度效应),EAS 的调度决策可能反而导致功耗增加。因此,OEM 厂商需要根据实际硬件校准能量模型。

3.3.3 EAS 调度决策 SVG

EAS 能量感知调度决策流程 任务唤醒 遍历候选 CPU 性能预估 (PELT 负载 → OPP) 能耗计算 (能量模型 → 功耗) 最优选择 (性能满足 + 能耗最低) 调度执行 EAS 核心优势:在任务唤醒时,同时考虑性能需求和能耗成本,做出全局最优决策 相比 HMP 的固定阈值,EAS 的决策更加精细和动态

3.4 CFS、HMP、EAS 对比总结

特性 CFS HMP EAS
核心架构 同质多核 异构多核(大小核) 异构多核 + 能量模型
调度依据 时间片公平性 负载阈值 性能 + 能耗联合优化
功耗感知 无 间接(通过核心类型) 直接(通过能量模型)
迁移决策 负载均衡 固定阈值 动态能耗计算
Android 引入版本 Android 早期版本 Android 5.x - 8.x Android 9+(主线内核 4.x+)
典型功耗优化 无 10%-15% 20%-30%

3.5 实践建议:EAS 调优方向

在 Android 系统性能优化中,针对 EAS 的调优通常关注以下方面:

  • 能量模型校准:确保 /sys/devices/system/cpu/cpu*/energy_model 中的数据与实际硬件功耗曲线匹配。可以使用 powercap 或 perf 工具进行验证。
  • 负载跟踪参数:调整 PELT 的半衰期(kernel.sched_pelt_period),在响应速度和稳定性之间取得平衡。
  • 调度域配置:通过 /proc/sys/kernel/sched_domain/ 调整调度域的层级和标志位,控制任务迁移的范围和频率。
  • 关键任务标记:使用 sched_setattr() 系统调用为 UI 线程设置 SCHED_FLAG_UTIL_CLAMP_MIN,确保其始终获得足够的 CPU 资源。
性能分析工具:使用 schedtop、trace-cmd 和 kernel.sched_schedstats=1 可以实时观察 EAS 的调度决策,识别任务迁移和能耗异常。