如何在OpenCL中充分利用SIMD?

时间:2015-10-31 14:24:58

标签: opencl gpgpu simd spmd

optimization guide of Beignet, an open source implementation of OpenCL targeting Intel GPUs

  

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

     

Gen上的两个可能的SIMD通道是8或16.不浪费SIMD   车道,我们需要遵循这条规则。

Compute Architecture of Intel Processor Graphics Gen7.5中也提到了

  

对于基于Gen7.5的产品,每个EU有七个线程,总共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 spec也提供了矢量数据类型。因此,通过传统的SIMD编程(如在NEON和SSE中)充分利用EU中的SIMD-16计算资源是可行的。

问题2:如果是这种情况,使用vector-16数据类型已经明确使用了SIMD-16资源,因此删除了至少16项的每项工作组限制。是这种情况吗?

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

1 个答案:

答案 0 :(得分:1)

  1. 几乎。您假设每个工作组有一个线程(在此上下文中的N.B.线程是CUDA称之为“wave”。在Intel GPU中,工作项是GPU线程的SIMD通道)。没有子组,就没有办法强制工作组大小完全是一个线程。例如,如果您选择WG大小为16,编译器仍然可以自由编译SIMD8并将其分布在两个SIMD8线程中。请记住,编译器在知道WG大小之前选择SIMD宽度(clCompileProgramclEnqueueNDRange之前)。 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传输的成本(算术密度)。
    • 如果你的意思是GPU线程(GEN SIMD8或SIMD16生物)。目前没有(公开可见的)方法明确地编程GPU线程(编辑请参阅subgroups extension(GEN7.5上不可用))。如果你能够,它将与汇编语言进行类似的交易。工作更难,编译器有时只能做得更好,但是当你解决特定问题并拥有更好的领域知识时,你通常可以通过足够的编程工作做得更好(直到硬件改变和你聪明的程序的假设)变得无效。)