我很好奇当我运行 CUDA 程序时,数据如何在 CPU 和 GPU 内存之间来回复制。具体来说,我想知道Linux内核是如何参与这个过程的。
我有一些可能的假设:
- CUDA 用户库将 GPU 视为一个文件,
read(2)
并write(2)
为每个事务调用 和 。 - CUDA 用户库要求 Linux 将
mmap(2)
相关控制寄存器(DMA 寄存器、PIO 寄存器和其他一些 MMIO 寄存器)放入用户空间,然后在用户态下对 GPU 进行任意操作。 - 还有别的事吗?
我通过运行简单的 CUDA 程序来消除假设#1,该程序来回复制数据 1000 次(并在其间启动一些空内核),其中strace(1)
没有观察到对write(2)
和 的任何调用read(2)
。
假设 #2 似乎是可能的,因为我观察到time(1)
传输的数据量似乎随着user
时间而不是sys
时间而变化。所以该程序似乎是在用户态复制数据。
但似乎有点奇怪。如何允许用户程序自己操作如此重要的I/O控制寄存器?
我将不胜感激有关这个主题的一些专业想法。
答案1
应用程序在启动时向内核请求mmap
一组缓冲区,创建此映射是一项特权操作。
正常操作只是用数据(例如纹理、顶点或命令)填充这些缓冲区,最后进行单个内核调用来启动提交的命令队列。此启动选通是唯一执行的寄存器访问,其他所有内容都是共享内存。
GPU 有自己的基本 MMU,以确保命令无法引用属于另一个上下文的数据,除非需要(例如,将游戏中的渲染目标与覆盖层中的渲染目标组合在一起的合成器,并将结果写入到本地)屏幕缓冲区)。
对于仅计算的工作负载,相同的机制可以正常工作,命令队列只是不以“将数据发送到屏幕”结束,而是以“将数据返回到主机”结束。