☰
第八章 GPU 调度器:8.1 命令提交的演进
2026/11/5 2:04:26 网站建设 项目流程

1.4 节说明了命令提交的硬件机制:CPU 将命令写入命令缓冲区,在 ring 中写入指向它的包并写入 doorbell,命令处理器从占用硬件队列槽位的队列中取包执行。硬件只规定命令以何种格式、经何种途径到达命令处理器;命令中的地址如何确定、命令访问的内存如何保持可用、作业之间如何同步、由谁写入 ring,均由软件决定。

一次提交涉及四项信息:命令所在的位置、命令访问的 BO、执行前需要等待的工作、完成时需要通知的对象。传统形态中,用户态经 ioctl 把这些信息交给内核,由内核完成接收、等待、下发与完成通知;若队列直接向用户态开放,用户态即可自行向 ring 写入包并写入 doorbell,内核不再逐次参与提交。从早期的 radeon、i915 到当前的 amdgpu、Xe、panthor,提交接口与内核实现经历了多次变化,这些变化同时沿四个方向进行:寻址(地址如何确定)、就位(BO 如何保证就位)、同步(作业之间如何同步)、仲裁(由谁仲裁并写入 ring)。本节说明这四个方向的演进及其相互关系,作为第 8 至 11 章的主线。

各种形态以不同方式使用 1.4 节中的队列,由此产生硬件队列、用户态队列与软件队列等名称,同一个“队列”在不同语境中所指不同。表 8.1.1 汇总与提交相关的对象,前四项由硬件定义,后三项是软件层面的概念,第 8 至 11 章均按此使用。

表 8.1.1 与提交相关的对象
对象说明
命令缓冲区存放作业本身的命令,由用户态写入;amdgpu 称 IB,Intel 称批缓冲区
ring首尾相接的缓冲区,存放命令处理器依次处理的包,包中多为命令缓冲区的地址与长度,以及 fence 等控制命令
队列一条 ring 连同其读写指针、doorbell 与队列描述符,格式由硬件规定、存储由软件分配,是命令处理器取包的单位
硬件队列槽位命令处理器中数量固定的寄存器组,队列描述符装入其中并激活后,命令处理器才从该队列取包
硬件队列调度器下发作业的目标队列。内核调度下是固定占用一个槽位、由内核独占的队列,常直接称为 ring;固件调度下是登记给固件、由固件按需映射到槽位上的队列,称为固件队列
用户态队列队列向用户态开放访问后的形态:ring、读写指针与 doorbell 映射到用户态,提交不再经过内核;这类队列由固件调度,创建、销毁与暂停仍由内核完成
软件队列调度器在内核内存中为每个提交来源维护的作业队列,暂存尚未写入 ring 的作业

1. 四个方向

四个方向分别对应一次提交必须解决的一个问题,各方向的演进阶段如图 8.1.1 所示。每条泳道左侧给出该方向需要解决的问题,右侧从左到右是同一方向上的几种形态,同一列的形态并不要求同时出现。

图 8.1.1 提交的四个演进方向

1.1 寻址:地址如何确定

早期 GPU 只有一个全局的 GTT 地址空间,用户态无法预知 BO 的地址,命令中的地址先以占位值写入,并在提交时附带重定位表。内核为 BO 分配地址后按表回填,每次提交都要逐项处理。

引入每进程 VM(每个进程拥有独立的 GPU 页表与虚拟地址空间)后,地址分配权开放给用户态,用户态以GEM_VA一类 ioctl 预先在 VM 中建立 GPU 虚拟地址到 BO 的映射,这一操作称为绑定。绑定后地址保持不变,提交不再需要重定位。

VM_BIND 进一步把绑定做成独立于提交的操作:绑定可以带输入与输出同步对象,在依赖满足后异步生效,提交只引用已绑定的地址。

可恢复缺页是指 GPU 访问未映射的地址时,只暂停出错的访问,由内核补齐映射后从出错处继续执行,而不是终止作业。若 GPU 支持可恢复缺页,还可以采用共享虚拟内存(SVM):GPU 直接使用 CPU 进程的虚拟地址,GPU 页表成为 CPU 页表的镜像,用户态不再为 GPU 单独分配地址,也不再执行绑定。

