OpenCL:将变量传递给使用CL_MEM_USE_HOST_PTR的内核时,设备/主机内存协同性

7
如果使用CL_MEM_USE_HOST_PTR将变量传递到内核中,那么在设备中对该变量所做的任何更改是否也会显示在主机内存中?
我现在的情况是,我将CPU用作设备而不是GPU,因此传递给内核的所有内容都将标记为CL_MEM_USE_HOST_PTR。
如果这是真的,那么我就不需要再把所有东西读回主机了,这非常方便。
1个回答

11
您的理解是正确的,但存在一种可能的陷阱:文档指出:

OpenCL 实现允许在设备内存中缓存由 host_ptr 指向的缓冲区内容。当在设备上执行内核时,可以使用此缓存的副本。

这意味着内核执行对数据所做的更改可能不会立即反映在 host_ptr 中。实际上,在用作缓冲区时,并没有保证 host_ptr 包含有效数据。
为了拥有有效和最新的数据,您必须强制同步。官方文档对此时刻有点模糊不清,但缓冲区映射/取消映射绝对可行:

如果创建缓冲区对象时在 mem_flags 中设置了 CL_MEM_USE_HOST_PTR,则在 clEnqueueMapBuffer 命令完成时,host_ptr 中指定的区域将包含最新的位;而由 clEnqueueMapBuffer 返回的指针值将派生自创建缓冲区对象时指定的 host_ptr

以下是从Khronos group 论坛帖子中调整的示例:
cl_mem device_output = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, size, original_output, NULL);
// run the kernel
void* pointer = clEnqueueMapBuffer(queue, device_output, CL_TRUE, CL_MAP_READ, size, 0, 0, NULL, NULL, NULL);
// work with 'original_output'
clEnqueueUnmapMemObject(queue, device_output, pointer, 0, NULL, NULL);
clReleaseMemObject(device_output);

2
这是一个微妙的陷阱,我也曾经被它咬过,所以很好你提出来了。 - Ani
@aland 我想我问得很晚了... 但是,如果我使用事件等待而不是映射内存,它会更新我的主机设备中的正确数组吗?对我来说,这很有效(可能是因为我使用事件让内核完成)。但是,那么我可以跳过映射吗? - Vishwadeep Singh
1
@Vishwadeep 只是等待内核执行完成是不够的。你的方法可能有效,特别是如果你只使用CPU作为计算设备,但这仍然是未定义的行为。 - aland
是的,@aland,你找对了,我正在使用CPU作为计算设备。谢谢你的回答。 - Vishwadeep Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接