4

随着 OpenCL 2.0 的引入,OpenCL 似乎具备了 Grand Central Dispatch (GCD) 的许多特性,例如 CLang/Apple 样式的块和队列。看看它们各自的功能集,我想知道 OpenCL 是否可以做 GCD/libdispatch 可以做的所有事情,但增加了将计算定向到 GPU 和 CPU 的能力——或者 GCD 是否可以提供更多与众不同的功能来自 OpenCL。

具体来说,我的问题是:

  1. GCD 和 OpenCL 的并发特性有何不同?

  2. 如果一起使用它们是有价值的(假设 GCD 提供了附加功能),C 块可以路由到 GCD 队列或 OpenCL 队列吗?如果以 CPU 为目标,是否有理由通过 OpenCL 与直接运行

  3. OpenCL 2.0 是否提供 GCD 样式的负载平衡,可以填充跨越 CPU 和 GPU 的线程?

4

3 回答 3

5

在目前的形式中,OpenCL 能够解决数据并行和任务并行问题,不同的 OpenCL API 原语将工作排入队列就证明了这一点:

  • clEnqueuNDRangeKernel:用于将具有 N 维工作组大小的内核排入队列。通常用于数据并行处理。
  • clEnqueueTask:用于将由单个工作项组成的内核排入队列。该原语用于任务并行执行,基本上相当于clEnqueueNDRangeKernel全局工作大小为 1。它已从 OpenCL 2.0 规范中删除
  • clEnqueueNativeKernel将本机 C/C++ 函数排队到设备(如果它支持本机内核),好处是您可以使用排队机制(和队列中的排序)并直接从 OpenCL 上下文访问缓冲区数据。除此之外,这与线程或任务的概念非常相似。

因此,尽管 OpenCL 显然起源于 GPU 上的数据并行处理,并且仍然最适合处理可以以某种方式强制在 1、2 或 3 维网格中的数据,但面向任务的处理也是可能的。一旦开始针对具有多个 CPU、GPU、DSP 和加速器的异构系统,其优势就会变得更加明显,因为 OpenCL 可以以一种形式针对所有这些设备。

另一方面,GCD 提供了一个方便的库,通过构建队列(不同类型和优先级)的概念,将开发人员从管理和调度任务的大部分负担中解脱出来。因此,使用 GCD 可以在对称多处理系统上产生更不容易出错和更紧凑的代码。

因此,虽然 OpenCL 和 GCD 在其起源上有不同的背景(除了它们都来自 Apple 的事实),但它们都在其基础上使用队列来管理工作项分发。他们都有一个“上下文”的概念来定义数据访问。

从 OS X 版本 10.7 开始,可以使用 GCD 将 OpenCL 内核(类似于块)分发到支持 OpenCL 的设备,从而为结合 OpenCL 和 GCD 的优势/优势开辟了潜力。

以下是针对您的具体问题的一些答案/见解的尝试:

1 - GCD 和 OpenCL 的并发特性有什么区别?

正如@Dithermaster 和@sharpneli 所指出的,GCD 最初的目标是面向任务(对称多)处理,而 OpenCL 最初是针对异构架构上的数据并行处理。

OpenCL 和 GCD 之间的一个主要区别在于排队机制。例如,虽然 OpenCL 和 GCD 都支持同步和异步执行,但 GCD 对全局异步队列有三个优先级。OpenCL 运行时没有这个(它有工作项的乱序执行,但没有定义运行时将首先执行哪些工作项)。

GCD 手册还指出,任务比传统线程更轻量级,使得生成 GCD 任务的指令比线程少得多。

另一个区别是使用的内存一致性模型。OpenCL 使用宽松的内核模型,具有全局、本地、私有和常量内存。GCD 没有这个。

另一方面,OpenCL 具有向量数据类型和向量内在函数,允许直接挖掘架构的 SIMD 潜力,而无需依赖编译器。在某些架构上这是有益的,而其他架构(如 MIC)建议不要手动进行矢量化。