1.2 就位:BO 如何保证就位

寻址确定命令使用哪个地址,就位保证该地址背后的内存在执行时位于 GPU 可访问的位置、页表项有效。全局 GTT 中二者合一:BO 的地址就是它的位置,BO 移动后地址随之改变,重定位同时解决两个问题。每进程 VM 使二者分离:虚拟地址在绑定后保持不变,BO 移动时只更新页表项,就位由此成为独立的问题。

早期每次提交携带完整的 BO 列表,内核逐个加锁、校验位置、在必要时迁移并更新映射。开销与 BO 数量成正比,在无绑定资源访问的图形负载中,一次提交引用的 BO 可达数千个。

VM 式提交(映射在绑定时建立、提交不再携带 BO 列表的提交方式)改为以 VM 为单位处理:VM 私有的 BO 共用 VM 的dma_resv,一次加锁即完成;与其他进程共享的 BO 记入外部对象列表;被驱逐的 BO 记入 evict 列表,提交时只重新校验这一部分。

执行时间无法预知的作业称为长时运行作业,常见于计算负载。内存管理等待的 dma_fence 必须在有限时间内完成,长时运行作业与用户态队列中的作业无法满足这一条件,就位改在驱逐时保证。内核为承载这类作业的队列准备一个抢占 fence 或驱逐 fence,内存管理等待它时触发队列暂停,暂停完成后该 fence 才发出信号;迁移并重新绑定之后,队列恢复执行。

可恢复缺页使就位推迟到访问发生时完成,就位的对象也从 BO 变为 CPU 进程的页面:GPU 访问尚未映射的地址时触发缺页,驱动取得页面、在必要时迁入显存并建立映射;CPU 一侧需要回收或迁移页面时,内核经 MMU notifier(CPU 页表发生变化时回调已注册驱动的机制)清除对应的 GPU 页表项并刷新 TLB,GPU 此后的访问重新触发缺页。

1.3 同步:作业之间如何同步

这一方向包含两件事:输入依赖与完成通知。完成通知有两类使用者,其他提交与 CPU 上的等待者关心命令何时执行完毕,内存管理关心 BO 何时不再被 GPU 访问。早期两类使用者共用同一个 dma_fence,二者的分离是这一方向演进的关键。

早期的同步是隐式的:内核从每个 BO 的dma_resv中收集未完成的 fence 作为依赖,并把本次作业的 fence 写回。用户态无需描述依赖,代价是内核必须知道本次提交访问哪些 BO,且同步粒度只能是整个 BO。

显式同步以sync_file与 syncobj 让用户态直接给出依赖,时间线 syncobj 用一个对象表示一串时间点。VM 式提交不再列出 BO,内核无法替用户态推断隐式依赖,作业 fence 以 BOOKKEEP 用途写入 VM 的dma_resv,只供内存管理使用;需要与其他进程或设备隐式同步时,用户态经 dma-buf 的sync_file导入导出接口显式转换。

长时运行作业与用户态队列中作业的执行时间无法预知,进度改以内存中的数值表示:GPU 在作业完成时写入该数值,这种形式称为用户 fence;后续作业可在命令流中等待该数值,CPU 一侧也可以直接读取。

共享虚拟内存中,内存管理一侧的同步由页表失效完成:清除 GPU 页表项并刷新 TLB 即可使 GPU 停止访问,内存管理无需等待作业完成,也无需暂停队列。

1.4 仲裁:由谁仲裁并写入 ring

仲裁方向先后出现三种形态,如图 8.1.2 所示。

图 8.1.2 仲裁方向的三种形态

图中按用户态、内核、GPU 固件与 GPU 硬件四层对照三种形态。实线是提交路径,即命令经由哪些层到达命令处理器;虚线是管理路径,即哪一层决定队列占用槽位。从左到右,槽位的决定权先由内核移至固件,随后提交路径也不再经过内核。

早期 GPU 每类引擎只有少量队列,驱动初始化时将它们固定映射到硬件队列槽位,此后不再解除映射。这些队列由内核独占,一条 ring 服务所有使用者。早期驱动在提交 ioctl 中直接写入 ring,执行次序由调用先后决定,无法兼顾公平、优先级与依赖。

