RFC-0250:电源拓扑 | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 介绍系统电源管理要使用的相互依赖状态管理模型。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2024-03-09 |
审核日期(年-月-日) | 2024-06-03 |
摘要
系统电源管理的一个关键问题是支持各种系统元素(我们用以下术语来简单地指代具有状态的事物,包括硬件和软件)向不同的状态转换,同时妥善管理这些状态之间的相互依赖关系。此提案指定了一种名为 Fuchsia Power Topology 的模型,可用于解决此问题,同时为归因和可观察性方面的相关问题提供了解决方案。本工作重点是建立一个包含严格定义的术语的概念框架;未来的 RFC 将讨论与实现更密切相关的设计。
设计初衷
状态管理问题
此提案源于需要在 Fuchsia 中支持系统暂停/恢复操作,如 RFC 230 中所述。
系统挂起的主要任务是确保在 CPU 停止执行指令之前,所有硬件元素都已进入适当的低功耗状态。从表面上看,这似乎是一个深层级别的依赖项管理问题:硬件元素的“活动”状态取决于 CPU 的活动状态,因此必须先将硬件元素置于暂停状态,然后才能暂停 CPU。
不过,硬件元素可能相互依赖;例如,必须先挂起设备,然后才能停用总线。与此同时,设备在系统挂起期间可能有多个状态,在不同条件下,这些状态都很有用,例如,如果设备要用作唤醒源,则应使用低功耗状态;如果设备不作为唤醒源,则应使用完全关闭状态。与此同时,相关的状态管理问题并不仅限于系统挂起。在 CPU 处于活动状态时,硬件元素可能会进入低功耗状态,例如当手机处于飞行模式时,需要关闭某些无线电。
鉴于这些因素,创建一个支持相互依赖状态转换的框架非常有用。由于功耗管理是需要进行此类转换的主要原因,因此此责任落在 Fuchsia 的功耗框架上。我们引入了“电源拓扑”一词,以便灵活地同时指代该框架核心的依赖项图和框架本身。
在开发电源拓扑时,我们发现管理硬件元素之间状态依赖项所需的概念会自然而然地延伸到软件元素,这些元素可以在硬件之上提供更高级别的抽象,或自然地描述面向用户的功能的启用/停用状态。具体而言,通过明确捕获支持面向用户的功能所需的依赖项,我们建立了一种自然的方式来强制执行按需使用,以便仅在需要时使用依赖项,并将所用资源的归因提供给需要它们的功能。对组件的归因也很重要,但功能与使用电源的原因更密切相关,因此需要在子组件级别进行归因。
我们为强制执行基于需求的状态更改而建立的概念将允许电源拓扑不仅编码系统中各个元素支持的状态,还编码用于驱动状态更改的规则。这将为产品开发者和系统工程师打造一款强大的工具,他们将能够通过拓扑本身(而非源代码)来查看系统级行为并提出功能更改建议。
为什么要采用新的拓扑?
Fuchsia 已经有两个重要的拓扑用于描述驱动程序和组件。不过,这两种方法都无法轻松解决状态管理问题。因此,我们将独立开发电源拓扑,并希望定期回顾组件图和驱动程序图,以阐明电源拓扑在其中的作用。
为方便您参考,我们简要介绍一下现有拓扑。
组件拓扑描述了两件事:组件实例之间的父/子关系和 capability 路由图。它是一个树,用于描述组件实例的层次结构,并且功能会映射到该树顶部的 DAG。如果某个组件需要访问另一个子树中的 capability,则该 capability 会通过其父级进行路由。
驱动程序管理器还会将自己的节点拓扑作为 DAG 进行跟踪。在驱动程序框架中,节点是设备的抽象,驱动程序会绑定到节点以使用其关联的资源,例如对 MMIO 寄存器的访问。驱动程序是组件拓扑中的组件,但会展平为集合。采用这种结构的原因是,组件拓扑没有用于表示没有绑定驱动程序的节点的方法,并且节点可以有多个父级(这些称为复合节点),而组件拓扑的树结构不允许这样做。
利益相关方
教员:
Adam Barth abarth@google.com
Reviewers:
- Power:Kyle Gong kgong@google.com
- 电源:Michael Brunson mbrunson@google.com
- 驱动程序框架:Justin Mattson jmatt@google.com
- 驱动程序框架:Harsha Priya NV harshanv@google.com
- Zircon 内核:Nick Maniscalco maniscalco@google.com
- 平台驱动程序:Andres Oportus andresoportus@google.com
- 组件框架:Gary Bressler geb@google.com
咨询了:
- David Gilhooley dgilhooley@google.com
- Corey Tabaka eieio@google.com
- Filip Filmar fmil@google.com
- Guocheng Wei guochengwei@google.com
- HanBin Yoon hanbinyoon@google.com
- Eric Holland hollande@google.com
- Mukesh Agrawal quiche@google.com
- John Wittrock wittrock@google.com
社交:
此设计最初通过 Google 内部设计文档向来自 Power Framework、Component Framework、Driver Framework、Driver 和 Zircon 团队的审核人员进行过共享。在设计 Power Broker 和 System Activity Governor 的过程中,我们进一步优化了该规范,这两项规范都将成为即将发布的 RFC 的主题。
要求
有序的依赖项管理
如前面所述,系统电源管理的一个关键问题是,以尊重这些状态之间的依赖关系的方式管理不同系统元素的状态变化。此类依赖项的影响示例如下:
- USB 设备只有在其总线通电后才能开机。
- 只有在为其供电的电源轨电压足够高时,时钟才能以给定频率运行。
- 只有在有有效的网络连接时,视频在线播放应用才能开始在线播放视频。
一般来说,给定系统元素 E 可能具有一系列可占据的状态 S0、S1、S2...。为了让 E 正确占据给定状态 Si,必须满足 Si 的所有依赖项。
如果操作始终保留所有系统元素状态的依赖项,我们将其称为有序操作。具体而言,对于具有候选状态 Si 的每个元素 E:
- 只有在满足该状态的所有依赖项后,E 才会进入 Si。
- 如果要破坏 Si 的某个依赖项,E 必须先退出 Si。
Power Framework 必须支持参与的系统元素的有序状态转换。
当无法有序执行状态转换时,Power Framework 应确保将元素置于明确定义的状态,并尽量减少执行无序更改的元素数量。
归因
系统元素可能处于各种状态,其中一些状态的功耗较高。当元素占用较高功耗状态时,电源框架必须能够确定出现这种情况的原因。
效率
系统元素应被驱动到 Power Framework 可以归因于操作原因的最低功耗状态。框架用户必须能够通过简单的方式根据需要将元素推送到更高功率状态,但可能需要引入新的归因原因才能做到这一点。
可观测性
功耗框架必须支持观察框架用户认为与功耗相关的系统元素的状态。
性能
假设系统元素能够以符合一组产品要求的方式执行状态转换,Power Framework 必须充分支持它们执行此操作。这大致可分解为两个方面:
- 不得抑制本地性能。电源框架不得为各个系统元素的状态转换引入过长的延迟时间。
支持优化非本地性能。Power 框架应支持优化跨多个元素的状态转换。
- 例如,假设图形子系统和音频子系统在系统挂起操作期间并行进入低功耗状态。Power Framework 应指明它们是并行执行的,并提供有关哪个操作耗时更长的深入分析,以便系统挂起操作的延迟时间优化可以适当地侧重于其中一个操作。
适用范围
电源拓扑需要考虑非常大的解题空间。本提案明确不涉及以下主题:
- 电源代理的详细规范。此 RFC 必须确定 Power Broker 的一些基本方面,以便开发拓扑模型。不过,它会尽量将有关 Power Broker 规范的部分留待即将发布的 Power Broker RFC 中进行说明。Power Broker 将实现本文档中详述的模型之外的行为,我们希望为其提供实现这些行为所需的所有灵活性。
- 一流的错误处理。本文档中开发的拓扑模型未提供用于处理状态转换错误的明确方法。此排除项是对上一个条目的扩展;它对 Power Broker 的错误处理没有任何影响,并且主要目的是避免施加任何限制。
- 不法分子。电源代理和元素所有者之间的职责分工最终会要求考虑那些行为不良且出乎意料的元素所有者。
- 由截止期限支持的状态转换。为了强制执行及时的系统级操作,自然会考虑为各个状态转换设置应用时限。
随着用例提供具体要求,我们会进一步考虑这些问题。
设计
本文介绍的设计建立了电源拓扑结构的基础模型,与任何特定接口或实现无关。从实际角度来看,对于打算将其子系统与电源拓扑集成在一起的开发者来说,即将发布的几个 RFC 也非常重要:
- Power Broker RFC 将介绍管理电源拓扑结构所涉及的接口以及实现这些接口的组件。
- 系统活动控制器 RFC 将介绍电源拓扑与系统暂停/恢复进程的集成点。
- “支持电源的驱动程序”RFC 将介绍集成过程中与驱动程序相关的方面。
不过,拓扑模型本身非常复杂,需要单独撰写一篇文档来介绍。本 RFC 旨在通过一致的概念框架批准这些概念,为其他 RFC 奠定基础,并在此基础上开发稳定的文档,以协助 Power Framework 用户进行集成。
电源拓扑和核心概念
促成此设计的主要功能需求是上述有序性要求。首先,我们需要确定哪些类型的系统元素可以参与我们的模型,它们可以占据哪些类型的状态,以及这些状态可以通过电源拓扑表达哪些依赖项。只有这样,我们才能指定如何有序地控制这些状态。
电源元素
电源元素是此设计中的基本有状态实体。电源元件可能处于有限数量的状态,并且在任何给定时间都只处于其中一种状态。有时,将电源元素视为泛化设备模型会很有用,但也可以简单地将其视为状态的容器。
给定硬件设备可能直接对应于单个电源元素,但也可以使用描述不同设备状态的多个电源元素对其进行建模。例如,您或许可以单独配置触摸传感器的采样率和位置跟踪容量;因此,传感器的驱动程序可以公开独立的“采样率”和“位置跟踪”元素。
功率元素还可用于对更抽象的概念进行建模,例如跨多个硬件的子系统的总体状态,或面向用户的软件功能的启用/停用状态。
功率等级
功率级别是电源元素允许占据的状态。功耗级别架构由给定功耗元素可能占据的功耗级别集合以及稍后将介绍的元数据组成。
Power Framework 假定架构中的级别遵循若干约束条件。框架用户负责确保在为电源元素指定架构时,这些约束条件准确反映了所建模实体的属性。这些约束条件如下:
- 它们可以按耗电量递增的顺序排序。(测量功耗的方法有很多;就目前而言,只需根据上下文定义“典型”功耗即可。)其余约束条件以此排序为依据。
- 依赖项是累积的:对于给定元素,在级别 L 下正常运行所需的任何资源,级别 M(大于 L)也需要这些资源。
功能是累积的:对于给定元素,级别 L 提供的任何功能也由级别 M(大于 L)提供。
- 此要求可消除电源元素的依赖项之间发生冲突的可能性。例如,如果一个依赖项需要第 N 级的功能,而另一个依赖项需要第 (N+1) 级的功能,则该元素可以通过在第 (N+1) 级运行来满足这两项要求。
功耗等级架构由以下部分组成:
- 架构中每个电源等级的标签。
- 各个等级的排序,以功耗递增为顺序。
示例
为方便说明,我们将使用字符串标签,并使用从下到上排序的垂直列表来表示排序顺序。(有关电源等级的实际表示方式的详细信息将在电源代理 RFC 中介绍。)
下图展示了三种可能的电源级别架构:
|
|
|
特别值得注意的是,电源级别的排序方式与 ACPI 电源状态相反。这样可以消除非正式用语中不幸的模糊性。根据 ACPI 惯例,“较低功耗状态”等表达式有两种完全相反的解释,具体取决于“较低”是指功耗(对应于排序顺序中的较高编号)还是排序顺序中的编号(对应于较高功耗)。“功耗更低”等表达式不会出现这种模糊性。
并非所有电源元素都能够使用与其他元素共享的通用电源电量架构。例如,您可以定义一个功率元素来指定 CPU 的运行频率下限,在这种情况下,功率等级与相关 CPU 支持的频率相对应。
用途和限制
出于多种原因,电源级别架构是表示元素状态的有用起点:
- 它们可以清晰地表达常见模式,如上文所示。
- 它们提供了一种方法,可通过汇总(而无需繁琐的重复)的方式捕获大量状态之间的依赖项。
- 它们的使用方式不会发生冲突,这是一种并非在所有情况下都能实现的特性,但应尽可能加以利用。
单个电源元素和电源级别架构无法描述 Power Framework 用户感兴趣的所有场景。例如,单个设备的互不相干的运行模式(作为一个简单但不合适的示例,请考虑可以供暖或制冷的热泵)无法准确地建模为单个功率元素。
不过,电源级别架构可用作构建块来描述更复杂的系统。有关执行此操作的最佳实践超出了本 RFC 的范围;我们将在即将发布的文档中介绍该主题。框架用户还可以通过 Fuchsia > Power 组件向 Power Framework 团队提交 bug。
可操作性和依赖项
在任何给定的时间点,电源元件都能够在其功率等级的一部分范围内正常运行,具体取决于当前的系统条件。这些是其可操作级别。此子集始终由小于或等于最大可操作级别的所有级别组成,对于元素 E,表示为 max_operable_level(E)。
电源电量依赖项是一种条件,用于指示一个电源元素的可操作电量级别与另一个元素的当前电源电量级别之间的关系。功耗等级依赖项表示,若要让子元素 C 在等级 L 或更高等级下运行,则需要父元素 P 在所需等级 RL 下运行。更确切地说,(C, L) 对 (P, RL) 的依赖项意味着:
- 如果 current_level(P) < RL,则 max_operable_level(C) < L。
等效地,此条件可以表述为:
- 只有在 current_level(P) ≥ RL 时,max_operable_level(C) ≥ L。
(C, L) 的每个依赖项都建立了 L 可操作的必要条件。依赖项可以根据其关联条件的状态描述为“满足”“已满足”等。
另请注意,对于任何级别 K < L,(C, K) 的每个依赖项都会为 L 的可操作性创建一个必要条件。具体而言,(C, L) 的可操作性可能会对父元素施加要求,即使 (C, L) 本身并不直接依赖于该元素。我们将具有此类要求的所有元素集称为 (C, L) 的必需元素。对于此集中的任何元素 P,都有一个最低要求级别,以便 (C, L) 可正常运行;我们将其表示为 min_required_level(P; C, L)。
对所有必需元素进行汇总,必须满足以下一系列必要条件,才能使 L 可正常运行:
- 对于所有 P ∈ required_elements(C, L),current_level(P) ≥ min_required_level(P; C, L)。
当这些条件都满足时,我们称 L 为正常可操作。即使 L 在名义上可操作,也可能无法操作;本地条件(例如可能未观察到的硬件错误)可能会阻止 C 在 L 下运行,即使满足所有相关的电源级别依赖项也是如此。应将额定可操作性视为电源拓扑尝试对真实可操作性进行建模的方式。虽然这两个概念之间存在差异是不可避免的,但当元件设计师尽量减少此类差异时,电源拓扑结构将能够发挥最佳性能。
一个电源元素可能对另一个元素具有多个电源级别依赖项。固定父级和子级的所有此类级别依赖项组成一个电源元素依赖项。如果 C 的至少一个级别与 P 的某个级别之间存在依赖关系,我们就会说 C 依赖于 P。
电源拓扑
作为一个正式实体,电源拓扑是一种多边图,其中电源元素作为节点,电源电平依赖项作为有向边。此外,我们还对此图表施加以下约束条件:
无环:电源拓扑结构是无环的。
- 具体而言,父/子关系的行为符合预期;如果元素 C 依赖于元素 P,则 P 可能不依赖于 C。
最低电源级别可操作性:无论其他电源元素的当前电源级别如何,任何电源元素的最低电源级别都必须始终可操作。此外,它可能没有电源级别依赖项。
此条件是指可操作性,而不是标称可操作性,它可确保每个元素始终至少有一个可操作级别。必须由元素所有者强制执行。
允许一个元素的最小级别依赖于另一个元素的最小级别不会对可操作性产生影响。但此类依赖关系在功能上没有关联,并且允许此类依赖关系还需要考虑仅通过最低级别相互依赖的元素。
电源拓扑可能包含冗余的电源级别依赖项。例如,(C, L) 可能同时依赖于 (P, RL1) 和 (P, RL2),其中 RL1 < RL2,即使依赖于 (P, RL2) 所强加的条件严格强于依赖于 (P, RL1) 所强加的条件。在该提案的模型中,此类冗余被视为无害,但在实现时可能会受到特殊考虑。
示例和上下文
注意:这些示例仅作说明之用。此 RFC 对必须使用电源元素进行建模的内容没有任何影响。
电源级别依赖项的最基本形式与开启/关闭状态相关。在一个非常简化的示例中,我们可以表示 USB 总线必须处于开启状态,USB 设备才能处于开启状态,如下所示:
为了有序地处理上述依赖项,必须先开启总线,然后再开启设备;必须先关闭设备,然后再关闭总线。
功耗级别依赖项的更广泛定义可容纳更复杂的关系,例如 DVFS 期间时钟和电压之间的耦合。(由于 DVFS 对时间非常敏感,因此可能不适合用于电源拓扑集成,但它是一个有用的示例。)假设我们有一个具有以下 DVFS 表的时钟,其中列出了支持的频率及其所需的电压:
时钟频率 | 电压 |
---|---|
1.6 GHz | 900 mV |
1.5 GHz | 800 mV |
1.4 GHz | 700 mV |
下表将电源元素、电源级别和依赖项转换如下:
(请注意,(时钟频率,1.4 GHz)对(电压,700 mV)的依赖性在技术上不会包含在拓扑中,但为了便于与表格进行比较,我们在图中进行了描述。)
表示设备软件功能或用户级操作模式等内容的电源元素可能具有许多依赖项,用于描述其正常运行所需的所有资源。在另一个简化示例中,视频通话客户端的“Active”级别可能取决于进行视频通话所需的各种硬件子系统:
最后,多个子元素可以依赖于同一元素。在这里,我们描绘了一款设备,该设备以延迟时间来描述其功耗水平。客户端 A 的“活跃”级别需要低延迟,而客户端 B 的“活跃”级别需要中等延迟。设备可以通过低延迟运行来满足这两个子级的“活跃”级别。
此示例展示了电源等级的一个重要属性:电源等级的定义方式使得不同客户端的需求不会冲突。
边缘方向惯例
如前面的图表所示,我们采用了以下惯例:电源拓扑中的边沿会沿着依赖项方向(从子级到父级)延伸。有些讨论和直观的术语可能无法避免地基于电源从父级流向子级的方向。目前,我们的目标是针对所有正式开发使用依赖项方向,我们只是建议读者注意此问题。
电源等级管理
为了指定如何在真实系统上使用电源拓扑,我们接下来需要定义管理拓扑和各个电源元素的相关方。
Power Broker
电源拓扑将由一个名为 Power Broker 的电源框架组件管理。Power Broker 将维护整个电源拓扑的表示法,包括所有电源元素、其电源等级架构、电源等级依赖项和当前电源等级。它将为每个元素所有者提供接口,以便他们在适当的时间更新其元素的电源级别,以便尽可能有序地进行级别更改。
电源代理的存在反映了此设计的一个关键断言:电源拓扑将由集中管理。我们认为这样做很有必要,原因如下:
- 如果尝试在本地管理拓扑,则会大大增加依赖项管理中出现实现错误的可能性。
- 中央管理员拥有全系统可见性,可将提升的电源电平与电源使用需求相关联,从而满足效率要求。
- 中央管理员有权根据归因要求执行归因。
- 中央管理员可以维护和报告详细的遥测数据,以满足可观测性要求,即使单个子系统未提供任何插桩也是如此。
- 通过集中管理,您可以明确地从不应拥有代理权的元素所有者手中移除代理权。例如,通常建议驱动程序不要做出有关其底层硬件当前功耗等级的决策;驱动程序可以通过放弃对其所拥有的功耗元素的租用能力来明确编码此偏好设置。
集中管理确实会增加本地化性能开销,因为管理员会引入一个必须了解电源元素及其等级的方。因此,在 Power Broker 的设计和实现过程中,必须仔细关注性能。不过,Power Broker 将支持全球视角,这可能有助于它通过提供系统级性能优化机会来抵消本地费用。
元素所有者
每个电源元素都与一个元素所有者相关联,该所有者是负责管理该元素的组件(可能是 DFv2 驱动程序)的实例。所有者将该元素注册到 Power Broker,声明其电源级别架构,定义其依赖项,并在适当的时间更新其电源级别。
如有必要,可以在元素的生命周期内委托元素的所有权。这很可能涉及一个组件实例充当注册和配置任务的所有者,另一个组件实例则获得运行时管理的所有权。
电源元素及其关联依赖项的生命周期时长将在电源代理 RFC 中加以说明。
电源元素的类型
大多数电源元素将处于受管理状态,这意味着其所有者将电源级别的选择和更改时间推迟到电源代理。如需通知元素所有者需要更改级别,Power Broker 会向所有者发送必要级别。所有者进行更改,然后通知 Power Broker 元素的新当前级别。
在当前模型中,我们做出一个简化假设。在收到元素 E 的所需级别 RL 的通知后,E 的所有者始终会:
- 如果 RL 可操作,请将 current_level(E) 更新为 RL。
- 如果 RL 不可用(例如,在尝试更新 E 的当前级别时发现硬件错误),请执行一项操作,使 (E, RL) 不再名义上可用。(例如,错误状态元素可用于指定 (E, RL) 的不可操作性。
这绝非对可能出现的错误情况的详尽处理。而是将错误处理的开发工作委托给 Power Broker(如排除项中所述),同时指明在此模型范围内可采用的主动错误处理方式。
未受管理的元素称为非受管理元素。它不能有依赖项,并且每当其级别发生变化时,其所有者只需向 Power Broker 报告其当前级别即可。其当前级别会影响依赖于它的所有元素的可操作性。
此类元素对于描述非软件控制且只能观察到的状态(例如硬件开关的状态或某个硬件的错误状态)至关重要。
电源电平控制
通过受管理的元素,电源代理将负责推动整个拓扑中的大多数电源级别更改。为了限制本 RFC 中涉及的设计表面,我们将仅关注稳态行为。
Power Broker 的控制方案旨在平衡电源使用需求与限制其使用的约束条件。
从概念上讲,电源使用需求源自设备的功能要求。这些要求通常会根据对用户当前对设备的预期情况的了解而动态变化。用户可能会打开某个应用来执行特定任务,这表明与该应用关联的某些电源元素需要在较高功率水平下运行。或者,设备可能会感知到表明用户就在附近且可能很快与其互动的活动,这表明设备应进入一种能够以低延迟时间响应的模式。即使应用处理器处于非活跃状态,系统也会根据用户对哪些互动会唤醒设备的预期(例如说出热词、点击鼠标、点按屏幕等)来产生需求。为了表示需求进入电源拓扑,我们将引入一个名为租约的对象。
而约束条件则可以通过两种不同的方式产生。在某种情况下,无法通过软件控制的状态可能会直接抑制功耗;这由非受管理元素进行建模。在另一种情况下,系统可能需要一种方法来表达何时应或不应提高功耗等级,以满足租约表达的需求;依赖项执行方式政策可用于捕获此需求。
总而言之,这些概念将使我们能够指定 Power Broker 引导系统的稳态,同时将对时间相关方面所需的细微之处留给 Power Broker RFC。
稳定状态
在任何给定时间点,一组特定因素都会决定受管理元素的稳态,即只要决定因素保持不变,功耗代理将引导它们达到的功耗水平。在本 RFC 的范围内,我们将从稳态的角度描述 Power Broker 的控制方案。这样,我们就可以介绍相关的关键概念,同时限制所需的详细信息量。
稳定状态决定因素
稳定状态的决定因素如下:
- 拓扑结构,即电源元素和依赖项。
租赁。
非托管元素的当前级别。
对这些决定因素的任何更改都将导致对稳态进行重新评估。
对稳态的评估
确定稳态的关键因素是评估哪些租约将被执行,即租用元素级别的所有依赖项均已满足。
Power Broker 将以“全部或全无”的方式处理租约。如果 (C, L) 上存在租约,但 Power Broker 无法或不满足 (C, L) 的所有依赖项,则无法满足 (C, L) 的任何依赖项,除非这样做有助于实现其他可满足的租约。
为了确定是否履行租赁,电源代理需要确定自己是否可以履行租赁,以及是否应该履行租赁。“可以”这个问题是功能要求方面的问题,可通过非受管元素的级别来解决。为了回答“应”这个问题,需要引入一个新概念来指定 Power Broker 是否会主动努力满足对受管元素的依赖项。
为此,我们为电源级依赖项引入了两种可能的执行政策:强执行和弱执行。只有当依赖项的必需元素是受管理的元素时,才能强制执行,而对受管理和不受管理元素的依赖项都可以弱制执行。
执行方式政策也会汇总到依赖项的路径。如果依赖项路径中的每个依赖项都已强制执行,则该路径是强制执行的;否则,该路径是弱制执行的。
现在,假设有一组固定的稳态决定因素,我们就可以指定租约何时会履行。只有当 (C, L) 通过弱满足路径依赖于的每个元素级 (P, RL) 满足以下条件时,(C, L) 的租约才会在稳态下得到满足:
- 如果 P 是无管理的,则 current_level(P) ≥ RL。
- 如果 P 是受管理的,则 (P, RL) 由在稳定状态下执行的另一个租约所需,并且通过强制执行的路径依赖于它。
确定租约的稳态履行后,任何受管理元素 C 的稳态功耗等级只是已履行租约所需的最大等级,如果没有已履行租约需要 C 的某个等级,则为 min_level(C)。
有序
Power Broker 会尽可能按依赖项顺序执行操作,引导系统进入稳定状态。特别值得注意的是,如果所有稳态功耗级别都大于或等于当前功耗级别,则保证向稳态功耗级别的过渡有序进行。
在某些情况下,电量下降时可能会出现无序变化。为了描述此类情况,我们为电源级别依赖项引入了两种终止政策:orderly-on-termination 和 disorderly-on-termination。对托管元素的任何依赖项都是有序终止的,而对非托管元素的任何依赖项都是无序终止的。
与执行方式政策一样,终止政策会汇总到依赖项的路径。如果路径中的所有依赖项都是有序终止的,则该路径也是有序终止的。否则,它是终止时无序的。
如果 (E, L) 通过有序终止路径依赖于 (M, RL),则 Power Broker 将尽可能确保在 current_level(M) 降低到低于 RL 之前,current_level(E) 降低到低于 L。反之,如果 (E, L) 通过终止时无序的路径依赖于 (U, RL),则本文档中的模型无法保证在 current_level(U) 减小到低于 RL 时,沿路径的级别更改的顺序。
为了更具体地从非受管理元素的角度描述无序情况,不妨考虑 (E, L) 对 (U, RL) 的无序终止依赖项,其中 U 必须是无管理的。如果 current_level(U) 降低到低于 RL,则此事件不在电源代理的控制范围内。无法提前将 current_level(E) 驱动到低于 L 的级别;Power Broker 必须以响应方式将其驱动到更低的级别。由于 U 的当前级别降低后,对 (U, RL) 的传递依赖项也会立即断开,因此在系统进入新的稳定状态时,无法强制执行级别更改的明确顺序。
依赖项类型
上述正式说明产生了三种不同的依赖项,我们为其指定了以下名称:
依赖项类型 | 履单政策 | 终止政策 |
---|---|---|
基本 | 弱 | 无序 |
随机 | 弱 | 有序 |
Assertive | 极佳 | 有序 |
基本依赖项始终是受管元素对非受管元素的依赖项,而断言依赖项或机会依赖项始终是受管元素对另一个受管元素的依赖项。
示例
不受管理的元素
此示例演示了如何在具有硬件静音开关的系统上使用非托管元素。这些元素如下:
静音开关:当静音开关处于“关闭”状态时,系统的麦克风会正常运行。处于启用状态时,麦克风的时钟会固定,因此它提供的信号是无用的。
输入流:表示音频子系统传递给应用的来自麦克风的传入数据流。其“Active”功耗级别对“Mute Switch, Disengaged”(静音开关,未启用)具有基本依赖项。
音频处理器:此元素属于出于未指定用途处理传入麦克风数据的应用。
系统活动:此元素以抽象方式表示系统允许的任务处理范围。当此元素设为“高”时,系统会处理各种各样的任务;当设为“低”时,系统会更有选择地处理任务。
步骤:




对托管元素的机会性依赖项
在此示例中,有两个功能需要将“System Activity”元素设为“High”级别才能运行。高优先级功能的依赖项是断言性的,因此如果租约(高优先级功能,处于活动状态)需要,系统活动将提升到“高”。但是,低优先级功能的依赖项是机会性的,因此只有当高优先级功能的租约将系统活动状态提升到“高”时,才能将其提升到“活动”。
步骤:

“低优先级功能(处于活动状态)”存在租约,但 Power Broker 不会满足该租约,因为对“系统活动(高)”的依赖项是机会性的。

已获取租约(高优先级功能,有效)。这会改变稳态。

系统活动级别上调为“高”。

这两个功能级别会同时提升为“有效”,以履行这两项租约,但不遵循特定顺序。

“(高优先级功能,有效)”的租约已被释放。在新稳定状态下,系统将不再履行“低优先级功能,有效”的租约。

“高优先级功能”已降级为“无效”。(注意:此 RFC 不保证此状态更改会在“低优先级功能”的级别降低之前发生。)

为保持有序性,系统活动将保持“高”状态,直到“低优先级功能”降级为“无效”。 此步骤突出显示了一种机会依赖项的属性,许多人会感到惊讶。机会依赖项在实现方式上与断言依赖项不同,但在确保关机顺序有序时,Power Broker 会平等地对待这两种依赖项类型。

系统活动最终降至“低”。
错误状态元素
元素所有者可以使用会抑制特定功率级别可操作性的非受管理元素来对错误状态进行建模。下图展示了元素 E 的两个可能的错误元素,其级别分别为 L0、L1、L2、L3。
在顶部场景中,错误元素的级别直接反映了 E 的级别。如果 current_level(错误状态)为“Li OK”,则 Li 是 E 可以运行的最大级别。在底部场景中,如果 current_level(错误状态)为“错误”,更简洁的错误元素会抑制 E 在 L2 或 L3 的操作。
此机制仅用于停用元素架构顶部的连续一组级别。您可以使用其他机制停用高于某个级别的级别,使其上方至少有一个级别保持可操作状态,但我们希望在出现此类用例时仔细审核。
归因
Power Broker 将支持将当前功率水平归因于其履行的租约。如果这样做很有用,Power Broker 将支持区分明确要求特定级别的租约与机会性要求特定级别的租约。
可观测性
Power Broker 将通过 Fuchsia 已建立的诊断设施公开有关电源元素的信息,包括其电源级别架构和依赖项。此外,它还会在某个合适的(可能可配置的)回溯期内维护租约和功耗级别转换记录。总而言之,这些信息有助于检查查询时拓扑的状态,同时还能让未来的工具提供拓扑的近期历史记录的回放。
配置
通过静态配置,可以轻松捕获电源拓扑的许多方面。例如,之前通过图表介绍的 USB 示例可以改为描述为:
[
{
name: "USB Bus",
levels: ["Off", "On"],
},
{
name: "USB Device",
levels: ["Off", "On"],
dependencies: {
"On": ("USB Bus", "On")
},
}
]
如果必须跨组件边界识别元素,就会出现额外的复杂性。我们将与组件框架团队合作,研究简化静态配置的方法。
后续主题
过渡延迟时间支持
从长远来看,电源拓扑旨在提供一个框架,以便了解和优化系统状态转换的延迟时间。电源元素定义将建立一个规范位置,用于对本地转换延迟时间(即满足所有依赖项后更改元素电源级别所需的时间)进行编码。本地元素延迟时间不是必需的,但随着给定系统的成熟,可以添加这些延迟时间。
本地延迟时间的应用包括:
- 对跨多个元素的复合操作的延迟进行半静态分析(例如,通过在运行时捕获拓扑配置)。
- 对观察到的延迟进行运行时跟踪,并报告与预期偏差。
- 向客户报告延迟时间估算值,以支持具有严格时间要求的操作。
其他类型的状态和依赖项
出于多种原因,我们介绍的电源级别和依赖项类型是表示元素状态的实用起点。它们提供了一种方法,可以汇总的方式捕获大量状态之间的依赖项,而无需繁琐的重复。此外,它们还可以以不会发生冲突的方式使用,这是一种并非在所有情况下都能实现的特性,但应尽可能加以利用。
随着电源拓扑的不断演变,支持其他类型的状态和依赖项可能很有用,也可能很有必要。例如:
- 传感器的固件可以实现为支持一组不相交的操作模式,每个模式都经过优化以满足不同的要求,但不遵循功能和功耗严格增加的规模。虽然此类传感器可以通过每种模式的一个二进制电源元素进行描述,但我们可以改为引入一种新类型的状态架构,该架构可以同时描述所有模式,同时包含用于解决竞争客户端之间冲突的规则。
- 某些类型的硬件(例如 GPU)的电源级别可能会根据多个客户端的并发负载要求进行选择。电源拓扑可能支持捕获此类负载要求并以通用方式累积这些要求的依赖项。
目前,此类开发尚处于推测阶段;在整个子系统与电源拓扑的初始集成过程中,应根据需要重新审视这些开发。
实现
实现电源拓扑本身并在整个 Fuchsia 中加以利用是一项艰巨的任务。有几项集中式工作将被广泛使用,因此在初始实现后,需要进行大幅优化。与此同时,Fuchsia 子系统目前对电源管理的支持有限,在许多情况下,其开发者需要在将这些策略映射到电源拓扑的同时,开发适当的电源管理策略。
将开发策略分为不同的阶段(其中一些是历史阶段)会很有帮助。在第 1 阶段,核心功能在相对隔离的环境中开发,然后在第 2 阶段进行少量集成,以演示关键用例并实现系统暂停/恢复的端到端测试。在前两个阶段中,我们总结了一些经验,现在将在第 3 阶段打好基础,以实现更多集成并带来稳定的开发周期,如第 4 阶段及更高阶段所述。
- Power Broker 负责管理电源拓扑。
- 系统 activity 控制器定义和管理支持系统暂停/恢复操作的元素。
- 驱动程序框架支持将驱动程序与 Power Framework 集成。(Power Framework 功能将通过标准方式路由到非驱动程序组件,无需特殊支持。)
第 2 阶段(历史):概念验证版 Power Framework 集成
- 与将硬件置于低功耗和高功耗状态的驱动程序的初始集成。
- 与支持唤醒源的驱动程序的初始集成。
- 首次在端到端挂起/恢复工作流中使用。
- 批准此 RFC;提出并批准适用于功耗代理、系统活动控制器和感知功耗的驱动程序的 RFC。
- 描述现有实现所施加的设计约束条件,例如延迟开销所施加的有效速率限制。
- 确定并设计下一组与 Power Framework 的子系统集成。
- 制定并记录最佳实践和设计模式。
- 确定并实施小规模改进,以协助集成(例如 API 改进、简单的优化)。
- 建立测试流程和支持库,其中包含 Power Framework 的特定领域注意事项。
确定大规模功能添加和改进的优先级。可能的原因包括:
- 支持跟踪转换延迟时间。
- 需要进行重大界面更改和/或后端实现工作的性能改进。
- 简化了组件框架集成。
第 4 阶段及更高阶段:进一步集成和更大规模的改进
- 集成更多子系统。
- 在适当情况下优化现有集成。
- 根据新出现的需求,继续进行小规模改进。
- 解决优先级最高的更大规模改进。
- 确定需要在下一阶段解决的更大规模改进(如果有)。
性能
性能的许多方面最适合在第 3 阶段 RFC 中加以解决,其中 Power Broker 与此提案的概念构建最为相关。不过,在当前范围内,我们可以提出一些一般准则,以便考虑性能影响。
本地与非本地性能
本地和非本地性能要求之间存在矛盾,因为与电源代理协商状态更改通常至少会产生一些费用,而纯本地化解决方案可以避免这些费用。不过,纯本地化解决方案无法充分支持执行有效非本地优化所需的系统级分析。
识别延迟时间开销
电源代理对电源拓扑的管理会产生一定量的延迟开销,尤其是由于元素所有者与代理之间的 IPC。不过,请务必仔细思考哪些成本是真正的开销。特别值得注意的是,某些子系统本身就需要在其进程之间进行通信,才能实现任何形式的电源管理,而与电源拓扑的集成可以通过 Power Broker 间接实现这种通信。
大小驱动的延迟时间开销
由于相对不频繁的操作(例如全系统挂起和恢复)而产生的延迟开销主要受其影响的子图大小的影响。了解子图广度、深度和节点数对此类开销的影响非常重要。
QPS 驱动的延迟时间开销
目前,导致 QPS 向电源代理发出请求的主要原因预计是挂起阻塞租约;System Activity Governor RFC 中将详细介绍相关电源元素。
目前尚未明确规定 Power Broker 必须支持哪些 QPS。 相反,由于事件到达速率足够高,导致每个事件的租约会产生过多开销,因此某些子系统集成可能需要阻止挂起。在这种情况下,必须采用其他设计模式,以便在单个挂起阻塞租约下整合多个事件的处理。
为了帮助进行此类评估,估算每次租赁的延迟时间开销非常重要。
安全注意事项
在第 3 阶段 RFC 中,应详细考虑安全性,因为此阶段的提案更接近具体实现,因此可以进行更广泛的讨论。下面简要介绍了使用电源拓扑时固有的安全问题。
电源依赖项和功能
由于电源拓扑使用依赖项将电源元素提升到更高的电源级别,因此能够声明对特定电源元素的依赖项本身就是一项特权操作。因此,为了符合 Fuchsia 的安全模型,依赖项声明应在相当精细的级别(至少按元素)明确进行 capability 保护。
到目前为止,Power Broker 采用了集中式权限管理方法,以便根据当前支持的 capability 类型严格处理权限。我们之所以选择这种方法,是因为它比组件框架的并发演变更能快速全面了解电源拓扑的影响。从长远来看,Component Framework 或许能够更自然地表示与电源拓扑相关的功能,从而减轻 Power Broker 的一些安全相关责任,并支持更顺畅的开发者体验。
集中管理的风险
将 Power Broker 用作中央管理员会使其面临风险,例如 DDoS 攻击(可能会阻止其管理系统关键状态转换)和绕过其权限逻辑(可能会使攻击者能够恶意操控硬件状态)。
隐私注意事项
由于系统会在设备端跟踪详细的子系统状态,因此请务必确定如何在利用车队指标中的数据时兼顾隐私保护问题。在第 4 阶段或之后,当我们能够具体演示 Power Broker 可能会为大量子系统导出的数据时,才能最有效地考虑此问题。
测试
第 1 阶段已纳入对所开发的所有功能的单元测试,以及 Power Broker 与虚构客户端的集成测试,以及将 Power Broker 与系统 activity 控制器耦合的集成测试。
第 2 阶段添加了端到端挂起/恢复测试,并支持针对系统 activity 调度器进行非密封驱动程序测试。
第 3 阶段将通过库和文档建立正式支持,以便在实践中遇到的各种用例中测试与 Power Framework 的集成,同时扩大端到端测试的覆盖范围。
文档
此 RFC 是电源拓扑中概念定义的可信来源。
我们将添加文档来解决以下问题(并非详尽无遗):
- 对此处定义的概念进行了优化以提高可读性的说明。
- 集成指南。
- 实际电源拓扑集成示例。
- 电源元素的建议使用模式。
缺点、替代方案和未知情况
缺点
与此方案相关的两项主要费用如下:
- Power Broker 的实现。在撰写本文时,Power Broker 已实现,并且与本文中介绍的概念仅存在细微差异,因此这项费用很小。
- 客户端集成的费用分散。我们将研究通过文档、客户端库(注意 FIDL 评分标准的注意事项)和测试支持来降低这些成本的方法。
替代方案
分散式电源控制
作为电源拓扑的极端替代方案,您可以考虑采用无集中电源管理的系统。在这种系统中,子系统会提供自定义接口,以便将其驱动到不同的电源状态。
对于需要子系统处于特定电源状态的任何系统级模式,某个“模式控制器”实体需要负责确保每个子系统都处于适用于该模式的电源状态。该实体需要使用每个子系统专用接口。
负责控制给定模式电源状态的实体会有效地为该模式执行集中式电源管理,因此这种方法并非真正去中心化。与此同时,要求模式控制器使用其自行选择的接口控制每个子系统会造成明显的扩缩问题。综合考虑这些因素,我们预计 Fuchsia 必须至少支持某种形式的集中式电源管理,并且具有一定程度的接口标准化。
值得注意的是,此提案并未对子系统应如何利用电源拓扑做出严格规定。某些子系统开发者可能会发现,最适合执行轻量级集成,即仅在必要时将一个或两个总体子系统状态公开给电源拓扑,以便与系统模式转换集成。其他人可能认为,利用更深入的集成来全面模拟整个平台和驱动程序中的子系统是值得的。
操作序列
我们提出的基于状态和依赖项的方法的替代方案是标准化特定操作的顺序,从本质上将驱动程序具有“挂起回调”和“恢复回调”的概念推广为创建正常运行的系统所必需的。在 Linux 挂起/恢复中,这表现为四个可能的挂起驱动程序回调(prepare
、suspend
、suspend_late
、suspend_noirq
)和四个恢复驱动程序回调(resume_noirq
、resume_early
、resume
、complete
)。
我们之所以不采用这种方法,有以下几点原因:
它可能会隐藏系统处于暂停状态或恢复状态时设备所处的状态;公开此类状态的过程在很大程度上转化为创建此处提出的拓扑结构。此外,此类状态可能取决于设备在暂停期间应有的行为方式。
这会让人困惑,“暂停”和“恢复”是指在任何给定设备上执行的操作,还是指在整个系统上执行的操作。
它对意外要求非常脆弱,上述
_late
/_early
和_noirq
回调变体就是明证。有序依赖项管理问题适用于任何形式的电源状态控制,而不仅仅适用于系统级暂停和恢复操作。
采用操作序列化方法时,状态间依赖关系图仍然存在于抽象中,但在源代码中是隐式的。
命令式关机
作为按需使用率的替代方案,电源框架可以使用命令式关机模型,其中电源元素默认为高功耗状态,并且必须明确命令为低功耗状态。这种方法可在短期内简化某些功能的实现,但更容易引入未跟踪的依赖项。此外,它还不支持归因。
同时,按需利用率模型可在需要时在特定范围内适应强制性关机。在电源拓扑的具体细节中,只需一个用途是将资源拉到所需默认电源级别的使用方元素,使用方的所有者提供一个接口以根据需要更改级别即可。然后,使用方元素可用于在系统级视图中明确表示使用强制关机。
推迟的主题
Power Broker RFC 将解决以下问题和疑问:
- 元素和依赖项的生命周期时长。
- 租约生命周期。
- 与功率级别定义相关的 API 版本控制问题(基于兼容性提案中的指南),待 2024 年 4 月 22 日讨论结果更新。
- 汽车经销商会向待处理租赁的持有人提供任何反馈吗?
- 适用于与拓扑结构集成的子系统的测试准则,尤其是关于使用虚构电源代理与使用虚构电源元素的真实电源代理的准则。
- 用于原子添加/移除依赖项的 API。
- 处理冗余依赖项。
- Power Broker 崩溃时的行为。
- 元素所有者发生崩溃时的行为,包括与优雅关闭/启动进行比较。
- 错误处理。
在先技术和参考文档
Linux
Mac OS
Windows