RFC-0198:Magma API

RFC-0198:Magma API
状态已接受
领域
  • 图形
说明

适用于 GPU 和其他计算加速器的驱动程序 API 设计。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-09-19
审核日期(年-月-日)2022-11-01

摘要

Magma 是 Fuchsia 的 GPU 驱动程序设计。它还可用于支持其他硬件计算加速器。此 RFC 是适用于 Magma FIDL 协议的 API 设计文档。

Magma 包含两个驱动程序组件:一个是加载到每个应用地址空间的硬件专用库(“客户端驱动程序”,有时称为“可安装的客户端驱动程序”或“ICD”);以及一个与硬件进行交互的 Magma 系统驱动程序。两个“驱动程序”之间的通信由 Magma 协议定义。

在本文档中,“应用”用于表示使用客户端驱动程序公开的 API 的软件组件。

设计初衷

Magma API 解决了在 Fuchsia 系统上支持硬件加速图形和计算 API(主要是 Vulkan)的问题。其 API 概念并非特定于 Vulkan,因此可减少支持其他客户端 API(例如适用于视频的 VA-API、OpenVX 和 OpenCL)的流畅性。

Magma 旨在供 Vulkan API 的实现使用。Vulkan 是 Fuchsia SDK 中提供的 C 样式 ABI。这些实现(“ICD”)通常由硬件供应商开发,因为加速器硬件大而复杂,而构建实现需要具备详细的硬件编程知识。

由于应用可能会直接使用 Vulkan,因此 ICD 是由系统提供的库,但无法访问硬件。使用 Magma,ICD 可以与加速器硬件进行交互,以满足 Vulkan API 的要求,该 API 主要包括执行客户端定义的程序。

Magma 系统驱动程序(“MSD”)通过在硬件上调度和执行客户端请求来实现此协议的服务器端。因此,Magma 旨在连接 ICD 和 MSD,其作用与 Linux 上的 DRM(直接渲染管理器)类似。

Magma 的目标是尽量减少 API 中供应商特定方面的程度。这样,您就可以更轻松地推断 API 安全性,并便于对驱动程序进行安全审核。

Magma 不让每个 GPU 供应商设计自己的 ICD-MSD 接口(就像在 Linux 上经常一样),而是提供了一套常用的核心 API 功能和方法;在必要情况下,Magma 支持特定于供应商的查询和命令结构。Magma 定义中未包含供应商细节,但驱动程序专用文档中已阐明。

对显示硬件的支持并不是一个目标。

有三个驱动程序正在生产环境中使用 Magma API。这些客户端驱动程序的构建和发布流程非常复杂,因为 Fuchsia SDK 中未提供这些 API。

在当前的所有情况下,系统都会使用客户端库来简化与 C 代码库的集成(C 是 Mesa 中的首选语言,它提供了许多开源图形驱动程序),并为虚拟化提供了一个方便的抽象层。在以后的练习中,会审核并可能将客户端库纳入 SDK。

利益相关方

教员

不适用

审核者

jbauman@、rlb@:硬件图形

咨询人员

API 委员会

社交

不适用

设计

Magma 有三个协议,定义位置如下:

https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/sdk/fidl/fuchsia.gpu.magma/magma.fidl

有些名称带有数字后缀(例如 BufferRangeOp2);数字后缀详细描述了协议的演变过程,可以忽略。

  1. 设备

在 Fuchsia 启动序列期间,Magma 系统驱动程序会针对能够加速图形和/或计算的每个物理设备进行实例化。获得适当的应用权限后,客户端可以扫描是否存在一个或多个“gpu”类设备并打开这些设备。可以通过设备协议执行同步查询来获取参数,这些参数有助于应用决定在哪种配置下使用哪些实体设备。查询参数还用于确定哪些类型的 ICD 与每种 GPU 设备兼容。驱动程序专用协议和设备专用协议的确切行为取决于这些查询参数。

当应用声明其打算使用特定实体设备时,便会与 Magma 系统驱动程序建立连接。例如,在 Vulkan 中,使用实体设备的意图是通过调用 vkCreateDevice() 来表示的。此连接为客户端驱动程序和系统驱动程序之间的所有进一步通信奠定了基础。

该连接由两个通道组成。主渠道用于主要协议,主要用于客户端-服务器方向,另一个渠道用于服务器到客户端的通知。

  1. 主要