DRM 调度器(drm_gpu_scheduler)把这项职责收归内核:提交只把作业放入软件队列,调度器在依赖满足、容量允许时把作业写入 ring,并负责超时检测与恢复。调度器最初在 amdgpu 中实现,后来移入 DRM 公共代码。

新一代 GPU 由内置的调度微控制器运行调度固件(Intel GuC、Arm Mali CSF、AMD MES)。内核创建队列时将其登记给固件,由固件把数量众多的固件队列映射到有限的硬件队列槽位上,并按优先级与时间片轮换槽位。内核为每个固件队列各设一个调度器,仍由内核写入其 ring,但调度器不再决定执行次序,只负责等待依赖与控制下发的数量。各使用者拥有独立的队列,出错的队列可以单独移除,不再牵连其他使用者。

用户态队列中,用户态直接写入 ring 和 doorbell,提交不再经过系统调用,仲裁完全由固件完成。内核只在创建、销毁与暂停队列时参与,隔离依靠每个地址空间一套的 GPU 页表与按进程分配的 doorbell 实现。

三种形态的区别如表 8.1.2 所示。

表 8.1.2 仲裁方向的三种形态
形态写入 ring决定队列占用槽位提交是否经过内核
内核仲裁内核,早期在 ioctl 中直接写入,后由调度器写入内核,初始化时固定映射是
固件仲裁内核,每个固件队列一个调度器固件,按需映射是
用户态队列用户态固件,按需映射否

2. 方向之间的关联

四个方向并非各自独立,一个方向上的变化会迫使其他方向随之调整。

  • 寻址影响就位与同步。映射在绑定时建立并长期存在后,提交不再需要 BO 列表,就位随之转为以 VM 为单位维护。BO 列表消失后,内核也无法再从各 BO 的dma_resv中收集依赖,隐式同步只能由用户态显式转换。
  • 仲裁影响完成通知。固件仲裁后,内核看到的作业开始时间不再是实际开始执行的时间,超时判断需要修正。用户态队列中,提交不经内核,内核不再为每次提交创建 dma_fence。
  • 完成通知影响就位。dma_fence 必须在有限时间内到达,内存回收路径可以等待它。执行时间无法预知的作业不能以普通的作业 fence 写入dma_resv,否则内存回收可能无限期阻塞。完成通知因而一分为二:用户 fence 面向其他工作,抢占 fence 或驱逐 fence 面向内存管理。等待后者的代价是暂停队列,暂停可以在有限时间内完成,就位也随之从提交时转移到驱逐时。
  • 缺页影响寻址、就位与完成通知。GPU 能从缺页恢复后,映射与就位都可以推迟到访问发生时,地址空间可以与 CPU 进程共用。内存管理以清除页表项取代暂停队列,面向内存管理的完成通知随之不再需要。

综合四个方向,演进的共同趋势是提交路径上由内核完成的工作逐步减少,转移到绑定时、驱逐时、缺页时与固件中。不变的是内核对内存管理的最终控制:任何形态下,内核都能在有限时间内使 GPU 停止访问某块内存,手段从等待作业 fence、暂停队列发展到清除页表项。各种新形态的设计,实质上是在提交路径变短的同时维持这一约束。

3. 第 8 至 11 章的组织

第 7 章已经说明同步原语 dma_fence、dma_resv与 syncobj,它们是同步方向的基础。第 8 至 11 章按方向展开,见表 8.1.3。

表 8.1.3 第 8 至 11 章与四个方向的对应
章主题对应的方向
第 8 章GPU 调度器框架仲裁方向中由内核仲裁的形态:作业排队、依赖等待、流量控制、超时与恢复
第 9 章GPU 地址空间的演进寻址方向,以及就位方向中以 VM 为单位的维护
第 10 章提交路径的演进四个方向在提交路径上的组合:BO 列表式、VM 式、长时运行与用户态队列四种形态,以及固件仲裁与 dma_fence 约束带来的调整
第 11 章共享虚拟内存寻址与就位方向的最终形态:地址与 CPU 共用,就位推迟到缺页时完成;以及同步方向中以页表失效与内存管理同步

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询