GPU中的并行性 - CUDA / OpenCL

时间:2011-12-22 11:49:18

标签: cuda opencl

我对GPU上的CUDA或OpenCL代码中的并行性有一般性的疑问。我使用的是NVIDIA GTX 470。

我在Cuda编程指南中简要阅读,但没有找到相关的答案,因此在这里问。

我有一个调用CUDA内核的顶级函数(对于相同的内核,我有一个OpenCL版本)。这个顶级函数本身在我的主函数的'for循环'中被调用3次,用于3个不同的数据集(图像数据R,G,B) 并且实际的codelet还处理图像/帧中的所有像素,因此它具有2'for loops'。

我想知道的是这里采用了什么样的并行性 - 任务级并行或数据并行?

所以我想要理解的是,这个CUDA和C代码是否为codelet和顶级代码中的不同功能/函数创建了多个线程,并在 并行和利用任务并行。如果是,则由于没有明确包含在代码中或与。链接的线程库而创建它。

OR

它为不同的'for循环'迭代创建线程/任务,这些迭代是独立的,从而实现数据并行性。 如果它实现了这种并行性,它是否只是通过注意到不同的for循环迭代没有依赖关系并因此可以并行调度来利用它?

因为我没有看到任何特殊的编译器构造/内在函数(在openMP中为循环并行),它告诉编译器/调度程序并行调度这样的for循环/函数?

任何阅读材料都会有所帮助。

3 个答案:

答案 0 :(得分:6)

GPU上的并行性是SIMT(单指令多线程)。对于CUDA内核,您可以指定每个块具有N个线程的块网格。 CUDA库完成所有技巧,CUDA编译器(nvcc)生成GPU执行的GPU代码。 CUDA库告诉GPU驱动程序以及GPU上的线程调度程序更多应该执行内核的线程数((块数)x(线程数))。在您的示例中,顶级函数(或主机函数)仅执行异步的内核调用并返回emediatly。不需要线程库,因为nvcc会创建对驱动程序的调用。

示例内核调用如下所示:

helloworld<<<BLOCKS, THREADS>>>(/* maybe some parameters */);

OpenCL遵循相同的范例,但是你在运行时编译你的内核(如果它们没有被预编译)。指定执行内核的线程数,lib完成其余的工作。

学习CUDA(OpenCL)的最佳方法是查看CUDA Programming GuideOpenCL Programming Guide)并查看GPU Computing SDK中的示例。

答案 1 :(得分:2)

  

我想知道的是这里采用了什么样的并行性 - 任务级并行或数据并行?

主要是数据并行性,但也涉及一些任务并行性。

在图像处理示例中,内核可能会对单个输出像素进行处理。您将指示OpenCL或CUDA运行与输出图像中的像素一样多的线程。然后,它会调度这些线程以在您要定位的GPU / CPU上运行。

高度数据并行。内核被编写为执行单个工作项,并且您可以安排数百个工作项。

任务并行性是因为你的主机程序仍在CPU上运行,而GPU正在运行所有这些线程,所以它可以继续其他工作。这通常是为下一组内核线程准备数据,但它可能是一个完全独立的任务。

答案 2 :(得分:2)

如果启动多个内核,它们将不会自动并行化(即没有GPU任务并行性)。但是,内核调用在主机端是异步的,因此主机代码将在内核执行时继续并行运行。

要获得任务并行性,您必须手动完成 - 在Cuda中,概念称为流,在OpenCL命令队列中。如果没有显式创建多个流/队列并将每个内核调度到自己的队列,它们将按顺序执行(有一个OpenCL功能允许队列无序运行,但我不知道是否有任何实现支持它。但是,如果每个数据集足够大以利用所有GPU核心,并行运行内核可能不会带来太多好处。

如果你的内核中有实际的for循环,它们本身不会被并行化,并行性来自指定一个网格大小,这将导致内核被并行调用该网格中的每个元素(所以如果你在你的内核中有for循环,它们将由每个线程完整地执行)。换句话说,您应该在调用内核时指定网格大小,并在内核中使用threadIdx / blockIdx(Cuda)或getGlobalId()(OpenCL)来标识要在该特定线程中处理的数据项。

学习OpenCL的有用书是OpenCL Programming Guide,但OpenCL spec也值得一看。