主要协议包含少量采用前馈设计实现的核心功能。错误会触发一条唱片消息,然后关闭连接通道。

a) 导入共享资源、缓冲区和事件(ImportObject、ReleaseObject)

缓冲区是由 Zircon VMO 提供支持的共享内存对象。当 API 需要信号量时,可以使用 Zircon 事件进行同步。

对象通过其 KOID(内核对象 ID)进行分配和引用。客户端分配是一种前馈设计选择。这一假设所有缓冲区都来自系统内存,移动类硬件通常如此。

未来,对具有专用内存的桌面类 GPU 的支持可能需要更改 API。

未来对外部 Vulkan 时间轴信号量的支持可能需要导入新型内核对象。

b) 映射缓冲区(MapBufferGpu、UnmapBufferGpu、BufferRangeOp)

为了可供硬件访问,必须将该缓冲区映射到设备地址空间。每个客户端连接都会获得一个专用 GPU 地址空间(请参阅“安全和隐私”),因此 Magma 希望客户端执行设备地址空间管理。

对于某些驱动程序,MapBufferGpu 可能会暗示在设备 MMU 中填充页面表,而对于某些驱动程序,可以通过缓冲区范围操作明确控制页面表格填充。

缓冲区页面的提交隐含在页面表填充中。任何客户端页面停用操作都应通过相应的取消填充操作与系统驱动程序进行协调。

c) 创建执行环境(CreateContext、DestroyContext)

如需在硬件上执行工作,需要一个上下文。上下文包含允许将多个上下文切换到硬件所需的所有硬件状态,并且已安排由 Magma 系统驱动程序执行。Magma 支持每个连接使用多个上下文;这允许多个上下文共享一个地址空间。

d) 执行命令(ExecuteCommand、ExecuteImmediateCommands)

命令包含特定于供应商的数据,这些数据可以修改硬件状态并触发加速器计算核心上的代码执行。程序代码由应用提供给客户端驱动程序,通常采用与机器无关的格式(如 SPIR-V)。客户端驱动程序必须将代码转换为加速器硬件可以理解的机器级指令。

Magma 提供了两个用于执行命令的接口:

ExecuteCommand 假定程序代码和关联资源包含在共享缓冲区中。同步时会提供一系列等待信号量(必须在调度工作之前发出信号),以及当命令完成时发出信号的信号量。

ExecuteImmediateCommands 以内嵌方式发送命令。如果驱动程序定义了拆分命令的方式,则单个通道消息中可能会包含多个命令。目前,每条消息的命令字节数上限为 2k,这是任意限制,到目前为止有效,但不允许有效利用整个通道消息大小。提供的信号量可用于等待或发出信号,具体取决于关联的命令数据。

未来提交命令时的考虑因素包括:将 fuchsia.mem.Data 与临时 VMO 一起使用,或 Linux“io_uring”之类的模型:https://en.wikipedia.org/wiki/Io_uring

e) 流控制

为防止客户端将过多的消息推送到主通道,并防止主通道中待导入的缓冲区对象过度使用内存,设备协议会发布最大值,而主协议规定客户端应保留计数,并延迟发送消息以使这些计数小于已发布的最大值。服务器会提供事件消息,以便在计数可能减少时通知客户端。

f) 性能计数器

主要协议公开了许多专门用于与硬件计数器交互的 API,这些 API 对应用深入了解加速器硬件上运行的程序的行为和性能特征至关重要。

  1. 通知

通知渠道用于仅按反向(服务器-客户端)方向发送的消息,通常是在响应命令完成时发送。通知消息的内容往往因供应商而异,因此定义了一个空协议。

使用独立于主渠道的通知渠道可使客户端更轻松地处理通知事件,例如,客户端可以使用专用线程。在主通道上,客户端调用可以来自多个线程,其中没有任何循环在异步调度程序中进行轮询,而且出于性能方面的考虑,我们不想将这些调用代理到主通道中。这会使读取异步事件变得很困难(流控制事件除外,此类事件只需在发送消息期间被读取)。

未知

目前有四个受支持的 Magma 驱动程序(三个在生产环境中使用),另外两个驱动程序已完成原型设计。启动每个额外的 Magma 驱动程序可让您进一步了解 Magma 协议能否取代各种现有的基于 Linux 的客户端驱动程序内核驱动程序接口。增加对桌面类 GPU 的支持可确保核心 API 与各种硬件兼容。

