GPU中的并行计算 - CUDA / OpenCL

4

我有一个关于在GPU上使用CUDA或OpenCL代码的并行性的一般问题。我使用NVIDIA GTX 470。

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

我有一个顶级函数,它调用CUDA内核(对于相同的内核,我有其OpenCL版本)。此顶级函数本身从我的主函数中的“for循环”中调用3次,针对3个不同的数据集(图像数据R、G、B),而实际的代码块也对图像/帧中的所有像素进行处理,因此它有2个“for循环”。

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

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

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

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

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

3个回答

6
在GPU上的并行处理是SIMT(单指令多线程)。对于CUDA内核,您需要指定一个块网格,其中每个块都有N个线程。CUDA库会完成所有技巧,CUDA编译器(nvcc)将生成由GPU执行的GPU代码。CUDA库告诉GPU驱动程序以及GPU上的线程调度器应该执行内核的线程数((块数)x(线程数))。在您的示例中,顶级函数(或主机函数)仅执行异步内核调用,并立即返回。不需要线程库,因为nvcc创建了对驱动程序的调用。
一个示例内核调用如下:
helloworld<<<BLOCKS, THREADS>>>(/* maybe some parameters */);

OpenCL遵循相同的范例,但您需要在运行时编译内核(如果它们没有预编译)。指定要执行内核的线程数,库将完成其余工作。
学习CUDA(OpenCL)的最佳方法是查看CUDA编程指南OpenCL编程指南),并查看GPU计算SDK中的示例。

2
如果启动多个内核,它们将不会自动并行化(即没有GPU任务并行性)。然而,内核调用在主机端是异步的,所以主机代码将在内核执行时继续并行运行。
要获得任务并行性,您必须手动完成——在Cuda中,这个概念被称为流,在OpenCL命令队列中。如果没有显式地创建多个流/队列并将每个内核调度到其自己的队列中,则它们将按顺序执行(有一个OpenCL功能允许队列无序运行,但我不知道任何实现是否支持它)。但是,如果每个数据集足够大以利用所有GPU核心,同时并行运行内核可能不会带来太多好处。
如果您的内核中实际存在for循环,它们本身不会被并行化,但并行性来自指定网格大小,这将使内核在该网格中的每个元素上并行调用(因此,如果您在内核中有for循环,则每个线程将完整地执行它们)。换句话说,在调用内核时应指定网格大小,并在内核内部使用threadIdx/blockIdx(Cuda)或getGlobalId()(OpenCL)来标识特定线程中要处理的数据项。
学习OpenCL的一本有用书籍是OpenCL编程指南,但OpenCL规范也值得一看。

2
我想知道这里利用了哪种并行处理方式--任务级并行还是数据级并行?
主要是数据级并行,但也涉及一些任务级并行。
在图像处理的例子中,一个核心可能会为单个输出像素进行处理。您会指示OpenCL或CUDA运行与输出图像中的像素数量相同的线程。然后它会将这些线程安排到您正在针对的GPU / CPU上运行。
高度数据并行。内核被编写为执行单个工作项,并且您可以调度数百万个工作项。
任务并行性是因为当GPU运行所有这些线程时,您的主机程序仍在CPU上运行,因此它可以继续其他工作。通常,这是为下一组核心线程准备数据,但它可能是完全独立的任务。

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