您对零拷贝工作原理的理解是正确的。基本前提是您可以从设备访问主机内存,也可以从主机访问设备内存,而无需在两者之间执行中间缓冲步骤。
您可以通过使用以下标志创建缓冲区来执行零复制:
CL_MEM_AMD_PERSISTENT_MEM //Device-Resident Memory
CL_MEM_ALLOC_HOST_PTR // Host-Resident Memory
然后,可以使用内存映射语义来访问缓冲区:
void* p = clEnqueueMapBuffer(queue, buffer, CL_TRUE, CL_MAP_WRITE, 0, size, 0, NULL, NULL, &err);
//Perform writes to the buffer p
err = clEnqueueUnmapMemObject(queue, buffer, p, 0, NULL, NULL);
使用零拷贝,您可以获得比执行以下操作的实现更高的性能:
- 将文件复制到主机缓冲区
- 将缓冲区复制到设备
相反,您可以一步完成这一切
- 内存映射设备端缓冲区
- 将文件从主机复制到设备
- 取消映射内存
在某些实现上,映射和取消映射的调用可以隐藏数据传输的成本。就像我们的例子一样,
- Memory Map设备端缓冲区【实际上创建了一个相同大小的主机端缓冲区】
- 将文件从主机复制到设备[实际写入主机端缓冲区]
- 取消映射内存[实际上是通过 clEnqueueWriteBuffer 将数据从主机缓冲区复制到设备缓冲区]
如果实现以这种方式执行,那么使用映射方法将没有任何好处。然而,AMD 的 OpenCL 较新驱动程序允许直接写入数据,使得映射和取消映射的成本几乎为 0。对于独立显卡,请求仍然通过 PCIe 总线进行,因此数据传输可能会很慢。
然而,在 APU 架构的情况下,由于 APU 独特的架构(如下图所示),使用零复制语义的数据传输成本可以大大提高传输速度。在此架构中,PCIe 总线被统一北桥 (UNB) 取代,从而实现更快的传输。
BE AWARE当使用带有内存映射的零拷贝语义时,当从主机读取设备端缓冲区时,您将看到绝对可怕的带宽。这些带宽约为 0.01 Gb/s,很容易成为代码的新瓶颈。
抱歉,如果信息太多。这是我的论文题目。