可能需要改进的 API 领域主要包括:命令执行和通知处理。

非常感谢 API 委员会的反馈,特别是以下主题:

a) 这些 API 与其他 Fuchsia API 的相似之处或不同之处是什么? b) 是否有机会使这些 API 更具前瞻性? c) 您对 Fuchsia 的 io_uring 模型实用性有何想法?

Google 领域专家已对该 API 进行了简要审核;但让 Google 的其他专家/其他相关团队进行更彻底的审核可能更有益。

性能

设备协议包含同步方法,但这些方法只应在应用设置阶段使用。主要协议包含异步方法,而命令完成则通过通知渠道异步返回。

大多数数据在 VMO 中共享,因此最大限度地减少数据复制。创建和映射缓冲区可能速度很慢,但假定应用经过精心设计(例如执行内存子分配),这些操作很少发生。

在大多数情况下,在 Fuchsia 上,Magma 驱动程序的性能相当于在 Linux 和同一硬件上运行的同一客户端驱动程序代码库。

人体工学、易用性

API 设计与所研究的现有基于 Linux 的客户端驱动程序内核驱动程序接口类似,不同之处在于分配尽可能在客户端执行。

该 API 的语义被认为相当直观,因为该 API 已使用两年,在此期间进行了修改,并且目前正在生产环境中使用来自不同供应商的三个驱动程序。

将来,对于 Vulkan 时间轴信号量,新的内核对象可能会被视为必要;在这种情况下,可能会将其添加到 ObjectType 中,并且在“执行”API 中由 KOID 指定信号量时,可以引用“时间轴”对象来代替事件。

向后兼容性

FIDL 表已用在预计未来可扩展性的各种地方。

安全性

Magma API 可让应用针对重要的共享系统资源运行未验证的程序,因此安全性是一个重要的主题。已于 2021 年 6 月完成安全审核:请参阅 https://fxbug.dev/42146613。

客户端可能会提交长时间运行的程序,以拒绝其他客户端访问硬件。Magma 系统驱动程序可确保长时间运行的程序在中止时造成,系统中断程度类似于其他系统的行为,而这些中断的程度可接受

图形内存可能包含密码等敏感信息,因此请务必隔离客户端的内存访问。客户端连接通过独立的硬件地址空间相互隔离:也就是说,客户端的程序只能访问已导入到连接(由客户端创建或从外部明确接收)的内存缓冲区。这种方法存在潜在的硬件漏洞。

客户端数量可能会超过硬件提供的地址空间数量。MSD 应安排对这些资源的访问或完全拒绝客户端。

出于性能原因,验证客户端命令和程序并不现实,因此预计硬件具有弹性。

隐私权

通过查询 DEVICE_ID 提供的设备 ID 通常不是唯一的。

性能计数器事件可用于确定系统中其他工作负载的一组详细统计信息,这些统计信息可用于指纹识别其他进程正在执行的操作。因此,它们比大多数 Magma API 更受限制,并且只能用于访问 /dev/class/gpu-performance-counters 设备的设定进程。

测试

此处提供了 API 的简单功能测试:

https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/graphics/lib/magma/tests/integration/test_magma_fidl.cc

如果不包含硬件详细信息,可能很难编写使用 Magma API 的更复杂的测试。客户端驱动程序代码包含这些硬件编程详情,因此使用客户端驱动程序公开的 API 的测试套件至关重要。

我们在持续集成中针对两个正式版 Magma 驱动程序对 Vulkan 一致性测试进行了测试。OpenVX 一致性测试在用于机器学习的 Magma 驱动程序上运行。

请注意,在构建 Magma 驱动程序时,开发者应先构建一个能够实现 Magma 协议的服务器端的功能性 Magma 系统驱动程序,然后才能测试使用 Magma API 的客户端驱动程序代码。

文档

文档采用 FIDL 定义。

缺点、替代方案和问题

此设计与 Vulkan 同步,后者旨在最大限度地减少驱动程序开销并最大限度地提高系统图形性能。该设计的一个缺点是,为安全起见,它在很大程度上依赖于硬件,而替代设计可能会尝试提供客户端命令验证。然而,验证却比较复杂、不完美,并且很可能会有昂贵的性能成本。

现有艺术和参考资料

Linux GPU 驱动程序开发者指南:https://www.kernel.org/doc/html/v4.18/gpu/index.html