能量感知调度¶
1. 简介¶
能量感知调度 (EAS) 使调度器能够预测其决策对 CPU 功耗的影响。EAS 依赖于 CPU 的能量模型 (EM) 为每个任务选择一个节能 CPU,同时对吞吐量的影响最小。本文档旨在介绍 EAS 的工作原理、其背后的主要设计决策,以及详细介绍使其运行所需的条件。
在继续之前,请注意在撰写本文时
/!\ EAS does not support platforms with symmetric CPU topologies /!\
EAS 仅在异构 CPU 拓扑结构(例如 Arm big.LITTLE)上运行,因为这是通过调度节省能量的潜力最大的地方。
EAS 使用的实际 EM _不是_ 由调度器维护的,而是由一个专门的框架维护的。有关此框架及其提供的详细信息,请参阅其文档(请参阅 设备能量模型)。
2. 背景和术语¶
- 为了从一开始就明确
能量 = [焦耳] (像供电设备上的电池这样的资源)
功率 = 能量/时间 = [焦耳/秒] = [瓦特]
EAS 的目标是在完成工作的同时最大限度地减少能量。也就是说,我们要最大化
performance [inst/s]
--------------------
power [W]
这相当于最小化
energy [J]
-----------
instruction
同时仍然获得“良好”的性能。这本质上是调度器当前仅性能目标的替代优化目标。此替代方案考虑了两个目标:能源效率和性能。
引入 EM 的想法是允许调度器评估其决策的影响,而不是盲目地应用可能仅在某些平台上产生积极影响的节能技术。同时,EM 必须尽可能简单,以最大限度地减少调度器延迟的影响。
简而言之,EAS 改变了 CFS 任务分配给 CPU 的方式。当调度器决定任务应该在哪里运行时(在唤醒期间),EM 用于打破几个好的 CPU 候选者之间的僵局,并选择预计产生最佳能耗且不损害系统吞吐量的 CPU。EAS 所做的预测依赖于有关平台拓扑结构的特定知识元素,包括 CPU 的“容量”及其各自的能量成本。
3. 拓扑信息¶
EAS(以及调度器的其余部分)使用“容量”的概念来区分具有不同计算吞吐量的 CPU。CPU 的“容量”表示它在以最高频率运行时与系统中最强大的 CPU 相比可以吸收的工作量。容量值在 1024 范围内标准化,并且与每个实体负载跟踪 (PELT) 机制计算的任务和 CPU 的利用率信号相当。借助容量和利用率值,EAS 能够估计任务/CPU 的大小/忙碌程度,并在评估性能与能源的权衡时考虑到这一点。CPU 的容量是通过特定于架构的代码通过 arch_scale_cpu_capacity() 回调提供的。
EAS 使用的其余平台知识直接从能量模型 (EM) 框架读取。平台的 EM 由系统中每个“性能域”的功率成本表组成(有关性能域的更多详细信息,请参阅 设备能量模型)。
调度器在构建或重建调度域时管理对拓扑代码中 EM 对象的引用。对于每个根域 (rd),调度器维护一个单链表,其中包含与当前 rd->span 相交的所有性能域。列表中的每个节点都包含一个指向 struct em_perf_domain
的指针,该指针由 EM 框架提供。
列表附加到根域,以便处理独占 cpuset 配置。由于独占 cpusets 的边界不一定与性能域的边界匹配,因此不同根域的列表可能包含重复的元素。
- 示例 1。
让我们考虑一个包含 12 个 CPU 的平台,分为 3 个性能域(pd0、pd4 和 pd8),组织如下
CPUs: 0 1 2 3 4 5 6 7 8 9 10 11 PDs: |--pd0--|--pd4--|---pd8---| RDs: |----rd1----|-----rd2-----|
现在,假设用户空间决定使用两个独占 cpusets 来拆分系统,从而创建两个独立的根域,每个根域包含 6 个 CPU。上图中两个根域分别表示为 rd1 和 rd2。由于 pd4 与 rd1 和 rd2 相交,它将存在于附加到每个根域的链接列表“->pd”中
rd1->pd: pd0 -> pd4
rd2->pd: pd4 -> pd8
请注意,调度器将为 pd4 创建两个重复的列表节点(每个列表一个)。但是,两者都只保存一个指向 EM 框架的同一共享数据结构的指针。
由于对这些列表的访问可能与热插拔和其他事情同时发生,因此它们受 RCU 保护,就像调度器操作的其余拓扑结构一样。
当至少一个根域满足 EAS 启动的所有条件时,EAS 还维护一个静态键 (sched_energy_present)。这些条件在第 6 节中总结。
4. 能量感知任务放置¶
EAS 覆盖 CFS 任务唤醒平衡代码。它使用平台的 EM 和 PELT 信号,在唤醒平衡期间选择节能目标 CPU。启用 EAS 后,select_task_rq_fair() 调用 find_energy_efficient_cpu() 来执行放置决策。此函数在每个性能域中查找具有最高剩余容量(CPU 容量 - CPU 利用率)的 CPU,因为它是允许我们保持频率最低的 CPU。然后,该函数检查与将其保留在 prev_cpu(即任务在其上次激活中运行的 CPU)相比,将任务放置在那里是否可以节省能量。
find_energy_efficient_cpu() 使用 compute_energy() 来估计如果唤醒任务被迁移,系统将消耗的能量。compute_energy() 查看 CPU 的当前利用率情况,并对其进行调整以“模拟”任务迁移。EM 框架提供 em_pd_energy() API,该 API 计算给定利用率情况下每个性能域的预期能耗。
下面详细介绍一个能量优化的任务放置决策示例。
- 示例 2。
让我们考虑一个(虚构的)平台,它具有 2 个由两个 CPU 组成的独立性能域。CPU0 和 CPU1 是小 CPU;CPU2 和 CPU3 是大 CPU。
调度器必须决定将 util_avg = 200 且 prev_cpu = 0 的任务 P 放置在哪里。
CPU 的当前利用率情况如下图所示。CPU 0-3 的 util_avg 分别为 400、100、600 和 500。每个性能域有三个操作性能点 (OPP)。能量模型表中列出了与每个 OPP 关联的 CPU 容量和功率成本。P 的 util_avg 在下图中显示为“PP”
CPU util. 1024 - - - - - - - Energy Model +-----------+-------------+ | Little | Big | 768 ============= +-----+-----+------+------+ | Cap | Pwr | Cap | Pwr | +-----+-----+------+------+ 512 =========== - ##- - - - - | 170 | 50 | 512 | 400 | ## ## | 341 | 150 | 768 | 800 | 341 -PP - - - - ## ## | 512 | 300 | 1024 | 1700 | PP ## ## +-----+-----+------+------+ 170 -## - - - - ## ## ## ## ## ## ------------ ------------- CPU0 CPU1 CPU2 CPU3 Current OPP: ===== Other OPP: - - - util_avg (100 each): ##
find_energy_efficient_cpu() 首先查找两个性能域中剩余容量最大的 CPU。在此示例中,为 CPU1 和 CPU3。然后,它将估计如果 P 放置在其中任何一个上,系统的能量,并检查与将 P 保留在 CPU0 上相比是否可以节省一些能量。EAS 假设 OPP 遵循利用率(这与 schedutil CPUFreq 调速器的行为一致,有关此主题的更多详细信息,请参阅第 6 节)。
情况 1. P 迁移到 CPU1:
1024 - - - - - - - Energy calculation: 768 ============= * CPU0: 200 / 341 * 150 = 88 * CPU1: 300 / 341 * 150 = 131 * CPU2: 600 / 768 * 800 = 625 512 - - - - - - - ##- - - - - * CPU3: 500 / 768 * 800 = 520 ## ## => total_energy = 1364 341 =========== ## ## PP ## ## 170 -## - - PP- ## ## ## ## ## ## ------------ ------------- CPU0 CPU1 CPU2 CPU3
情况 2. P 迁移到 CPU3:
1024 - - - - - - - Energy calculation: 768 ============= * CPU0: 200 / 341 * 150 = 88 * CPU1: 100 / 341 * 150 = 43 PP * CPU2: 600 / 768 * 800 = 625 512 - - - - - - - ##- - -PP - * CPU3: 700 / 768 * 800 = 729 ## ## => total_energy = 1485 341 =========== ## ## ## ## 170 -## - - - - ## ## ## ## ## ## ------------ ------------- CPU0 CPU1 CPU2 CPU3
情况 3. P 保留在 prev_cpu / CPU 0 上:
1024 - - - - - - - Energy calculation: 768 ============= * CPU0: 400 / 512 * 300 = 234 * CPU1: 100 / 512 * 300 = 58 * CPU2: 600 / 768 * 800 = 625 512 =========== - ##- - - - - * CPU3: 500 / 768 * 800 = 520 ## ## => total_energy = 1437 341 -PP - - - - ## ## PP ## ## 170 -## - - - - ## ## ## ## ## ## ------------ ------------- CPU0 CPU1 CPU2 CPU3
从这些计算中,情况 1 的总能量最低。因此,从能效的角度来看,CPU 1 是最佳候选者。
大 CPU 通常比小 CPU 更耗电,因此主要在任务不适合小 CPU 时使用。但是,小 CPU 并不总是比大 CPU 更节能。例如,对于某些系统,小 CPU 的高 OPP 可能比大 CPU 的最低 OPP 效率低。因此,如果小 CPU 在特定时间点碰巧有足够的利用率,那么此时唤醒的小任务最好在大 CPU 上执行,以节省能量,即使它适合在小 CPU 上执行也是如此。
即使大 CPU 的所有 OPP 的能效都低于小 CPU 的 OPP,在特定条件下,使用大 CPU 执行小任务可能仍然可以节省能量。实际上,将任务放置在小 CPU 上可能会导致提高整个性能域的 OPP,这将增加已经在那里运行的任务的成本。如果唤醒任务放置在大 CPU 上,则它自身的执行成本可能高于在小 CPU 上运行的成本,但它不会影响小 CPU 的其他任务,这些任务将继续在较低的 OPP 下运行。因此,当考虑 CPU 消耗的总能量时,在大核心上运行该一项任务的额外成本可能小于为小 CPU 的所有其他任务提高 OPP 的成本。
上述示例在不知道系统所有 CPU 在不同 OPP 下运行的成本的情况下,几乎不可能以通用方式在所有平台上正确实现。得益于其基于 EM 的设计,EAS 应该可以轻松正确地应对这些情况。但是,为了确保在高利用率场景下对吞吐量的影响最小,EAS 还实现了另一种称为“过度利用”的机制。
5. 过度利用¶
从一般角度来看,EAS 最能发挥作用的用例是那些涉及轻/中 CPU 利用率的用例。每当运行长时间的 CPU 密集型任务时,它们将需要所有可用的 CPU 容量,并且调度程序在不严重损害吞吐量的情况下,无法做太多工作来节省能源。为了避免 EAS 损害性能,只要 CPU 的使用率超过其计算能力的 80%,就会被标记为“过度利用”。只要根域中没有 CPU 被过度利用,负载均衡就会被禁用,并且 EAS 会覆盖唤醒均衡代码。如果这样做不会损害吞吐量,EAS 可能会比其他 CPU 更多地加载系统中最节能的 CPU。因此,负载均衡器被禁用,以防止它破坏 EAS 找到的节能任务放置。当系统没有被过度利用时,这样做是安全的,因为低于 80% 的临界点意味着
所有 CPU 上都有一些空闲时间,因此 EAS 使用的利用率信号很可能准确地表示系统中各个任务的“大小”;
所有任务都应该已经获得了足够的 CPU 容量,而不管它们的 nice 值如何;
由于有空闲容量,所有任务都必须定期阻塞/休眠,并且在唤醒时进行均衡就足够了。
只要一个 CPU 超过 80% 的临界点,上述三个假设中至少有一个就不正确了。在这种情况下,整个根域都会被标记为“过度利用”,EAS 被禁用,并且负载均衡器被重新启用。通过这样做,调度程序在 CPU 密集型条件下回退到基于负载的唤醒和负载均衡算法。这可以更好地尊重任务的 nice 值。
由于过度利用的概念很大程度上依赖于检测系统中是否存在空闲时间,因此必须考虑由较高(高于 CFS)调度类(以及 IRQ)“占用”的 CPU 容量。因此,对过度利用的检测不仅考虑 CFS 任务使用的容量,还考虑其他调度类和 IRQ 使用的容量。
6. EAS 的依赖关系和要求¶
能源感知调度取决于系统的 CPU 是否具有特定的硬件属性以及是否启用了内核的其他功能。本节列出了这些依赖关系,并提供了关于如何满足这些依赖关系的提示。
6.1 - 非对称 CPU 拓扑¶
正如引言中提到的,EAS 目前仅在具有非对称 CPU 拓扑的平台上受支持。在构建调度域时,通过查找是否存在 SD_ASYM_CPUCAPACITY_FULL 标志来在运行时检查此要求。
有关在 sched_domain 层级结构中设置此标志需要满足的要求,请参阅 容量感知调度。
请注意,EAS 从根本上与 SMP 不兼容,但尚未在 SMP 平台上观察到显著的节省。如果事实证明并非如此,此限制将来可能会被修改。
6.2 - 能量模型存在¶
EAS 使用平台的 EM 来估计调度决策对能量的影响。因此,您的平台必须向 EM 框架提供功率成本表,才能启动 EAS。为此,请参阅 设备能量模型 中独立 EM 框架的文档。
另请注意,在 EM 注册后需要重新构建调度域,才能启动 EAS。
EAS 使用 EM 对能源使用情况进行预测决策,因此在检查任务放置的可能选项时,它更关注差异。对于 EAS,EM 功率值是以毫瓦表示还是以“抽象比例”表示并不重要。
6.3 - 能量模型复杂性¶
EAS 不对 PD/OPP/CPU 的数量施加任何复杂性限制,但将 CPU 的数量限制为 EM_MAX_NUM_CPUS,以防止在能量估算期间发生溢出。
6.4 - Schedutil governor¶
EAS 尝试预测 CPU 在不久的将来将以哪个 OPP 运行,以估计它们的能量消耗。为此,假设 CPU 的 OPP 跟随它们的利用率。
尽管实际上很难对这一假设的准确性提供硬性保证(例如,因为硬件可能不会按照指示执行),但 schedutil 与其他 CPUFreq governor 相比,至少会 _请求_ 使用利用率信号计算的频率。因此,与 EAS 一起使用的唯一明智的 governor 是 schedutil,因为它是唯一在频率请求和能量预测之间提供一定程度一致性的 governor。
不支持将 EAS 与 schedutil 以外的任何其他 governor 一起使用。
6.5 - 尺度不变的利用率信号¶
为了在所有 CPU 和所有性能状态下进行准确的预测,EAS 需要频率不变和 CPU 不变的 PELT 信号。可以使用架构定义的 arch_scale{cpu,freq}_capacity() 回调来获得这些信号。
不支持在未实现这两个回调的平台上使用 EAS。
6.6 - 多线程 (SMT)¶
EAS 的当前形式不了解 SMT,无法利用多线程硬件来节省能源。EAS 将线程视为独立的 CPU,这实际上可能会对性能和能源产生反作用。
不支持 SMT 上的 EAS。