长时间运行的工作负载和计算¶
长时间运行的工作负载(计算)是指在 10 秒内无法完成的工作负载。(这个时间是用户在伸手去按电源按钮之前等待的时间)。这意味着需要使用其他技术来管理那些不能使用围栏(fence)的工作负载。
某些硬件可能会调度计算作业,并且无法抢占它们,或无法将它们的内存换出。或者它们只是希望其工作负载根本不被抢占或换出。
这意味着它与 driver-api/dma-buf.rst 中描述的内容不同。
与普通计算作业一样,dma-fence 可能根本不被使用。在这种情况下,甚至不能用来强制抢占。驱动程序在解绑时会被简单地强制立即从长时间计算作业的地址空间中解除 BO 的映射,甚至不等待工作负载完成。如果硬件不支持恢复,这实际上会终止工作负载。
由于这是不希望发生的情况,因此需要采取缓解措施以防止工作负载被终止。有几种可能的方法,各有优缺点。
您可能首先尝试的方法是固定计算使用的所有缓冲区。这保证了作业将不间断运行,但也允许通过尽可能多地固定内存,独占所有 GPU 内存,并可能独占大量 CPU 内存,从而进行非常严重的拒绝服务攻击。
第二种方法是,在创建新作业(任何类型)时添加一个不驱逐的选项,这本身会稍微好一些。如果所有用户空间都选择此标志,它将阻止协同用户空间强制终止旧的计算作业以启动新的作业。
如果作业抢占和可恢复的页面错误不可用,那么这些是唯一可能的方法。因此,即使有了这些,您也需要一种单独的资源控制方式。内核的标准做法是使用 cgroups。
这创建了第三个选项,即使用 cgroups 来防止驱逐。GPU 和驱动程序分配的 CPU 内存都将计入正确的 cgroup,并且驱逐将感知 cgroup。这允许将 GPU 分区到 cgroup 中,从而允许作业在彼此相邻的情况下运行而互不干扰。
cgroup 的接口将类似于当前的 CPU 内存接口,如果驱逐可以感知 cgroup,则 min/low/high/max 具有相似的语义。
需要注意的是,每个内存区域(例如平铺内存)都应该有自己的记账方式。
键设置为驱动程序设置的 regionid,例如“tile0”。对于 $card 的值,我们使用 drmGetUnique()。