RFC-0255:系统 activity 调度器 | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 定义一个组件,用于利用电源拓扑概念管理平台的挂起状态。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2024-05-07 |
审核日期(年-月-日) | 2024-08-02 |
摘要
此 RFC 提议添加一个名为 System Activity Governor (SAG) 的核心组件来管理系统的电源级别。本文档介绍了 SAG 的要求、其政策以及实现 SAG 时用于管理系统功耗级别的流程。本 RFC 可视为 RFC-0230:Fuchsia 中的挂起到空闲状态实现的一部分。
目标
- 启用对发生暂停-待机时间的管理。
- 提供有关暂停的统计信息,以便进一步提升未来的功耗表现,并实现监控车队级功耗。
非目标
- 实现特定硬件系统向不同电源状态的转换,包括但不限于 CPU、GPU、内存、网络接口等。
- 实现用于触发任务暂停的逻辑,例如
zx_system_suspend_enter
。
设计初衷
Fuchsia 是一款通用操作系统,旨在为多元化的硬件和软件生态系统提供支持。为了满足对功耗敏感的硬件和软件的需求,Fuchsia 必须能够管理其所运行的硬件平台的功耗。这包括能够将 CPU 切换到低功耗模式、触发系统级任务暂停、激活内存自刷新以及任何其他节能硬件功能。一组旨在降低功耗的硬件配置或状态被归为一项称为挂起状态的概念。
许多系统都支持多种挂起状态。每个挂起状态都有一组硬件状态、功耗和恢复延迟时间(退出挂起状态所需的时间)。每个系统都可以在概念上定义相同的挂起状态(挂起到空闲),该状态会映射到一组完全不同的硬件配置。
例如,Fuchsia 可能在两个 CPU 不同的系统上运行。一个 CPU 可能支持的功耗较低的电源状态比另一个 CPU 支持的功耗较低;不过,这两种系统都可能会将转换到最低功耗状态视为进入“挂起到空闲”状态的操作之一。
在考虑此主题时,平台的状态如下所示:
- RFC-0230:Fuchsia 中的挂起到空闲状态定义了挂起到空闲状态的概要要求和设计。目前,这是 Fuchsia 平台支持的唯一挂起状态。
- RFC-0250:电源拓扑定义了电源拓扑,它是 Fuchsia 中未来电源管理系统的基础。
- 单独的 RFC 定义了在运行时管理电源拓扑的组件:电源代理。
- 必须解读来自各种子系统的各种信号,以协调进入“挂起-空闲”状态的转换。
为了使用 RFC-0250:电源拓扑 实现 RFC-0230:Fuchsia 中的挂起到空闲状态,需要创建一个实现用于管理向挂起到空闲状态的过渡的政策的组件:系统活动调度器。
利益相关方
教员:
Adam Barth abarth@google.com
Reviewers:
- Aidan Wolter awolter@google.com(软件组装)
- Andres Oportus andresoportus@google.com(平台驱动程序)
- Gary Bressler geb@google.com(组件框架)
- Gurjant Kalsi gkalsi@google.com(平台驱动程序)
- Harsha Priya N V harshanv@google.com(驱动程序框架)
- Justin Mattson jmatt@google.com(驱动程序框架)
- Kyle Gong kgong@google.com(电源)
- Mukesh Agrawal quiche@google.com(界面)
- Nick Maniscalco maniscalco@google.com(Zircon 内核)
- Onath Dillinger claridge@google.com(电源)
咨询了:
- Alice Neels neelsa@google.com(界面)
- David Gilhooley dgilhooley@google.com(组件框架)
- Didi She didis@google.com(电源)
- Eric Holland hollande@google.com(电源)
- Filip Filmar fmil@google.com(界面)
- Guocheng Wei guochengwei@google.com(Starnix)
- HanBin Yoon hanbinyoon@google.com(平台驱动程序)
- John Wittrock wittrock@google.com(软件交付)
- Novin Changizi novinc@google.com(驱动程序框架)
- Suraj Malhotra surajmalhotra@google.com(驱动程序框架)
社交:
我们与负责管理内核、驱动程序、驱动程序框架、组件框架、产品政策和电源框架的电源团队和子系统所有者讨论了此设计。
要求
支持转换为暂停状态的系统必须支持 Fuchsia 产品的用例以及暂停状态的硬件要求。为了在维护产品用例的同时妥善协助过渡到暂停状态,SAG 必须满足以下要求:
- Fuchsia 组件(包括驱动程序)必须能够在关键操作进行时防止转换为暂停状态。例如,假设用户正在观看视频。设备不应尝试在视频播放期间暂停系统;否则,用户将获得糟糕的体验。
- 如需启用产品驱动的暂停政策,必须收集和公开与暂停相关的统计信息。例如,假设某产品在之前恢复至少 1 秒后才能触发转换为暂停状态。为了支持此功能,产品组件必须能够计算上次恢复转换以来的时间。
SAG 只负责确定何时进行转换。定义和协助转换到每个挂起状态将由实现 SAG 使用的
fuchsia.hardware.suspend.Suspender
协议的组件处理。本 RFC 推迟了定义完整协议,但Suspender
必须提供以下功能:- 列出硬件支持的挂起状态。
- 将硬件转换为暂停状态。
对于此设计,SAG 充当系统执行代码能力的调度器(或限制器),由 Fuchsia 挂起 HAL(实现上述 Suspender
协议)来实现,以将系统转换为挂起状态。为了适应这一概念,我们做出以下假设:
- 硬件平台是指一系列硬件和软件系统,可让计算设备执行此 RFC 中的代码。这通常包括 CPU、内存、操作系统以及这些组件正常运行所需的其他控制功能(时钟树、电源域等)。这明确不包括微控制器单元、无线射频、显示屏控制器、辅助存储设备(固态硬盘、eMMC)等传统外围组件。
- 所有希望支持硬件平台暂停的设备都必须包含电源代理组件。
- 在挂起期间,Fuchsia 组件(包括 SAG 本身)不会在 CPU 上执行。在微控制器或其他外围硬件上运行的固件可能会继续处理数据。当硬件平台进入暂停状态时,CPU 可能会离线,调度程序可能会更新其政策,外围设备可能会更改配置。
- Fuchsia 组件必须与电源拓扑结构(直接或间接)集成,以允许和/或阻止转换到暂停状态。通过这种集中式会计机制,SAG 无需知道这些组件的状态,即可了解系统的其余部分需要什么。
- 未与电源拓扑集成的 Fuchsia 组件不得预期不间断执行。这要求任何需要不间断执行以执行关键任务(例如从网络或外围设备接收数据)的组件都必须通过防止挂起中所述的方法之一直接或间接与电源框架交互,以应对硬件平台挂起。
- 在唤醒中断待处理期间,硬件平台不得暂停。这对所有驱动程序都很重要,因为它让驱动程序有机会处理其中断,无论其与电源框架的互动如何。在确认中断后需要执行更多处理的驱动程序必须与电源框架交互,以防止硬件平台挂起。
- SAG 必须可供感知电源的驱动程序和内核读取的第一个文件系统中存在的提前启动组件使用(例如 RFC-0167:早期用户空间引导中的软件包中的 bootfs)。否则,在 SAG 稍后推出之前,感知电源的组件将无法设置可防止系统挂起的电源配置。此外,在挂起转换期间,更高级别的文件系统可以配置为比更低级别文件系统中的驱动程序更早关闭。这会导致电源元素依赖项问题。
- SAG 将尽可能使用电源拓扑概念,将硬件平台推向最低功耗级别。最终,设备进入/保持此最低功耗级别的时长取决于产品行为和政策、环境条件以及用户行为。
设计
系统活动控制器由以下部分组成:
- 电源元素
- 用于初始化、状态管理和处理电源电平变化的业务逻辑。
- 一种 FIDL 服务,用于提供对有关暂停/恢复的统计信息的访问权限。
- FIDL 服务,可让客户端保持硬件平台处于唤醒状态,并在发生挂起/恢复转换时收到通知。
FIDL 服务的确切定义将推迟到 API 审核/校准会话。
电源拓扑
如需了解电源拓扑图惯例,请参阅 RFC-0250:电源拓扑。
SAG 会创建和管理一个电源元素 Execution State
,该元素表示硬件平台执行代码的能力。此电源元素会汇总来自其他组件的信号,以确定何时应尝试挂起转换。
通过创建电源元素,SAG 允许其他组件执行以下操作:
- 只要硬件平台持有断言声明,就提高其执行状态的电源级别
- 说明为什么硬件平台应通过电源元素及其依赖项链继续执行代码
- 通过持有机会性声明来响应执行状态的变化。这还允许 SAG 实现针对
Execution State
的每个依赖项的功耗级别变化产生副作用。 - 最重要的是,RFC-0250:电源拓扑要求电源元素趋向于其最低功耗级别。这自然会导致在没有任何依赖的功耗元素处于活动状态时,对硬件平台的执行状态执行管控操作。
执行状态
此电源元素与硬件平台执行代码的能力尽可能接近。它支持 3 个功率级别:
- 活跃
- 正在暂停
- “Inactive”(无效)
当硬件平台正常运行时,此元素应处于 Active
功耗级别。在 Inactive
功耗级别下,硬件平台应处于挂起状态或正在积极尝试转换到挂起状态。此时,只有设备中不感知电源或不依赖电源的部分应在运行。如需详细了解此设计模式,请参阅按执行状态约束设备。如需详细了解挂起的触发时间和方式,请参阅挂起/恢复。
Suspending
功耗级别介于 Inactive
和 Active
功耗级别之间。此功耗级别用于区分仅在硬件平台运行时允许运行的功耗依赖项,以及在硬件平台在暂停状态和运行状态之间转换(无论是哪个方向)时可能需要运行的功耗依赖项。请参阅下面的存储空间示例,了解这种区分在哪种情况下很有用。
设计模式
防止挂起
为了防止硬件平台暂停,组件可以构建一个对 Execution State
具有断言依赖项的电源元素。
假设某产品具有媒体播放器功能。产品所有者希望媒体播放功能能够防止硬件平台暂停,以便支持连续播放音乐。如需支持此功能,管理播放状态的组件可以创建对 Execution
State
的断言依赖项,以防止 SAG 触发挂起转换。
在上图中,Media Player 组件有一个名为“Playback”的 Power 元素。播放电源元素对 Execution State
的 Active
电源级别具有断言依赖项。当需要开始媒体播放时,Media Player 组件将请求 Playback
的 Active
功耗级别的租约,以防止硬件平台暂停。满足租约后,Media Player 组件可以运行媒体播放逻辑,而无需担心硬件平台意外挂起。
按执行状态约束设备
产品可以采用的一个强大模式是,根据硬件平台的执行状态来限制设备的电源级别。这可用于将外围设备功耗与硬件平台的挂起状态相关联。当硬件平台转换为暂停状态时,驱动程序可以关闭其设备或更改其配置。对于希望在硬件平台暂停时关闭特定功能或子系统以降低功耗的产品,此设置可能很有用。
音频示例
考虑使用功耗密集型音频硬件的设备。产品所有者只希望在硬件平台处于唤醒状态时激活音频硬件。产品所有者可以使用对 Execution State
具有机会依赖项的电源拓扑来表示此配置。
在上图中,音频驱动程序(在图中称为“音频”)有一个名为“电源”的电源元素。音频驱动程序对 Execution State
的 Active
功耗级别具有机会性依赖项。音频驱动程序可以通过向 Power Broker 请求租赁来监控其依赖项是否已满足。当 Execution State
转换为 Active
时,音频驱动程序对电源的租约将满足。此时,音频驱动程序可以运行激活音频硬件所需的任何逻辑。反之,当 Execution State
想要将其功耗级别从 Active
降低时,音频驱动程序的功耗租约就会失效。此时,音频驱动程序可以运行逻辑来停用音频硬件,然后再通知电源代理其电源元素已降低电源电平。
处理唤醒中断
当硬件平台处于暂停状态时,可以通过外部刺激来恢复该平台。这种外部刺激通常以某个外围组件引发的 CPU 中断的形式出现。为了正确处理唤醒中断,预计会发生以下情况:
- 驱动程序的唤醒矢量是在挂起之前的某个时间点编程的。
- 处理中断时:
- 如果驱动程序在端口上等待中断,内核会调度其中断处理程序线程 (IHT)。
- IHT 或由其通知的其他组件可以创建租约以阻止硬件平台暂停。
- 驱动程序会根据需要与硬件和/或其他组件通信,以处理中断。在此期间,其他组件可能会请求租约。
- 中断处理完成后,驱动程序会调用
zx_interrupt_ack
。
在处理中断时,SAG 可以随时运行,因为内核会恢复在硬件平台转换为挂起状态时被挂起的任务。
存储空间示例
请参阅按执行状态限制设备 中的音频示例。虽然存储硬件可能遵循与音频类似的模式(即在硬件平台暂停时通常会关闭),但在硬件平台转换为暂停或恢复以处理唤醒中断时,它也会关闭。如果当前已分页的组件需要在挂起之前关闭并执行清理操作,则可能会导致问题。由于关机操作的顺序不确定,这种简化的设计是不够的。
解决此缺点的一种方法是允许存储驱动程序在转换期间运行。
在上图中,存储驱动程序(称为“Storage”)具有两个电源元素:
- Power 对(执行状态、挂起)具有机会依赖项。当其他电源元素提高
Execution State
的电源级别时,此依赖项将得到满足。只要存储驱动程序在执行状态开机到Suspending
后持有电源租约,执行状态便无法降低其电源级别。必须执行此操作,才能让存储驱动程序监控何时应关闭电源。 - 唤醒请求对(执行状态、挂起)具有断言依赖项。此依赖项会强制
Execution State
提高其功率等级。当存储驱动程序收到存储请求时,它会租用此电源元素。这对于允许存储硬件开机(即使系统的其他部分正在关机)而言是必需的。
处理系统级转换
启动
首次启动 SAG 时,它不会触发暂停,直到系统完成启动过程。在此启动状态下,Execution State
电源元素应处于 Active
电源级别,以反映硬件平台正在积极运行且未尝试暂停的实际情况。
在此期间,其他组件可以创建影响 Execution State
的依赖项和租约;不过,在启动完成之前,Execution State
始终处于 Active
功耗级别。为了退出启动状态,必须通知 SAG 托管的 FIDL 服务已完成启动。当系统的更高层级可以表达其功耗需求时(例如,在可能进行用户互动的会话中),预计会使用此服务。
暂停/恢复
当 Execution State
功耗级别为 Inactive
(最低功耗级别)时,系统会请求挂起转换。在开始挂起转换之前,SAG 会通知已注册的监听器即将发生挂起。为了正确处理 SAG、Power Broker 和中断处理驱动程序之间的潜在争用,SAG 需要满足以下要求:
- 如果未确认唤醒中断,Fuchsia 挂起 HAL 必须返回错误。这可以防止在中断处理程序有机会请求租约并确认中断之前运行 SAG 的竞态情况。
- 在暂停请求处理期间,SAG 不得更改
Execution State
的电源级别。当 SAG 从暂停状态恢复时,Execution State
的功耗级别应始终为Inactive
。在转换为挂起状态之前和转换期间,依赖于Execution State
的设备会转换到并保持适当的电源级别。SAG 会延迟处理电源代理请求的电源级别更改,以“锁定”Execution State
的电源级别,从而确保这一点。 - 如果驱动程序需要在 ACK 中断之前执行工作,则驱动程序或中断处理程序必须先获取租约。
当硬件平台恢复执行时,SAG 会收到 Suspender
设备发送的响应,其中指明了挂起请求的结果。然后,SAG 会通知已注册的监听器暂停请求的结果。届时,监听器可以请求租约,以阻止硬件平台暂停。如需了解详情,请参阅防止挂起。
暂停请求也可能会在转换发生之前失败。这可能是由以下原因导致的:即将唤醒硬件平台的待处理中断,或者 Fuchsia 挂起 HAL 或内核中的其他错误。当挂起请求失败时,SAG 会通知监听器失败,并等待所有监听器确认通知。这种设置允许商品级组件请求租约并更改系统配置,以防止重复发送最终会失败的暂停请求。
如果在恢复转换期间没有监听器提高 Execution State
的电源级别,SAG 会记录此失败。如果监听器发生崩溃,或者产品没有有效(或不完整/处于开发中)的产品体验,就可能会出现这种情况。
关闭
当系统中运行的组件请求关闭或重启时,组件管理器会开始根据 capability 图表终止组件。这会导致以下问题:阻止硬件平台进入暂停状态的组件会在 SAG 之前终止。这会导致 SAG 在关闭期间错误地触发中止。
为解决此问题,负责协调关机的组件(shutdown-shim
和/或 power-manager
)必须持有一个租约,以使 Execution
State
保持在 Suspending
功耗级别。由于 shutdown-shim
和 power-manager
是重新启动前最后运行的组件之一,因此这可以防止错误的挂起。
实现
在完成完整实现之前,添加此功能需要进行许多单独的更改,并获得关键子系统的支持。这可分为以下步骤:
- 基本暂停支持
- 当
Execution State
变为Inactive
时触发挂起 - 在恢复时发送监听器通知。
- 连接用于接收会让系统保持唤醒状态的恢复通知的监听器。
- 当
- 将所有关键子系统连接到 SAG 接口,使其具有电源感知功能。
- 优化了挂起时间。
- 公开内核和/或 Fuchsia 挂起 HAL 中的中断和/或其他唤醒条件。
- 使用内核/Fuchsia 挂起 HAL 信号来延迟触发预计会失败的挂起请求。
- 持续集成其他支持暂停的子系统。
性能
对系统性能的总体影响在很大程度上取决于 Power Broker 的性能。SAG 的大多数客户端都会在初始化期间执行一次性调用,以设置依赖项,以便日后由 Power Broker 促成的互动是间接的。监听 SAG 事件的客户端会直接影响系统性能,因为它们必须确认已处理恢复和挂起失败通知。我们应密切监控这些事件处理脚本的延迟时间指标,以确保及时处理各产品中的恢复和暂停故障。最后,Fuchsia Suspend HAL 会报告触发挂起的延迟时间。我们应监控此延迟时间,以确保在各产品中及时完成挂起操作。这包括监控在发生挂起失败时撤消挂起请求的延迟时间和性能影响。
安全注意事项
RFC-0250:电源拓扑建立的电源框架定义了电源拓扑的安全模型。SAG 通过协议功能公开对电源元素的访问权限。通过访问此协议,其他电源元素可以依赖于 SAG 的电源元素。最终,SAG 安全性依赖于组件框架提供的保证来路由协议功能。
SAG 的协议功能依赖于 Fuchsia 挂起 HAL 和电源代理。如果这些组件中的行为与预期行为存在任何偏差,都可能会导致 SAG 实现出现异常行为。SAG 需要考虑缺失和行为异常的依赖项,以减少可能出现的级联负面影响。
注册监听器的客户可能会滥用此功能。恶意组件可能会通过不及时确认事件来阻止正确的暂停或恢复。您可以通过设置响应超时来避免此类问题。
隐私注意事项
SAG 预计不会收集任何个人身份信息;不过,SAG 会通过 FIDL 协议和 Inspect 收集和公开从暂停/恢复行为派生的数据。这些数据将在设备端以外的系统中汇总,以供产品所有者和 Fuchsia 工程师进行分析。这需要对实现进行隐私权审核。
测试
SAG 将通过一系列集成测试和端到端测试进行测试。集成测试将确保 SAG 在内部状态之间转换,并正确发送挂起请求。
客户端可以使用一组测试支持库来测试其实现,这些测试支持库使用 Power Broker 和 SAG,但移除了 Fuchsia Suspend HAL。借助此测试支持库,客户端可以调用 SAG 中的特定状态,以确保客户端组件对这些更改做出正确响应。这包括确保妥善处理由电源级别转换触发的所有副作用。依赖于 SAG 电源元素的组件的完整测试套件应包含以下场景:
- 无电源框架
- 在锁定的功率水平下,初始启动状态下的 SAG
Execution State
,电源等级为Active
Execution State
,电源等级为Suspending
Execution State
,电源等级为Inactive
- (如果适用)在关键操作期间不会暂停
文档
您需要提供大量文档来说明 SAG 在系统中的角色、配置(包括产品所有者的期望)、API 模式和测试支持库。该文档应包含有关操控 SAG 电源元素和正确使用其 API 的示例和最佳实践。示例应针对上文设计模式部分中列出的情况提供分步指南。
本文档应属于有关电源框架及其概念的一组更大文档的一部分。
缺点、替代方案和未知情况
实现此提案的缺点与电源框架的一般缺点类似。
用于触发暂停的信号是分散的。除非产品所有者整理组件以强制执行此模式,否则任何单个组件都无法保证此 API 会发生挂起。从 API 使用角度来看,这会导致系统行为模糊不清。例如,当对 Execution State
拥有租约的组件放弃租约时,如果其他组件拥有租约,SAG 可能不会暂停。组件只有通过向 SAG 注册监听器,才能知道挂起已触发,这会增加复杂性。
如果用户空间提供了恢复延迟时间要求,Fuchsia 应遵循相同的要求。如果未提供恢复延迟时间,Fuchsia 应以尽可能短的恢复延迟时间进入“挂起到空闲”状态。
由于平台目前仅支持一种暂停状态,因此本 RFC 不考虑此要求。
我们尚未确定现场驱动程序和硬件存在的所有可能的电源控制模式,因此随着这些模式的发现,此设计可能需要不断演变。这包括但不限于恢复延迟时间注意事项、支持更多挂起状态等。这些设计变更将根据需要在后续 RFC 中编码。