我正在学习OpenCL并试图在一些低延迟的情况下使用它,所以我真的很关心内存传输延迟。
根据NVidia的OpenCL最佳实践指南以及许多其他地方,应避免直接读/写缓冲区对象。相反,我们应该使用map / unmap实用程序。在该指南中,演示代码如下:
cl_mem cmPinnedBufIn = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, memSize, NULL, NULL);
cl_mem cmDevBufIn = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, memSize, NULL, NULL);
unsigned char* cDataIn = (unsigned char*) clEnqueueMapBuffer(cqCommandQue, cmPinnedBufIn, CL_TRUE, CL_MAP_WRITE, 0, memSize, 0, NULL, NULL, NULL);
for(unsigned int i = 0; i < memSize; i++)
{
cDataIn[i] = (unsigned char)(i & 0xff);
}
clEnqueueWriteBuffer(cqCommandQue, cmDevBufIn, CL_FALSE, 0, szBuffBytes, cDataIn , 0, NULL, NULL);
在此代码段中,显式生成了两个缓冲区对象,并且还显式调用了写入设备操作。
如果我的理解是正确的,当您使用clCreateBuffer
OR CL_MEM_ALLOC_HOST_PTR
调用CL_MEM_USE_HOST_PTR
时,缓冲区对象的存储将在主机端创建,可能在DMA内存中创建,并且没有存储空间在设备端分配。所以上面的代码实际上创建了两个独立的存储如果是这样的话:
如果我在没有主机端内存的cmDevBufIn
上调用地图缓冲区会怎么样?
对于CPU集成的GPU,没有单独的图形内存。特别是,对于新版本的AMD APU,内存地址也是同源的。所以看来创建两个缓冲对象并不好。集成平台的最佳实践是什么?
有没有办法为不同平台编写单行内存传输代码?或者我必须编写几种不同的内存转移代码才能获得Nvidia,AMD独立GPU,AMD旧APU,AMD新APU和Intel HD图形的最佳性能......
答案 0 :(得分:2)
不幸的是,每个供应商都有所不同。
NVIDIA声称他们的最佳带宽是当你使用读/写缓冲区时主机内存被固定&#34;这可以通过创建一个带有CL_MEM_ALLOC_HOST_PTR的缓冲区并映射它来实现(我想你的例子就是那个)。您还应该将其与映射和取消映射设备内存进行比较;他们最近的司机在这方面做得更好。
使用AMD,您只需映射/取消映射设备缓冲区即可获得全速。它们还有一堆供应商特定的缓冲区标志,可以使某些场景更快;你应该研究它们,但更重要的是要创建基准测试,尝试一切,看看哪种方法最适合你的任务。
对于两个离散设备,您应该为传输操作使用单独的命令队列,以便它们可以与其他(非依赖)计算操作重叠(查找各种计算重叠示例)。此外,一些较高端的离散GPU可以在上传另一个缓冲区的同时下载一个缓冲区(使用双DMA引擎),因此您可以上传一批工作,同时还要计算另一个工作区。下载第三个结果。优雅地编写时,这不是严格顺序版本的代码,但是您必须使用OpenCL事件在命令队列之间进行同步。 NVIDIA有一个你可以观看的GTC演讲,它说明了如何每隔16毫秒为视频帧做这件事。
使用AMD的APU和英特尔的集成显卡,&#34;设备的映射/取消映射&#34;缓冲区是免费的&#34;因为它在主存中。不要在这里使用读/写缓冲区,否则您将为不需要的传输付费。