如何在OpenCL中充分利用SIMD?

8

在Beignet的优化指南中,这是一个针对Intel GPU的开源OpenCL实现(链接)

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

Gen上有两个可能的SIMD通道,分别为8或16。为了不浪费SIMD通道,我们需要遵循这个规则。

Intel处理器图形Gen7.5的计算架构中也提到了这一点:

对于基于Gen7.5的产品,每个EU有七个线程,总共28 Kbytes的通用寄存器文件(GRF)。在Gen7.5计算架构上,大多数SPMD编程模型采用这种样式的代码生成和EU处理器执行。实际上,每个线程在其自己的SIMD lane中同时执行一定数量的kernel instances。因此,对于一个SIMD-16编译的计算内核来说,可能会在单个EU上并行地执行SIMD-16 x 7 threads = 112个内核实例。同样,对于SIMD-32 x 7 threads = 224的情况,也会在单个EU上并行地执行224个内核实例。如果我理解得正确,使用“SIMD-16 x 7 threads = 112 kernel instances”作为例子,在一个EU上运行224个线程,工作组大小需要为16。然后,OpenCL编译器将16个内核实例折叠成一个16个lane的SIMD线程,并在7个工作组上重复这个过程,然后在一个单独的EU上运行它们。

问题1:我现在的理解是正确的吗?

然而,OpenCL规范 也提供了向量数据类型。因此,通过常规的SIMD编程(如NEON和SSE),可以充分利用EU中的SIMD-16计算资源。

问题2:如果是这样,使用向量-16数据类型已经明确地利用了SIMD-16资源,因此消除了每个工作组至少16个项目的限制。是这样吗?

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

1个回答

1
  1. 几乎正确。你假设每个工作组只有一个线程(注意:在这种情况下,线程是CUDA所称的“wave”。在Intel GPU中,工作项是GPU线程的SIMD通道)。如果没有子组,就无法强制工作组大小恰好为一个线程。例如,如果选择WG大小为16,则编译器仍然可以编译SIMD8并将其分散到两个SIMD8线程中。请记住,在编译器知道WG大小之前(clCompileProgramclEnqueueNDRange之前),编译器会选择SIMD宽度。subgroups extension可能允许您强制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线程(EDIT请参阅subgroups extension(在GEN7.5上不可用))。如果您能够这样做,那么它将类似于汇编语言的折衷。工作更难,编译器有时比我们做得更好,但当您解决特定问题并具有更好的领域知识时,通常可以通过足够的编程工作做得更好(直到硬件发生变化并且您聪明的程序的假设被否定为止。)

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