I915 VM_BIND 特性设计和用例¶
VM_BIND 特性¶
DRM_I915_GEM_VM_BIND/UNBIND ioctl 允许 UMD 在指定的地址空间 (VM) 的指定 GPU 虚拟地址上绑定/解绑 GEM 缓冲区对象 (BO) 或 BO 的部分。这些映射(也称为持久映射)将在由 UMD 发出的多个 GPU 提交(execbuf 调用)中保持持久性,而无需用户在每次提交期间提供所有必需映射的列表(旧 execbuf 模式所需)。
VM_BIND/UNBIND 调用允许 UMD 请求时间线输出栅栏,以指示绑定/解绑操作的完成。
VM_BIND 特性通过 I915_PARAM_VM_BIND_VERSION 向用户发布。用户必须在 VM 创建期间通过 I915_VM_CREATE_FLAGS_USE_VM_BIND 扩展选择地址空间 (VM) 的 VM_BIND 绑定模式。
在不同的 CPU 线程上并发执行的 VM_BIND/UNBIND ioctl 调用没有顺序。此外,当指定了有效的输出栅栏时,VM_BIND/UNBIND 操作的部分可以异步完成。
VM_BIND 特性包括
多个虚拟地址 (VA) 映射可以映射到对象的相同物理页面(别名)。
VA 映射可以映射到 BO 的一部分(部分绑定)。
支持在 GPU 错误时捕获转储中的持久映射。
支持 userptr gem 对象(无需特殊的 uapi)。
TLB 刷新注意事项¶
i915 驱动程序为每次提交刷新 TLB,并在释放对象的页面时刷新 TLB。VM_BIND/UNBIND 操作不会执行任何额外的 TLB 刷新。任何添加的 VM_BIND 映射都将位于该 VM 的后续提交的工作集中,并且不会位于当前正在运行的批处理的工作集中(这将需要额外的 TLB 刷新,这是不支持的)。
VM_BIND 模式下的 Execbuf ioctl¶
VM_BIND 模式下的 VM 不支持旧的 execbuf 绑定模式。VM_BIND 模式下的 execbuf ioctl 处理与旧的 execbuf2 ioctl 有很大不同(参见 struct drm_i915_gem_execbuffer2
)。因此,添加了一个新的 execbuf3 ioctl 来支持 VM_BIND 模式。(参见 struct drm_i915_gem_execbuffer3
)。execbuf3 ioctl 不接受任何 execlist。因此,不支持隐式同步。预计以下工作将能够支持所有用例中的对象依赖关系设置要求
“dma-buf: 添加用于导出同步文件的 API”(https://lwn.net/Articles/859290/)
新的 execbuf3 ioctl 仅在 VM_BIND 模式下工作,VM_BIND 模式仅适用于 execbuf3 ioctl 进行提交。在 execbuf3 调用时映射到该 VM 上的所有 BO(通过 VM_BIND 调用)都被视为该提交所需的。
execbuf3 ioctl 直接指定批处理地址,而不是像 execbuf2 ioctl 中那样指定对象句柄。execbuf3 ioctl 也不支持许多旧功能,如 in/out/submit 栅栏、栅栏数组、默认 gem 上下文等(参见 struct drm_i915_gem_execbuffer3
)。
在 VM_BIND 模式下,VA 分配完全由用户管理,而不是由 i915 驱动程序管理。因此,所有 VA 分配、驱逐在 VM_BIND 模式下均不适用。此外,对于确定对象活动性,VM_BIND 模式将不使用 i915_vma 活动引用跟踪。它将改为使用 dma-resv 对象(参见 VM_BIND dma_resv 用法)。
因此,许多支持 execbuf2 ioctl 的现有代码(如重定位、VA 驱逐、vma 查找表、隐式同步、vma 活动引用跟踪等)不适用于 execbuf3 ioctl。因此,所有 execbuf3 特定的处理都应该在一个单独的文件中,只有这些 ioctl 共有的功能才能尽可能地成为共享代码。
VM_PRIVATE 对象¶
默认情况下,BO 可以映射到多个 VM,也可以 dma-buf 导出。因此,这些 BO 被称为共享 BO。在每次 execbuf 提交期间,请求栅栏必须添加到映射到 VM 上的所有共享 BO 的 dma-resv 栅栏列表中。
VM_BIND 特性引入了一种优化,即用户可以在 BO 创建期间通过 I915_GEM_CREATE_EXT_VM_PRIVATE 标志创建一个 VM 私有的 BO。与共享 BO 不同,这些 VM 私有 BO 只能映射到它们私有的 VM 上,并且不能 dma-buf 导出。VM 的所有私有 BO 共享 dma-resv 对象。因此,在每次 execbuf 提交期间,它们只需要更新一个 dma-resv 栅栏列表。因此,快速路径(其中所需的映射已经绑定)提交延迟是关于 VM 私有 BO 数量的 O(1)。
VM_BIND 锁定层次结构¶
此处的锁定设计支持旧的(基于 execlist)execbuf 模式、新的 VM_BIND 模式、带 GPU 页面错误的 VM_BIND 模式以及可能的未来系统分配器支持(参见 共享虚拟内存 (SVM) 支持)。旧的 execbuf 模式和新的无页面错误的 VM_BIND 模式使用 dma_fence 管理后备存储的驻留。带页面错误的 VM_BIND 模式和系统分配器支持根本不使用任何 dma_fence。
VM_BIND 锁定顺序如下。
Lock-A:vm_bind 互斥锁将保护 vm_bind 列表。此锁在 vm_bind/vm_unbind ioctl 调用、execbuf 路径以及释放映射时获取。
将来,当支持 GPU 页面错误时,我们可以潜在地使用 rwsem 代替,以便多个页面错误处理程序可以获取读取侧锁以查找映射,因此可以并行运行。旧的 execbuf 绑定模式不需要此锁。
Lock-B:对象的 dma-resv 锁将保护 i915_vma 状态,需要在异步工作程序中绑定/解绑 vma 时以及更新对象的 dma-resv 栅栏列表时持有。请注意,VM 的私有 BO 将共享一个 dma-resv 对象。
未来的系统分配器支持将使用 HMM 规定的锁定。
Lock-C:spinlock/s 用于保护某些 VM 的列表,如因驱逐和 userptr 失效而失效的 vma 列表等。
当支持 GPU 页面错误时,execbuf 路径不会获取任何这些锁。在那里,我们将简单地将新的批处理缓冲区地址粉碎到环中,然后告诉调度程序运行它。获取锁仅发生在页面错误处理程序中,我们在读取模式下获取 lock-A,无论我们需要哪个 lock-B 才能找到后备存储(gem 对象的 dma_resv 锁和系统分配器的 hmm/core mm)以及一些额外的锁 (lock-D) 用于处理页表竞争。页面错误模式不应需要操作 vm 列表,因此永远不需要 lock-C。
VM_BIND LRU 处理¶
我们需要确保 VM_BIND 映射的对象被正确地 LRU 标记,以避免性能下降。我们还需要支持 VM_BIND 对象的批量 LRU 移动,以避免 execbuf 路径中的额外延迟。
页表页面类似于 VM_BIND 映射的对象(参见 可驱逐的页表分配),并且每个 VM 维护,并且需要在 VM 激活时(即,在调用带有该 VM 的 execbuf 时)固定在内存中。因此,也需要页表页面的批量 LRU 移动。
VM_BIND dma_resv 用法¶
需要将栅栏添加到所有 VM_BIND 映射的对象。在每次 execbuf 提交期间,它们都使用 DMA_RESV_USAGE_BOOKKEEP 用法添加,以防止过度同步(参见 enum dma_resv_usage
)。可以在显式对象依赖关系设置期间使用 DMA_RESV_USAGE_READ 或 DMA_RESV_USAGE_WRITE 用法覆盖它。
请注意,DRM_I915_GEM_WAIT 和 DRM_I915_GEM_BUSY ioctl 不检查 DMA_RESV_USAGE_BOOKKEEP 用法,因此不应用于批处理结束检查。相反,execbuf3 输出栅栏应用于批处理结束检查(参见 struct drm_i915_gem_execbuffer3
)。
此外,在 VM_BIND 模式下,使用 dma-resv apis 来确定对象活动性(参见 dma_resv_test_signaled()
和 dma_resv_wait_timeout()
),不要使用已弃用的旧 i915_vma 活动引用跟踪。这应该更容易与当前的 TTM 后端一起工作。
Mesa 用例¶
VM_BIND 可以潜在地减少 Mesa 中的 CPU 开销(Vulkan 和 Iris),从而提高 CPU 密集型应用程序的性能。它还允许我们实现 Vulkan 的稀疏资源。随着 GPU 硬件性能的提高,减少 CPU 开销变得更具影响力。
其他 VM_BIND 用例¶
长时间运行的计算上下文¶
dma-fence 的使用期望它们在合理的时间内完成。另一方面,计算可能会长时间运行。因此,计算使用用户/内存栅栏是合适的(参见 用户/内存栅栏),并且 dma-fence 的使用必须仅限于内核内部使用。
在 GPU 页面错误不可用的情况下,内核驱动程序将在缓冲区失效时启动长时间运行的上下文的挂起(抢占),完成失效,重新验证 BO,然后恢复计算上下文。这是通过使用每个上下文的抢占栅栏来完成的,该栅栏在有人尝试等待它时启用并触发上下文抢占。
用户/内存栅栏¶
用户/内存栅栏是一个 <地址,值> 对。要指示用户栅栏,指定的值将被写入指定的虚拟地址并唤醒等待进程。用户栅栏可以由 GPU 或内核异步工作程序指示(例如绑定完成时)。用户可以使用新的用户栅栏等待 ioctl 等待用户栅栏。
这是关于此的一些先前工作:https://patchwork.freedesktop.org/patch/349417/
低延迟提交¶
允许计算 UMD 直接提交 GPU 作业,而不是通过 execbuf ioctl。这是通过 VM_BIND 未与 execbuf 同步来实现的。VM_BIND 允许绑定/解绑直接提交的作业所需的映射。
调试器¶
通过调试事件接口,用户空间进程(调试器)能够跟踪并作用于由另一个进程(被调试)创建并通过 vm_bind 接口附加到 GPU 的资源。
GPU 页面错误¶
GPU 页面错误(如果将来支持)将仅在 VM_BIND 模式下支持。虽然旧的 execbuf 模式和新的 VM_BIND 绑定模式都需要使用 dma-fence 来确保驻留,但 GPU 页面错误模式(如果支持)将不使用任何 dma-fence,因为驻留完全通过安装和删除/使页表条目无效来管理。
页面级别提示设置¶
VM_BIND 允许每个映射设置任何提示,而不是每个 BO。子 BO 级别的位置提示对于即将到来的 GPU 按需页面错误支持将更重要。
页面级别缓存/CLOS 设置¶
VM_BIND 允许每个映射设置缓存/CLOS,而不是每个 BO。
可驱逐的页表分配¶
使页表分配可驱逐,并以类似于 VM_BIND 映射对象的方式管理它们。页表页面类似于 VM 的持久映射(此处的区别在于页表页面将没有 i915_vma 结构,并且在交换页面回来后,需要更新父页面链接)。
VM_BIND UAPI¶
I915_PARAM_VM_BIND_VERSION
支持的 VM_BIND 特性版本。参见 typedef drm_i915_getparam_t
参数。
指定支持的 VM_BIND 特性版本。已定义以下 VM_BIND 版本
0:不支持 VM_BIND。
- 1:在 VM_UNBIND 调用中,UMD 必须指定先前使用 VM_BIND 创建的确切映射,ioctl 将不支持解绑多个映射或拆分它们。同样,VM_BIND 调用不会替换任何现有映射。
2:取消了对解绑部分或多个映射的限制
- 。同样,绑定将替换给定范围内的任何映射。
参见
struct drm_i915_gem_vm_bind
和struct drm_i915_gem_vm_unbind
。
I915_VM_CREATE_FLAGS_USE_VM_BIND
在 VM 创建期间选择 VM_BIND 绑定模式的标志。参见 struct drm_i915_gem_vm_control
标志。
旧的 execbuf2 ioctl 不支持 VM_BIND 模式的操作。对于 VM_BIND 模式,我们有新的 execbuf3 ioctl,它不接受任何 execlist(有关更多详细信息,请参见 struct drm_i915_gem_execbuffer3
)。
struct drm_i915_gem_timeline_fence¶
-
输入或输出时间线栅栏。
定义
成员:
struct drm_i915_gem_timeline_fence {
__u32 handle;
__u32 flags;
#define I915_TIMELINE_FENCE_WAIT (1 << 0);
#define I915_TIMELINE_FENCE_SIGNAL (1 << 1);
#define __I915_TIMELINE_FENCE_UNKNOWN_FLAGS (-(I915_TIMELINE_FENCE_SIGNAL << 1));
__u64 value;
};
句柄
用户的 drm_syncobj 句柄,用于等待或发出信号。
标志
支持的标志是
I915_TIMELINE_FENCE_WAIT:在操作之前等待输入栅栏。
I915_TIMELINE_FENCE_SIGNAL:返回作为输出的操作完成栅栏。
值
时间线中的一个点。对于二进制 drm_syncobj,值必须为 0。时间线 drm_syncobj 的值为 0 无效,因为它将 drm_syncobj 转换为二进制。
描述
操作将等待输入栅栏发出信号。
返回的输出栅栏将在操作完成后发出信号。
struct drm_i915_gem_vm_bind¶
-
要绑定的 VA 到对象映射。
vm_id
成员:
struct drm_i915_gem_vm_bind {
__u32 vm_id;
__u32 handle;
__u64 start;
__u64 offset;
__u64 length;
__u64 flags;
#define I915_GEM_VM_BIND_CAPTURE (1 << 0);
struct drm_i915_gem_timeline_fence fence;
__u64 extensions;
};
句柄
要绑定的 VM(地址空间)id
对象句柄
用户的 drm_syncobj 句柄,用于等待或发出信号。
开始
要绑定的虚拟地址起始
偏移量
要绑定的对象中的偏移量
长度
要绑定的映射长度
I915_GEM_VM_BIND_CAPTURE:在 GPU 错误时捕获转储中的此映射。
支持的标志是
I915_TIMELINE_FENCE_WAIT:在操作之前等待输入栅栏。
请注意,栅栏 带有自己的标志。
栅栏
用于绑定完成信号的时间线栅栏。
时间线栅栏的格式为
struct drm_i915_gem_timeline_fence
。它是一个输出栅栏,因此使用 I915_TIMELINE_FENCE_WAIT 标志无效,并且将返回错误。
如果未设置 I915_TIMELINE_FENCE_SIGNAL 标志,则不请求输出栅栏,并且同步完成绑定。
扩展
以零结尾的扩展链。
用于未来的扩展。参见
struct i915_user_extension
。此结构传递给 VM_BIND ioctl,并指定 GPU 虚拟地址 (VA) 范围到对象部分的映射,该映射应绑定在指定地址空间 (VM) 的设备页表中。指定的 VA 范围必须是唯一的(即,当前未绑定),并且可以映射到整个对象或对象的一部分(部分绑定)。可以创建多个 VA 映射到对象的同一部分(别名)。
操作将等待输入栅栏发出信号。
开始、偏移量 和 长度 必须与 4K 页面对齐。但是,DG2 的设备本地内存的页面大小为 64K,并具有紧凑的页表。在该平台上,对于绑定设备本地内存对象,开始、偏移量 和 长度 必须与 64K 对齐。此外,UMD 不应在同一 2M 范围内混合本地内存 64K 页面和系统内存 4K 页面绑定。
如果 开始、偏移量 和 长度 未正确对齐,则将返回错误代码 -EINVAL。在版本 1 中(参见 I915_PARAM_VM_BIND_VERSION),如果无法保留指定的 VA 范围,则将返回错误代码 -ENOSPC。
在不同的 CPU 线程上并发执行的 VM_BIND/UNBIND ioctl 调用没有顺序。此外,如果指定了有效的 栅栏,则可以异步完成 VM_BIND 操作的部分。
struct drm_i915_gem_vm_unbind¶
-
要解绑的 VA 到对象映射。
rsvd
成员:
struct drm_i915_gem_vm_unbind {
__u32 vm_id;
__u32 rsvd;
__u64 start;
__u64 length;
__u64 flags;
struct drm_i915_gem_timeline_fence fence;
__u64 extensions;
};
句柄
要绑定的 VM(地址空间)id
对象句柄
保留,MBZ
要解绑的虚拟地址起始
要绑定的虚拟地址起始
要解绑的映射长度
要绑定的映射长度
当前保留,MBZ。
支持的标志是
用于解绑完成信号的时间线栅栏。
栅栏
用于绑定完成信号的时间线栅栏。
如果未设置 I915_TIMELINE_FENCE_SIGNAL 标志,则不请求输出栅栏,并且同步完成解绑。
它是一个输出栅栏,因此使用 I915_TIMELINE_FENCE_WAIT 标志无效,并且将返回错误。
如果未设置 I915_TIMELINE_FENCE_SIGNAL 标志,则不请求输出栅栏,并且同步完成绑定。
此结构传递给 VM_UNBIND ioctl,并指定应从指定地址空间 (VM) 的设备页表中解绑的 GPU 虚拟地址 (VA) 范围。VM_UNBIND 将强制从设备页表中解绑指定的范围,而无需等待任何 GPU 作业完成。UMD 有责任确保在调用 VM_UNBIND 之前不再使用该映射。
以零结尾的扩展链。
用于未来的扩展。参见
struct i915_user_extension
。此结构传递给 VM_BIND ioctl,并指定 GPU 虚拟地址 (VA) 范围到对象部分的映射,该映射应绑定在指定地址空间 (VM) 的设备页表中。指定的 VA 范围必须是唯一的(即,当前未绑定),并且可以映射到整个对象或对象的一部分(部分绑定)。可以创建多个 VA 映射到对象的同一部分(别名)。
操作将等待输入栅栏发出信号。
如果找不到指定的映射,ioctl 将简单地返回,而不产生任何错误。
在不同的 CPU 线程上并发执行的 VM_BIND/UNBIND ioctl 调用没有顺序。此外,如果指定了有效的 栅栏,则可以异步完成 VM_UNBIND 操作的部分。
struct drm_i915_gem_execbuffer3¶
-
DRM_I915_GEM_EXECBUFFER3 ioctl 的结构。
ctx_id
成员:
struct drm_i915_gem_execbuffer3 {
__u32 ctx_id;
__u32 engine_idx;
__u64 batch_address;
__u64 flags;
__u32 rsvd1;
__u32 fence_count;
__u64 timeline_fences;
__u64 rsvd2;
__u64 extensions;
};
句柄
上下文 id
仅允许具有用户引擎映射的上下文。
engine_idx
引擎索引
由 ctx_id 指定的上下文的用户引擎映射中的索引。
batch_address
批处理 gpu 虚拟地址/es。
对于正常提交,它是批处理缓冲区的 gpu 虚拟地址。对于并行提交,它是一个指向批处理缓冲区 gpu 虚拟地址数组的指针,数组大小等于参与该提交的(并行)引擎的数量(参见
struct i915_context_engines_parallel_submit
)。当前保留,MBZ
支持的标志是
rsvd1
fence_count
要解绑的虚拟地址起始
timeline_fences 数组中的栅栏数。
timeline_fences
指向时间线栅栏数组的指针。
时间线栅栏的格式为
struct drm_i915_gem_timeline_fence
。rsvd2
DRM_I915_GEM_EXECBUFFER3 ioctl 仅在 VM_BIND 模式下工作,VM_BIND 模式仅适用于此 ioctl 进行提交。参见 I915_VM_CREATE_FLAGS_USE_VM_BIND。
要解绑的虚拟地址起始
以零结尾的扩展链。
用于未来的扩展。参见
struct i915_user_extension
。此结构传递给 VM_BIND ioctl,并指定 GPU 虚拟地址 (VA) 范围到对象部分的映射,该映射应绑定在指定地址空间 (VM) 的设备页表中。指定的 VA 范围必须是唯一的(即,当前未绑定),并且可以映射到整个对象或对象的一部分(部分绑定)。可以创建多个 VA 映射到对象的同一部分(别名)。
操作将等待输入栅栏发出信号。
struct drm_i915_gem_create_ext_vm_private¶
-
使对象对指定 VM 私有的扩展。
base
成员:
struct drm_i915_gem_create_ext_vm_private {
#define I915_GEM_CREATE_EXT_VM_PRIVATE 2;
struct i915_user_extension base;
__u32 vm_id;
};
句柄
扩展链接。参见
struct i915_user_extension
。VM 的 Id,对象是私有的
要绑定的 VM(地址空间)id
操作将等待输入栅栏发出信号。
©内核开发社区。| 由 Sphinx 5.3.0 & Alabaster 0.7.16 提供支持 | 页面来源