3. HMP调度器详解:HMP与big.LITTLE、CPU迁移与负载均衡、调度域与调度组

好,咱们今天聊HMP调度器。说实话,这个知识点是手机性能调优里最绕不开的一块。你想想看,手机SoC里既有大核又有小核,怎么让它们干活不打架?这就是HMP要解决的核心问题。

3.1 HMP与big.LITTLE:异构多核的“翻译官”

big.LITTLE架构,说白了就是“大核干重活,小核干轻活”。大核性能强但功耗高,小核省电但性能弱。那问题来了——系统怎么知道哪个任务该放哪个核上?

HMP(Heterogeneous Multi-Processing)就是干这个的。它不是一个具体的调度算法,而是一套框架。我习惯把它理解成“异构多核的翻译官”——它把不同性能的CPU核心统一管理起来,让操作系统觉得“嗯,这些核虽然长得不一样,但都能干活”。

核心要点:HMP允许任务在大小核之间动态迁移,而不是像早期的“集群切换”那样,要么全用大核,要么全用小核。

我在项目中遇到过一个问题:某款手机刷微博时突然卡顿。查了半天,发现是HMP的迁移阈值设得太保守了。UI线程明明需要大核性能,系统却迟迟不肯把它从小核迁到大核上。嗯,这就是典型的“迁移策略没调好”。

3.2 CPU迁移与负载均衡:任务是怎么“搬家”的?

CPU迁移,就是任务从一个核搬到另一个核上。听起来简单,但背后门道很多。

我举个例子:你正在打游戏,一个渲染线程跑在小核上。突然来了个大招,计算量暴增。这时候调度器会怎么做?

  1. 负载检测:调度器每隔一段时间(通常是1ms或4ms)检查每个CPU的利用率。
  2. 过载判断:如果小核利用率超过某个阈值(比如80%),就认为它“扛不住了”。
  3. 迁移决策:找一个空闲的大核,把任务迁过去。
  4. 上下文切换:保存当前任务的寄存器状态,恢复到大核上继续跑。

这里有个坑——我曾经调试过一个场景,任务频繁在小核和大核之间来回迁移。每次迁移都有开销(保存/恢复上下文、缓存失效),结果性能反而下降了。这就是所谓的“迁移抖动”。

避坑指南:我曾经在某个项目中,把迁移阈值设得太灵敏。结果任务像“打乒乓球”一样在大小核之间弹来弹去。后来加了迁移延迟(migration delay),让任务在一个核上至少待够5ms才允许迁移,问题就解决了。

负载均衡呢?它和迁移是两码事。负载均衡是“全局视角”的——调度器会看所有CPU的负载情况,尽量让每个核的利用率差不多。比如大核负载80%,小核负载20%,调度器就会把大核上的一些任务挪到小核上。

但注意,负载均衡不是万能的。你想想看,如果所有任务都是计算密集型的,小核根本跑不动,硬塞过去反而更慢。所以HMP的负载均衡算法里,有个“任务类型识别”的机制——它会判断这个任务是“CPU密集型”还是“IO密集型”,再决定往哪放。

3.3 调度域与调度组:调度器的“地图”和“朋友圈”

调度域(Scheduling Domain)和调度组(Scheduling Group),这两个概念有点抽象。我换个说法——调度域就是调度器的“地图”,调度组就是“朋友圈”。

咱们先看调度域。在big.LITTLE架构里,CPU不是平级的。比如一个SoC有4个大核+4个小核,它们会分成两个调度域:

  • MC域(Multi-Core):包含所有CPU核心,用于跨集群的负载均衡。
  • DIE域:通常对应一个CPU集群(比如4个大核或4个小核),用于集群内部的负载均衡。

调度器会先看DIE域,如果搞不定(比如所有大核都满了),再往MC域看,尝试把任务迁移到小核上。

我画了一张图,帮你理解这个层级关系:

调度域与调度组层级结构 根调度域 (MC域) DIE域 (大核集群) DIE域 (小核集群) 调度组 (CPU0) 调度组 (CPU1) 调度组 (CPU2) 调度组 (CPU3) 每个调度组包含一个或多个CPU核心 调度器先在DIE域内做负载均衡 如果搞不定,再通过MC域跨集群迁移

调度组呢?它是调度域里的基本单元。每个调度组包含一个或多个CPU核心。调度器在做负载均衡时,是以调度组为单位的——它会比较不同调度组的负载,然后把任务从负载高的组迁移到负载低的组。

举个例子:大核集群里有4个CPU,它们属于同一个调度组。小核集群也是。调度器会先看大核组内部,如果某个大核负载高了,就把任务挪到另一个大核上。如果所有大核都满了,再看小核组,尝试跨组迁移。

个人经验:我建议你在调试调度问题时,先看 /proc/schedstat/sys/kernel/debug/sched/domains。这两个文件能告诉你当前调度域的层级结构和负载情况。我曾经靠这个定位过一个“大核利用率不均”的问题——发现是某个调度组的负载均衡周期设得太长了。

3.4 实战中的HMP调优要点

说了这么多理论,咱们来点实际的。如果你要调优HMP调度,重点关注这几个参数:

参数 位置 作用 我的建议值
up_threshold cpufreq governor 决定何时升频/迁移到大核 80-85%(太低了容易频繁迁移)
down_threshold cpufreq governor 决定何时降频/迁移到小核 50-60%(太高了容易降频过早)
migration_delay 调度器参数 任务迁移的最小间隔 5-10ms(防止迁移抖动)
load_balance_interval 调度域参数 负载均衡的检查周期 4-8ms(太短了CPU开销大)

嗯,这里要注意——这些参数不是通用的。不同SoC、不同场景,最优值都不一样。我习惯的做法是:先用默认值跑一遍,抓trace看迁移频率和负载分布,再根据实际情况微调。

最后说一句,HMP调度器的设计思路,其实和现代操作系统的很多思想是相通的——分层管理、负载感知、动态迁移。你理解了HMP,再看其他调度器(比如EAS),会发现很多相似之处。

总结一下:HMP的核心就是“让合适的任务跑在合适的核上”。调度域和调度组是它的组织架构,CPU迁移和负载均衡是它的执行手段。调优的关键,是找到那个“迁移频率”和“性能功耗”的平衡点。


专注资料整理