8

Beignet 的优化指南中,针对英特尔 GPU 的 OpenCL 开源实现

工作组大小应大于 16 并且是 16 的倍数。

由于 Gen 上两个可能的 SIMD 通道是 8 或 16。为了不浪费 SIMD 通道,我们需要遵循此规则。

在Intel Processor Graphics Gen7.5的计算架构中也提到:

对于基于 Gen7.5 的产品,每个 EU 有 7 个线程,总共 28 KB 的通用寄存器文件 (GRF)。

...

在 Gen7.5 计算架构上,大多数 SPMD 编程模型采用这种风格的代码生成和 EU 处理器执行。实际上,每个SPMD 内核实例似乎都在其自己的 SIMD 通道内连续且独立地执行

实际上,每个线程同时执行一个 SIMD-Width 数量的内核实例。因此,对于计算 内核的 SIMD-16 编译,SIMD-16 x 7 线程 = 112 个内核实例 可以在单个 EU 上同时执行。同样,对于 SIMD-32 x 7 线程 = 224 个内核实例在单个 EU 上同时执行。

如果我理解正确,SIMD-16 x 7 threads = 112 kernel instances以 为例,为了在一个 EU 上运行 224 个线程,工作组大小需要为 16。然后 OpenCL 编译器会将 16 个内核实例折叠成一个 16 通道 SIMD 线程,并执行此操作在 7 个工作组上运行 7 次,然后在一个 EU 上运行它们?

问题1:直到这里我是正确的吗?

然而OpenCL 规范也提供向量数据类型。因此,通过传统的 SIMD 编程(如在 NEON 和 SSE 中)充分利用欧盟的 SIMD-16 计算资源是可行的。

问题 2:如果是这种情况,使用 vector-16 数据类型已经明确使用 SIMD-16 资源,因此消除了 at-least-16-item-per-work-group 限制。是这样吗?

问题3:如果以上都成立,那么这两种方法如何相互比较:1) OpenCL编译器将112个线程折叠成7个SIMD-16线程;2) 7 个本机线程被编码为明确使用向量 16 数据类型和 SIMD-16 操作?

4

1 回答 1

1
  1. 几乎。您假设每个工作组有一个线程(在这种情况下,NB 线程是 CUDA 所称的“波”。在英特尔 GPU 中,工作项是 GPU 线程的 SIMD 通道)。如果没有子组,就无法强制工作组大小正好是一个线程。例如,如果您选择 WG 大小为 16,编译器仍然可以自由编译 SIMD8 并将其分布在两个 SIMD8 线程中。请记住,编译器在知道 WG 大小之前选择 SIMD 宽度(clCompileProgram先于clEnqueueNDRange)。子组扩展可能允许您强制 SIMD 宽度,但绝对不会在 GEN7.5 上实现。

  2. OpenCL 向量类型是在已经自动发生的隐式向量化之上的可选显式向量化步骤。以你float16为例。每个工作项将处理 16 个浮点数,但编译器仍将至少编译 SIMD8。因此,每个 GPU 线程都将处理 (8 * 16) 个浮点数(尽管是并行的)。这可能有点矫枉过正。理想情况下,我们不希望通过使用显式 OpenCL 向量类型来显式向量化我们的 CL。但有时如果内核没有做足够的工作(太短的内核可能不好),它有时会有所帮助。它在某处说 float4 是一个很好的经验法则。

  3. 我想你的意思是 112 个工作项?本地线程是指 CPU 线程还是 GPU 线程?

    • 如果您指的是 CPU 线程,则适用于有关 GPU 的常见论点。当您的程序差异不大(所有实例都采用相似的路径)并且您使用数据足够多的时间来降低将其传入和传出 GPU 的成本(算术密度)时,GPU 是很好的。
    • 如果您指的是 GPU 线程(GEN SIMD8 或 SIMD16 小动物)。目前没有(公开可见的)方法来显式地对 GPU 线程进行编程(编辑参见子组扩展(在 GEN7.5 上不可用))。如果可以的话,这将是与汇编语言类似的权衡。这项工作更难,编译器有时会比我们做得更好,但是当您解决特定问题并拥有更好的领域知识时,通常可以通过足够的编程工作做得更好(直到硬件更改和您聪明的程序的假设变为无效。)
于 2015-10-31T23:07:39.520 回答