19

我在教程中看过这两个版本,但我不知道它们的优缺点是什么。哪一个是合适的?

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

对比

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL);

谢谢。

[更新]

我添加CL_MEM_COPY_HOST_PTR,到第二个示例以使其正确。

4

5 回答 5

10

在我使用 OpenCL 的过程中,我发现了一个非常重要的区别

cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error);

cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error);
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0);

对于第一种方法,OpenCL 将不直接复制主机指针到 GPU。首先,它会在主机上分配第二个临时缓冲区,如果您将 CT 等大东西加载到 GPU 上,这可能会导致问题。在短时间内,所需的内存是 CT 大小的两倍。在此功能期间也不会复制数据。它在参数设置期间被复制到使用 3D 图像对象的内核函数。

第二种方法直接将数据复制到 GPU。OpenCL 没有进行额外的分配。我认为这可能与普通缓冲区对象相同。

于 2012-08-02T09:58:57.977 回答
7

我假设 inputdata 不为 NULL。

在这种情况下,第二种方法根本不起作用,因为规范说,clCreateBuffer 返回 NULL 和错误,如果:

CL_INVALID_HOST_PTR 如果 host_ptr 为 NULL 并且 CL_MEM_USE_HOST_PTR 或 CL_MEM_COPY_HOST_PTR 在标志中设置,或者如果 host_ptr 不为 NULL 但 CL_MEM_COPY_HOST_PTR 或 CL_MEM_USE_HOST_PTR 未在标志中设置。

所以你的意思是

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

或者

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

第一个应该或多或少与您展示的第一个方法相同,而第二个实际上不会复制数据,而是使用提供的内存位置进行缓冲存储(将部分或全部缓存在设备内存中) . 这两个哪个更好显然取决于使用场景。

就个人而言,我更喜欢使用首先分配缓冲区然后用 writeToBuffer 填充它的两步方法,因为我发现更容易看到发生了什么(当然一步可能更快(或者它可能不会,这只是一个猜测))

于 2010-10-01T03:07:31.773 回答
4

第一种方法的优点是“clEnqueueWriteBuffer”允许您将事件分配给缓冲区的副本。因此,假设您想使用 GPU_Profiling 选项测量将数据复制到 GPU 所需的时间,您将能够使用第一种方法来执行此操作,但不能使用第二种方法。

第二种方法更紧凑,更易于阅读,并且需要更少的代码行。

于 2012-05-24T19:25:02.647 回答
3

我遇到的一个主要区别是:

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL); clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

这第一组命令将创建一个空缓冲区并将命令排入命令队列以填充缓冲区。

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL)

第二个命令将创建缓冲区并立即填充它。请注意,此参数列表中没有命令队列,因此它使用当前输入数据的内容。

如果您已经在运行 CL 代码并且您的源指针依赖于命令队列中的前一个命令的完成(例如,对前一个输出缓冲区的排队读取),那么您肯定希望使用第一种方法。如果您尝试在单个命令中创建和填充缓冲区,您最终会遇到竞争条件,其中缓冲区内容不会正确等待您之前的缓冲区读取完成。

于 2011-02-12T19:35:26.480 回答
2

这两者之间的主要区别在于第一个在设备上分配内存,然后将数据复制到该内存。第二个只分配。

还是你的意思clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

于 2010-09-30T18:43:43.443 回答