最后——虽然不是真正的并发特性——OpenCL 具有允许读取和写入图像类型的功能,本质上让您可以直接访问纹理内存。即使对于与图像处理无关的算法,这通常也可用于获得显着的加速。

2 - 如果一起使用它们是有价值的(假设 GCD 提供了附加功能),C 块可以路由到 GCD 队列或 OpenCL 队列吗?如果以 CPU 为目标,是否有理由通过 OpenCL 与直接运行

通过同时使用 GCD 和 OpenCL,您可以处理任何支持 OpenCL 的设备。因此,您可以利用平台的潜在异构特性,同时仍然能够从 GCD 提供的更高级的机制中受益,以使多线程更容易。使用 OpenCL C API(甚至 C++ API)编写所有内容可能会导致代码稍微多一些。

此外,GCD 提供了gcl_get_kernel_block_workgroup_info可以为您的内核推荐最佳工作组大小的原语。

但是,据我了解,不可能将任意 C 块路由到 GCD 或 OpenCL 队列。C 块只能进入非 OpenCL 队列。OpenCL 内核只能(从主机端)分派到支持 OpenCL 的设备的队列中。从设备端(因此在 OpenCL 内核中),一个块只能被分派到同一个设备。

3 - OpenCL 2.0 是否提供 GCD 样式的负载平衡,可以填充跨越 CPU 和 GPU 的线程?

不,OpenCL 2.0 并没有真正定义如何进行负载平衡,无论是从主机的角度还是从设备的角度。

然而,在主机端,人们可以轻松地拆分计算并在 CPU 上运行其中的一部分,而在一个或多个 GPU 上运行另一部分。一种方法是使用工作组大小和工作组偏移量,只复制每个设备所需的最少数据。然后可以使用自动调整机制来确定所使用的不同设备之间的最佳负载平衡是什么。

一旦 OpenCL 2.0 驱动程序可用,新引入的管道、动态并行性和共享虚拟内存将为设备之间的有效分区工作提供更多可能性。目前尚不清楚这些功能是否以及如何通过 GCD 提供。

于 2014-02-06T01:30:43.510 回答
1

1) Dithermaster 已经很好地回答了。OpenCL 适用于当您的问题很好地并行化并且您拥有大量数据时。GCD 适用于您必须毫不费力地产生线程来处理文件 IO 或诸如此类的情况。您永远不能从 OpenCL 调用任何系统或其他库函数。

2)如果您的问题很容易并行化,那么即使在 CPU 上也值得使用 OpenCL。例如,英特尔的 OpenCL 实现设法水平并行化一些内核,以便单个内核一次有效地运行 8 个线程(一个线程“运行”在 SSE 寄存器的一个向量组件中)。

您不能将通用 C 块传递给 OpenCL。只是内核本身,仅此而已。OpenCL 对您可以在其上执行的内容更加挑剔。新奇的 Clang IR 唯一带来的是能够避免以文本形式分发内核源代码。它仍然仅限于 OpenCL 内核代码。

3) 不是自动的。确实存在一些执行此操作的实现。去年,GDC Intel 在他们的 CPU 上展示了自动负载平衡(它同时使用了集成 GPU 和 CPU)。

OpenCL2.0 并不真正关心它运行在哪种硬件上,因此硬件制造商有责任在他们的平台上实现这些功能。或者对于不相交的平台,这是程序员的头痛。

于 2014-02-04T09:28:12.097 回答
1

“OpenCL 具有矢量数据类型和矢量内在函数,允许直接挖掘架构的 SIMD 潜力,而无需依赖编译器”——Erik Duymelinck

Apple 确实推出了 iOS 8 和 OS X Yosemite

  • 2D、3D、4D 矢量马赫和几何。
  • CPU上C、Obj-C和C++中Metal的特点
  • 对特定于体系结构的 SIMD 以及类型和内在函数的抽象。
于 2014-07-27T18:21:10.037 回答