RFC-0091 - zx_system_get_event ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY

RFC-0091:zx_system_get_event ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY
状态已接受
领域
  • 内核
说明

提议向“zx_system_get_event()”系统调用添加新事件“ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY”。

问题
  • 73872
Gerrit 更改
  • 514760
作者
审核人
提交日期(年-月-日)2021-04-12
审核日期(年-月-日)2021-05-04

总结

此 RFC 提议向 zx_system_get_event() 系统调用添加新的事件类型 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY。新的内核事件会在 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 之前发出信号,以便捕获靠近 OOM 点的内存诊断。

设计初衷

当系统几乎耗尽可用物理内存,能够满足内存分配请求时,ZX_SYSTEM_EVENT_OUT_OF_MEMORY 会发出信号。driver_manager 进程会等待此 OOM 事件,并在收到信号时请求 fshost 关闭文件系统,以便尽可能彻底地重新启动设备。不过,此时并不存在可捕获有意义的内存状态的良好机制,这对于导致 OOM 的根本原因至关重要。

单纯等待 OOM 事件,并尝试在 OOM 点写出内存报告是不可行的,因为这会导致文件系统关闭出现争用。因此,此 RFC 提议公开一个新事件 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY,该事件会在尽可能接近 OOM 的位置收到信号,同时尝试在 OOM 之前留出一些余量,以便可靠地写出内存报告。ZX_SYSTEM_EVENT_OUT_OF_MEMORY例如,如果在系统可用内存级别下降到 50MB 时 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 发出信号,则 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY 可能会在有 60MB 可用内存时发出信号。

此外,从长远来看,我们还希望对 OOM 进行有序关闭,这将涉及更高级别的用户空间组件(而不是 driver_manager)等待 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 事件,并关闭某些关键组件以及文件系统。这是一个规模较大的项目,届时我们将必须重新访问 OOM 事件信号和报告代码路径。因此,此 RFC 中的方案可以视为一个中间步骤,只需对现有设计做出细微更改。memory_monitor 进程已经在等待正常事件、警告和严重事件,并在必要时生成内存报告,因此可以轻松地进行扩展以等待即将发生的 OOM 事件。如果报告生成操作是通过在 OOM 上依序关停来处理的,将来可能会移除此事件;如果报告提供了额外的价值,我们可能会决定保留此事件。

设计

内核内存回收系统根据三种内存水印(警告、严重和 OOM)发出内存压力事件信号。该逻辑可以轻松扩展,以便在“严重”和“OOM”之间包含新的即将出现的 OOM 水印。您可以通过内核命令行选项配置 Imminent-OOM 和 OOM 水印之间的增量。

为了与现有的内存水印(也可以通过内核命令行配置)保持一致,此增量将是内存的绝对大小(以 MB 为单位)。这也意味着,单个值可能不适用于所有平台,并且需要微调,而这也是现有内存水印共有的属性。此外,生成内存报告本身需要一定量的内存,在为此增量选择值时,还应考虑内存报告。

zx_system_get_event() 支持的其他内核事件一样,将需要根作业的句柄。与 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 不同,ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY 不需要 ZX_RIGHT_MANAGE_PROCESS 权限。这会使新事件类似于 ZX_SYSTEM_EVENT_MEMORY_PRESSURE_NORMALZX_SYSTEM_EVENT_MEMORY_PRESSURE_WARNINGZX_SYSTEM_EVENT_MEMORY_PRESSURE_CRITICAL,这也不需要 ZX_RIGHT_MANAGE_PROCESS 权限。换言之,“正常”“警告”“严重”和“紧急 OOM 事件”可以使用 RootJobForInspect 协议,而 OOM 事件则需要使用 RootJob 协议。

在内核中实现只需对现有内存回收逻辑稍做更改即可。我们只需向传递给 pmm_init_reclamation() 的水印列表添加另一个水印。Imminent-OOM 级别与其他内存压力级别不同的唯一方面是,它不会在内核中触发任何内存回收(逐出分页器支持的内存和可舍弃内存)。该级别仅用于一个诊断级别;此时触发内存回收会改变事件最初要捕获的内存状态。因此,这个新事件在 fuchsia.memorypressure 协议中将不会有相应的信号,该信号用于在用户空间中推动内存回收。

