Energy Aware Scheduling(EAS, 能量感知的调度)
Linux 5.15 EAS内核文档翻译
0. 引用
Documentation/scheduler/sched-energy.txt
1. 介绍 (Introduction)
EAS给出了调度器预测CPU的决策对能耗的影响。EAS依赖Energy Model (EM)模型为每个任务选择节能的CPU,从而使得对吞吐量影响最小。本文介绍EAS是如何工作的,其设计初衷是什么等内容。
注意:EAS不支持具有对称CPU拓扑的平台
EAS仅在异构CPU上运行,如Arm big.LITTLE,这是通过调度节省能量的实质。
EAS使用的EM模型不是由调度器维护的,而是由专用框架维护的。有关该框架及其提供的详细信息,请参阅其文档(请参阅documentation/power/energy-model.rst)。
2. 背景和术语 (Background and Terminology)
- 能量(energy):单位[joule],就类似于电源设备上的电池。
- 功率/功耗(power):能量/时间,单位为[joule/second]=[watt]
EAS目的是使得能量最小化,且使得任务完成,即我们想最大化(inst指的是指令数,s是秒,W是瓦特):
p
e
r
f
o
r
m
a
n
c
e
[
i
n
s
t
/
s
]
p
o
w
e
r
[
W
]
\frac{\mathrm{performance} \left[ \mathrm{inst}/\mathrm{s} \right]}{\mathrm{power} \left[ \mathrm{W} \right]}
power[W]performance[inst/s]
这等价于最小化下式且维持“好”的性能:
e
n
e
r
g
y
[
J
]
i
n
s
t
r
u
c
t
i
o
n
\frac{\mathrm{energy} \left[ \mathrm{J} \right]}{\mathrm{instruction}}
instructionenergy[J]
引入EM的初衷是允许调度器评估其决策造成的影响,而不是盲目地应用可能只在部分平台上的节能技术。同时,EM必须尽可能简单,以最大限度地减少调度器的延迟。
简而言之,EAS改变了将CFS(Completely Fair Scheduler)任务分配给CPU的方式。当调度程序决定任务应该在哪个CPU运行时,EM用于打破多个CPU候选项之间的平衡,并选择最佳能耗预期而不损害系统吞吐量的那个。EAS所做的预测依赖于平台拓扑的特定知识,包括CPU的’capacity’和它们各自的能源成本(energy costs)。
3. 拓扑信息 (Topology information)
EAS使用’Capacity’的概念来表征CPU的计算吞吐量。CPU的’Capacity’表示其在以最高频率运行时与系统中最强的CPU相比可以处理的工作量。'Capacity’值在1024范围内进行了标准化,并可以与由Per-Entity Load Tracking(PELT)机制计算的任务和CPU的利用率信号进行比较。
借助’Capacity’和利用率值,EAS能够对任务和CPU的能力和繁忙程度进行估计,并在评估性能与能源权衡时考虑这一因素。CPU的’capacity’是通过特定于架构的代码通过arch_scale_cpu_capacity()
回调提供的。
EAS使用的其余知识(可以理解为参数)直接从EM框架中读取。平台的EM由系统中每个“性能域”(请参阅Documentation/power/energy-model.rst了解有关性能域的更多详细信息)的功耗成本表组成。
调度程序在构建/重建调度域时,在拓扑代码中管理EM对象的引用。对于每个根域(root domain, rd),调度程序维护一个单链表,其中包含与当前rd->span
相交的所有性能域。列表中的每个节点都包含一个指向由EM框架提供的em_perf_domain
结构的指针。
这些链表附加到根域以处理独占的cpuset配置。由于独占cpuset的边界不一定与性能域的边界相匹配,不同根域的列表可能包含重复的元素。
案例1:假设有一个包含12个CPU的平台,将其分成三个性能域(pd0,pd4和pd8),如下组织:
CPUs: 0 1 2 3 4 5 6 7 8 9 10 11
PDs: |--pd0--|--pd4--|---pd8---|
RDs: |----rd1----|-----rd2-----|
现在,假设用户空间决定使用两个独占cpuset来分割系统,因此创建了两个独立的根域,每个根域包含6个CPU。上面的图中将这两个根域分别表示为rd1和rd2。由于pd4与rd1和rd2都有交集,因此它将出现在附加到它们各自的rd->pd
链表中:
- rd1->pd: pd0 -> pd4
- rd2->pd: pd4 -> pd8
调度程序将为pd4创建两个重复的链表节点。然而,这两个节点指向EM框架的同一个共享数据结构的指针。
由于对这些列表的访问可能与热插拔和其他操作并发发生,因此它们受到RCU(Read-Copy-Update,读复制更新)的保护,就像调度程序操作的其他拓扑结构一样。
EAS还维护一个静态键(sched_energy_present),当至少有一个根域满足EAS启动的所有条件时,它会被启用。这些条件在第6节中进行了总结。
4. 能量感知的任务分配 (Energy-Aware task placement)
EAS覆写(override)了CFS任务唤醒平衡代码。它使用平台的EM以及PELT信号在唤醒平衡期间选择能源效率最高的目标CPU。
当启用EAS时,select_task_rq_fair()
调用find_energy_efficient_cpu()
来进行任务分配决策。该函数在每个性能域中查找空闲Capacity最大的CPU(CPU capacity - CPU utilization,即容量减去已使用量),因为这将使我们能够保持频率最低。然后,将其保留在prev_cpu
上相比,检查将任务放置在该CPU上是否可以节省能源。prev_cpu是此任务之前所分配的的CPU。
find_energy_efficient_cpu()
使用compute_energy()
来估算唤醒并在cpu之间迁移任务将消耗多少能源。compute_energy()
会查看当前CPU的利用率情况,并“模拟”任务迁移。EM框架提供了em_pd_energy()
的API,该API计算了在给定的利用率情况下,每个性能域的预期能源消耗。这有助于评估将任务迁移到不同CPU上是否会节省能源。一个能量优化的任务分配决策如下:
案例2:考虑一个带有2个独立性能域的平台,每个性能域包含2个CPU核心,CPU0和CPU1是小核,CPU2和CPU3是大核。
调度器需要决策任务P,任务的利用率为util_avg=200,任务上一个cpu为prev_cpu=0。
CPU的当前利用率情况如下图所示。CPU 0-3的util_avg分别为400、100、600和500。每个性能域具有三个操作性能点(Operating Performance Points, OPPs)。与每个OPP相关的CPU容量和功耗成本列在Energy Model表中。任务P的util_avg如下图所示,表示为’PP’:
CPU使用率
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放置在其中任何一个CPU上,系统的能源消耗,并检查与将P保留在CPU0上相比是否能够节省一些能源。EAS假设OPPs按照利用率变化(这与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:任务迁移到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:任务仍旧停留在CPU0上
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有最低的总能量,所以CPU1是最佳的候选者。
大核通常比小核更耗电,因此主要处理小核难以适合的任务。然而,并不总是小核比大核更节能。例如,某些系统小核的最高的OPPs可能不如大核的最低OPPs节能。因此,如果小核在某时刻利用率过高,那么此时此任务可能更适合在大核上执行,以节省能源,即使它本来可以在小核上运行。
即使大核的所有OPPs都不如小核的OPPs节能,在特定条件下,将小型任务其放置在大核上可能仍然可以节省能源。这是因为,将任务放置在小核上可能会导致提高整个性能域的OPP,从而增加已在其中运行的任务的成本。如果将任务放置在大核上,其自身的执行成本可能较高,但它不会影响小核上的其他任务,后者将继续以较低的OPP运行。因此,在考虑CPU总能源消耗时,将一个任务放置在大核上的额外成本可能小于将小核上的所有其他任务的OPP提高的成本。这种情况下,能源感知的任务放置可以考虑将小型任务分配给大核,以实现更好的能源效率。
在不知道系统所有CPU在不同OPP下运行的成本的情况下,要以通用方式正确处理并适用于所有平台几乎是不可能的。基于EM的设计,EAS应该能够正确处理它们而不会出现太多问题。然而,为了确保在高利用率场景下对吞吐量的最小影响,EAS还实现了另一种称为“过度利用(over-utilization)”的机制。
过度利用 (Over-utilization)
从一般的角度来看,EAS适用于轻/中度CPU利用率的情况。当运行长时间的CPU密集型任务时,它们将需要所有可用的CPU,而调度程序很难在不严重损害吞吐量的情况下节省能源。为了避免在EAS中影响性能,只要CPU的利用率超过80%,就会将其标记为“Over-utilization”。只要在根域中没有CPU被过度利用,负载平衡就会被禁用,EAS将覆盖唤醒平衡代码。如果不会损害吞吐量,EAS很可能会加载系统中最节能的CPU。当系统未过度利用(<80%)时,禁用负载平衡是安全的,下面是原因:
- 所有CPU都有一些空闲时间,因此EAS使用的利用率信号很可能准确表示系统中各个任务的“大小”。
- 所有任务应该已经获得足够的CPU capacity,而不考虑它们的优先级(nice values)。
- 由于有空余的capacity,所有任务都必须定期阻塞/休眠,因此在唤醒时进行平衡已经足够。
一旦一个CPU的利用率超过80%的临界点,上面列出的三个假设中至少一个将不成立。在这种情况下,将为整个根域设置“Over-utilization”的标志,禁用EAS,并重新启用负载平衡器。通过这样做,调度程序会回到基于负载的算法,用于CPU密集型条件下的唤醒和负载平衡。这有助于更好地尊重任务的nice值(优先级)。这个切换策略能够更好地适应不同的工作负载,并在需要时提供更好的性能。
由于判断Over-utilization的概念在很大程度上依赖于系统的空闲时间,因此必须考虑被更高(高于CFS)调度类(以及IRQ)“窃取”的CPU capacity。因此,Over-utilization的检测不仅考虑了由CFS任务使用的capacity,还考虑了其他调度类和IRQ使用的capacity。这确保了在考虑过度利用时,系统中各种任务和中断的影响都被纳入考虑,从而更准确地判断是否存在Over-utilization的情况。
6. EAS的依赖(Dependencies and requirements for EAS)
能源感知调度依赖于系统的CPU具有特定的硬件属性,并且依赖于内核的其他功能已启用。以下是这些依赖关系的列表,并提供了如何满足它们的提示。
6.1. 非对称CPU拓扑(Asymmetric CPU topology)
正如在介绍中提到的,目前EAS仅支持具有不对称CPU拓扑的平台。这一要求在运行时通过查看调度域在构建时是否存在SD_ASYM_CPUCAPACITY_FULL标志来进行检查。
请参阅Documentation/scheduler/sched-capacity.rst,了解此标志在sched_domain层次结构中设置的要求。
需要注意的是,EAS与SMP(对称多处理器)原则上并不冲突,但目前尚未观察到在SMP平台上能够实现显著的节省。如果未来经过验证,这一限制可能会被修改。
6.2. 能量模型(Energy Model presence)
EAS使用平台的EM来估算调度决策对能源消耗的影响。因此,您的平台必须向EM框架提供功耗成本表,以启动EAS。要执行此操作,请参考独立EM框架的文档,位于Documentation/power/energy-model.rst中。
还请注意,在注册EM后,需要重新构建调度域以启动EAS。
EAS使用EM进行能源使用的预测决策,因此在检查可能的任务放置选项时更关注差异。对于EAS来说,不管EM功耗值是以毫瓦还是以“抽象刻度”表示,都不重要。
6.3. 能量模型复杂度(Energy Model complexity)
任务唤醒路径对延迟非常敏感。当平台的能源模型过于复杂(拥有太多的CPU、性能域、性能状态等等),在唤醒路径中使用它的成本可能会变得无法接受。能源感知的唤醒算法的复杂性由以下公式表示:
C
=
N
d
∗
(
N
c
+
N
s
)
C = N_d * (N_c + N_s)
C=Nd∗(Nc+Ns)
其中:
N
d
N_d
Nd 是性能域的数量;
N
c
N_c
Nc 是CPU的数量;
N
s
N_s
Ns 是总的OPP数量(例如,对于具有4个OPP的两个性能域,
N
s
=
8
N_s = 8
Ns=8)。
在构建调度域时,会在根域级别上进行复杂性检查。如果在某个根域上的复杂性
C
C
C超过了完全任意的EM_MAX_COMPLEXITY
阈值(在撰写本文时为2048),那么EAS将不会在该根域上启动。
如果您确实希望使用EAS,但您的平台的能源模型的复杂性太高,以至于无法在单个根域上使用,那么您只有两种可能的选择:
-
将系统分成单独的、较小的根域,使用独占的cpusets,并在每个根域上启用EAS。这个选项具有开箱即用的好处,但缺点是它会阻止根域之间的负载平衡,可能导致整体系统不平衡。
-
提交补丁以减少EAS唤醒算法的复杂性,从而使其能够在合理的时间内处理更大的能源模型。这个选项需要更多的开发工作,但可以改善EAS在复杂环境下的性能,并使其适应更大的能源模型。
6.4. Schedutil governor
EAS尝试预测CPU将在不久的将来以哪个OPP(Operating Performance Point)运行,以估算其能源消耗。为了实现这一目标,EAS假设CPU的OPPs会根据其利用率进行调整。
尽管在实际情况下很难提供关于这一假设准确性的证据(因为硬件可能不会按照期望的方式运行),与其他CPUFreq调度器相比,schedutil至少会使用利用率的信号(utilization signals)来计算频率。因此,与EAS一起使用的唯一合理的调度器是schedutil,因为它是唯一一个在频率请求和能源预测之间具有一致性的调度器。
使用EAS与除schedutil以外的任何其他调度器都不受支持。因此,如果要使用EAS来进行能源感知的任务调度,必须使用schedutil作为CPUFreq调度器。
6.5. 尺度不变的利用率信号(Scale-invariant utilization signals)
为了实现跨 CPU 和所有性能状态的准确预测,EAS 需要频率不变且 CPU 不变的 PELT 信号。 这些可以使用架构定义的 arch_scale{cpu,freq}_capacity()
回调来获得。
不支持在未实现这两个回调的平台上使用 EAS。
6.6. 多线程(Multithreading, SMT)
当前版本的EAS(Energy-Aware Scheduling)不支持多线程(SMT),它无法利用多线程硬件来节省能源。EAS将线程视为独立的CPU,这实际上可能对性能和能源效率都不利。
因此,EAS在多线程(SMT)上不受支持。这意味着如果系统具有多线程硬件,EAS不会充分利用多线程技术来提高性能或能源效率。在这种情况下,可能需要考虑其他调度策略或优化方法来更好地利用多线程硬件。