【发布时间】:2019-01-18 01:22:18
【问题描述】:
我有一个算法,我一直在尝试在我的 nVidia 上使用 OpenCL 来加速它。
它必须处理大量数据(比如说 100k 到百万),其中对于每个数据:必须首先更新一个矩阵(在设备上)(使用数据和两个向量);只有在整个矩阵更新后,两个向量(也在设备上)使用相同的数据更新。所以,我的主机代码看起来像这样
for (int i = 0; i < milions; i++) {
clSetKernelArg(kernel_matrixUpdate, 7, sizeof(int), (void *)&i);
clSetKernelArg(kernel_vectorsUpdate, 4, sizeof(int), (void *)&i);
clEnqueueNDRangeKernel(command_queue, kernel_matrixUpdate, 1, NULL, &global_item_size_Matrix, NULL, 0, NULL, NULL);
clEnqueueNDRangeKernel(command_queue, kernel_vectorsUpdate, 1, NULL, &global_item_size_Vectors, NULL, 0, NULL, NULL);}
不幸的是,这个循环的执行时间比内核本身要长。所以我的问题是:
- 有什么方法可以更有效地将 N 个内核排入队列?
- 有没有办法先更新整个矩阵,然后更新向量,而不使用单独的内核?例如。设备是否按顺序运行内核(即第一个工作组为 0,1,...,63;第二个工作组为 64,...)?但我想这无论如何都是一个不好的做法......
- 还有其他想法吗? :D
我们将不胜感激每一个反馈或意见。谢谢。
【问题讨论】:
-
最快的是使用 OpenCL 2.0 动态并行的设备端排队。此外,如果内核参数始终相同,则无需使用 clSetKernelArg 重新设置它们。一次就够了。如果您在创建时未指定无序标志,则内核默认按顺序运行。还有为什么
(void *)&i?它正在获取变量的地址,因此所有内核参数都将获得相同的最新值。他们都会看到millions-1的价值。如果仅更改该参数,则可以添加第二个内核以在 gpu 内存中增加该值,然后将它们逐个设备排入队列。至少这会跳过 CPU 端。 -
那么您只会将父内核排入队列一次。如果每个操作独立于另一个,您可以使用多个命令队列(可能多达 64 个)同时运行多个内核。
-
不幸的是,nVidia 目前似乎不支持 OpenCL 2.0 :(
-
听起来你的问题不在于 OpenCL,而是你的算法是顺序的。您确定不能更改算法以便批量更新吗?至少,如果您受 API 限制,一个明显的步骤是将您的 2 个内核合并为 1 个。(您可以将矩阵大小与向量大小联系起来吗?)但除此之外您不会得到太多帮助,除非您实际上发布您的算法的性质,因为这是需要优化的。
标签: parallel-processing opencl gpu gpgpu hardware-acceleration