实现

zx_system_get_event() 系统调用可以在单个 CL 中扩展;现有内核事件的 Waiter 不会受到此更改的影响。新事件的 Waiter 稍后可以在单独的 CL 中采用它。

性能

新事件不会影响现有事件的 Waiter 的性能。此外,在检索事件句柄和等待事件句柄方面,新事件预计也具有与现有事件类似的性能特征。用于发送事件信号的内核性能也与现有逻辑类似 - 当可用内存级别发生变化时,PMM 系统会查找最接近的内存水印来推断内存压力级别;我们提议的只是添加新水印,而不更改现有逻辑的其余部分。

工效学设计

无。

向后兼容性

无。

安全注意事项

无。

隐私注意事项

无。

测试

将编写 Zircon 核心测试,该测试会检索并等待 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY。采用事件时,系统也会编写用于验证客户端行为的单元测试。

文档

需要更新 zx_system_get_event() 的系统调用文档。内核概念文档中还会添加一个条目,说明各种内存压力级别的动机、每个内存压力级别的预期响应,以及这些级别与系统其余部分的关联方式。

缺点、替代方案和未知情况

缺点:内存报告可能不准确

由于事件在 OOM 之前收到信号,因此捕获的内存状态不会与 OOM 完全一致。不过,只要 OOM 水印的增量足够小(几十 MB),就应该仍然有助于诊断 OOM。

我们可能会出现在生成报告后没有 OOM 的情况,例如,设备在发生紧急 OOM 事件后以某种方式恢复。虽然此类报告不会发生 OOM 事件,但内存数据仍然非常有用,因为它仍表明内存用量增加,值得研究。

在内存分配快速达到峰值的情况下,事件的 Waiter 也可能无法生成报告。仍必须通过在本地重现问题并并行收集内存指标来诊断此类情况。报告应该仍能够捕获大多数 OOM 的内存诊断,因为快速分配峰值的情况很少见。

替代方案 1:使用现有事件,而不是新事件

ZX_SYSTEM_EVENT_OUT_OF_MEMORY 不能用于可靠地写出内存报告。这是因为 OOM 事件用于推动文件系统关闭,因此我们可能无法及时写出报告。

可以通过以下方式改变这种交互:将 OOM 信号处理从 driver_manager 移至另一个可以更有序地关闭的用户空间组件 - 先写出报告,然后关闭文件系统。此方法需要进行一些同步,以确保在文件系统关闭之前成功写出报告。这可能还要求我们在发出 OOM 信号后放宽 OOM 水印和重新启动延迟间隔,因为现在我们会在收到 OOM 事件信号时执行更多工作。对 OOM 信号处理方式的这种更改与有序关闭 OOM 所做工作的更大工作相关(在“动机”部分中进行了简要说明),这是未来可能要开展的一项更大范围的工作。

在 OOM 之前收到信号的另一个现有事件是 ZX_SYSTEM_EVENT_MEMORY_PRESSURE_CRITICAL,我们使用它来写入内存报告。不过,严重内存水印距离 OOM 水印足够远,因此这些报告可能会错过更接近 OOM 的重要内存状态变化。

替代方案 2:使用更丰富的 API 提供更多诊断事件

我们可以用替代 API 来指定要接收通知的多个自定义诊断内存级别,而不是在 OOM 附近公开特殊事件。这样可以实现更灵活的 API,并且将来更容易扩展。不过,目前还不存在可表明此类 API 会派上用场的具体用例。

可能有助于捕获诊断信息的其他内存压力级别为“警告”和“严重”。对于这些级别,我们可以直接使用表明级别变化的内核事件。我们已经针对“关键级别”进行了这项更改OOM 级别在这方面比较特殊,因为无法在 OOM 时准确捕获诊断。在理想情况下,我们希望在 OOM 点捕获状态。由于这不可能,我们需要另一个足够接近 OOM 的信号才能捕获相关状态,但又不能太近,以至于我们遇到类似的问题,无法编写报告。

早期技术和参考资料

zx_system_get_event 文档介绍了内核内存事件的工作原理。fuchsia.memorypressure 文档描述了基于内核事件构建的用户空间内存压力信号。