正确的方式通知OpenCL内核的许多内存对象?

时间:2012-06-16 11:20:22

标签: opencl gpgpu

在我的OpenCL程序中,我将最终得到60多个全局内存缓冲区,每个内核都需要能够访问。让每个内核知道每个缓冲区的位置的推荐方法是什么?

缓冲区本身在应用程序的整个生命周期中都是稳定的 - 也就是说,我们将在应用程序启动时分配缓冲区,调用多个内核,然后仅在应用程序端解除分配缓冲区。但是,它们的内容可能会随着内核从它们读/写而改变。

在CUDA中,我这样做的方法是在我的CUDA代码中创建60多个程序范围全局变量。然后,我会在主机上写入我分配到这些全局变量中的设备缓冲区的地址。然后内核会简单地使用这些全局变量来找到它需要使用的缓冲区。

在OpenCL中执行此操作的最佳方法是什么?似乎CL的全局变量与CUDA略有不同,但我无法找到关于我的CUDA方法是否有效的明确答案,如果是的话,如何将缓冲区指针转换为全局变量。如果那不起作用,那么最好的方法是什么呢?

2 个答案:

答案 0 :(得分:2)

60个全局变量确实很多!您确定没有办法重构您的算法以使用较小的数据块吗?请记住,每个内核应该是最小的工作单元,而不是巨大的!

然而,有一种可能的解决方案。假设您的60个阵列已知大小,您可以将它们全部存储到一个大缓冲区中,然后使用偏移量来访问该大型阵列的各个部分。这是一个包含三个数组的非常简单的示例:

A is 100 elements
B is 200 elements
C is 100 elements

big_array = A[0:100] B[0:200] C[0:100]
offsets = [0, 100, 300]

然后,您只需要将big_array和offsets传递给内核,并且可以访问每个数组。例如:

A[50] = big_array[offsets[0] + 50]
B[20] = big_array[offsets[1] + 20]
C[0] = big_array[offsets[2] + 0]

我不确定这会如何影响您的特定设备上的缓存,但我最初的猜测是“不太好”。这种阵列访问也有点讨厌。我不确定它是否有效,但您可以使用一些提取每个偏移量的代码启动每个内核,并将其添加到原始指针的副本中。

在主机端,为了使您的阵列更易于访问,您可以使用clCreateSubBuffer:http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSubBuffer.html,它还允许您在没有偏移数组的情况下将引用传递给特定数组。

我认为这个解决方案不会比传递60个内核参数更好,但是根据你的OpenCL实现的clSetKernelArgs,它可能会更快。它肯定会缩短你的参数列表的长度。

答案 1 :(得分:0)

你需要做两件事。首先,每个使用每个全局内存缓冲区的内核都应声明每个一个的参数,如下所示:

kernel void awesome_parallel_stuff(global float* buf1, ..., global float* buf60)

以便列出该内核的每个使用缓冲区。然后,在主机端,您需要创建每个缓冲区并使用clSetKernelArg将给定的内存缓冲区附加到给定的内核参数,然后再调用clEnqueueNDRangeKernel来获取该方启动。

请注意,如果内核在每次执行内核时都会使用相同的缓冲区,则只需要设置内核参数一次时间。我看到的一个常见错误,即会导致主机端性能下降,是在完全没必要的情况下重复调用clSetKernelArg