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 的要求,后者主要由执行客户端定义的程序组成。

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

Magma 的目标是从实际角度最大限度地减少 API 中供应商专用方面的程度。这样可以更轻松地推理 API 安全性,并简化驱动程序的安全审核。

Magma 提供了一组常用的核心 API 功能和方法,而不是让每个 GPU 供应商都设计自己的 ICD-MSD 接口(Linux 上通常是这种情况)。Magma 还允许在必要时使用供应商专有的查询和命令结构。Magma 定义不包含供应商具体信息,但会在特定于驱动程序的文档中加以说明。

不支持显示硬件。

Magma API 目前在生产环境中由三位驱动程序使用。由于 Fuchsia SDK 中不提供该 API,因此这些客户端驱动程序的构建和发布流程非常复杂。

对于目前的所有情况,都使用了客户端库,该库有助于与 C 代码库(C 是 Mesa 中的首选语言,提供许多开源图形驱动程序)集成,并为虚拟化提供了方便的抽象层。我们将在日后对客户端库进行审核,并考虑是否将其纳入 SDK。

利益相关方

教员

不适用

Reviewers:

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 支持的共享内存对象。Zircon 事件可用于在 API 预期使用信号量时进行同步。

对象由客户端分配,并通过其 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) 对 io_uring 模型对 Fuchsia 的实用性有何看法?

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