是否可以保证WaveFront(OpenCL)中的所有线程始终同步?

时间:2017-02-15 20:13:22

标签: concurrency opencl gpgpu amd simd

众所周知,有WARP(在CUDA中)和WaveFront(在OpenCL中):http://courses.cs.washington.edu/courses/cse471/13sp/lectures/GPUsStudents.pdf

enter image description here

  

4.1。 SIMT架构

     

...

     

warp一次执行一条通用指令,因此效率很高   当warp的所有32个线程都同意它们的执行时实现   路径。如果warp的线程通过数据相关的条件发散   分支,warp连续执行每个分支路径,禁用   不在该路径上的线程,当所有路径完成时,   线程会聚回同一个执行路径。分支分歧   仅在经线内发生; 不同的warp独立执行   无论他们是执行公共代码还是不相交代码   路径。

     

SIMT架构类似于SIMD(单指令,多指令)   数据)矢量组织中的单个指令控制   多个处理元素。一个关键的区别是SIMD矢量   组织将SIMD宽度暴露给软件,而SIMT   指令指定单个的执行和分支行为   线程。

  

在运行时,第一个wavefront被发送到计算单元   运行,然后将第二个波前发送到计算单元,依此类推。   在一个wavefront中处理项目并行执行锁定   步骤即可。但不同的波前顺序执行

即。我们知道,那个:

  • WARP (CUDA)中的线程 - 是SIMT线程,每次始终执行相同的指令并始终保持同步 - 即线程WARP与lanes of SIMD(在CPU上)

  • 相同 WaveFront (OpenCL)中的线程 - 是线程,它们总是并行执行,但不一定所有线程都执行完全相同的指令,并不一定所有线程都是同步的

但是,是否可以保证WaveFront中的所有线程始终同步,例如WARP中的线程或SIMD中的通道?

结论

  1. WaveFront-threads(项目)始终是同步的 - 锁定步骤" wavefront以锁定步骤相对于彼此执行多个工作项。"
  2. WaveFront映射到SIMD-block " wavefront中的所有工作项都转到两个流量控制路径"
  3. 即。 每个WaveFront-thread(项目)映射到SIMD-lanes
  4. 第20页:http://developer.amd.com/wordpress/media/2013/07/AMD_Accelerated_Parallel_Processing_OpenCL_Programming_Guide-rev-2.7.pdf

      

    第1章OpenCL架构和AMD加速并行处理

         

    1.1术语

         

    ...

         

    Wavefronts和工作组是与计算相关的两个概念   提供数据并行粒度的内核。 wavefront   相对于每个工作项执行锁定步骤中的多个工作项   其他。 在矢量上并行执行16个工作项   单位,整个波前覆盖四个时钟周期。它   是流量控制可以影响的最低级别。这意味着如果   波前的两个工作项目是不同的流动路径   控制, wavefront中的所有工作项都转到两个流程路径   控制

    适用于:http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_OpenCL_Programming_Optimization_Guide2.pdf

    • (第45页)第2章 GCN设备的OpenCL性能和优化
    • (第81页)第3章常青树和北部群岛设备的OpenCL性能和优化

2 个答案:

答案 0 :(得分:1)

首先,您可以查询一些值:

CL_DEVICE_WAVEFRONT_WIDTH_AMD
CL_DEVICE_SIMD_WIDTH_AMD
CL_DEVICE_WARP_SIZE_NV
CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE

但据我所知,仅来自主办方。

让我们假设这些查询返回64并且您的问题重视线程的隐式同步。

如果有人选择当地范围= 4怎么办?

由于opencl从开发人员中抽象出硬件时钟,因此您无法知道运行时内核执行中的实际SIMD或WAVEFRONT大小。

例如,AMD NCU有64个着色器,但它有16个宽SIMD,8个宽SIMD,4个宽SIMD,2个宽SIMD,甚至两个标量单元位于同一个计算单元内。

可以在两个标量和一个2宽单元或任何其他SIMD组合上共享4个本地线程。内核代码无法知道这一点。即使它以某种方式知道计算事物,你也无法知道在运行时在随机计算单元(64个着色器)中下一个内核执行(甚至下一个工作组)将使用哪个SIMD组合。 < / p>

或者其中有4x16个SIMD的GCN CU可以为每个SIMD分配1个线程,使所有4个线程完全独​​立。如果他们都住在同一个SIMD,你很幸运。无法保证知道“之前”内核执行。即使您知道,下一个内核可能会有所不同,因为无法保证选择相同的SIMD分配(后台内核,三维可视化软件,甚至操作系统都可能在管道中放置气泡)

无法保证命令/提示/查询N个线程在内核执行之前作为相同的SIMD或相同的WARP运行。然后在内核中,没有命令获取线程的波前索引,就像get_global_id(0)一样。然后在内核之后,您不能依赖于数组结果,因为下一次内核执行可能不会使用相同的SIMD来完成相同的项目。甚至来自其他波前的一些项目也可以与当前波前的项目进行交换,只是为了通过驱动程序或硬件进行优化(nvidia最近有负载均衡器,本来可以这样做,amd的NCU也可能在将来使用类似的东西)

即使您猜测硬件和驱动程序上的SIMD上的线程组合正确,但在另一台计算机上可能完全不同。

如果从性能的角度来看,您可以尝试:

  • 内核代码中的零分支
  • 在后台运行零内核
  • gpu未用于监视器输出
  • gpu未用于某些可视化软件

为了确保%99概率,管道中没有气泡,因此所有线程在同一周期退出指令(或者至少在最近退休的情况下同步)。

或者,在每个指令之后添加一个围栏,以便在全局或本地内存上进行同步,这非常慢。 Fences使工作级别同步,障碍使本地组级别同步。没有波前同步命令。

然后,在同一SIMD内运行的那些线程将表现为同步。但是你可能不知道那些线程和哪些SIMD。

对于4线程示例,使用float16进行所有计算可能会让驱动程序使用16位宽的AMD GCN CU SIMD进行计算,但之后它们不再是线程,只有变量。但是这应该比数据更好地同步数据。

还有更复杂的情况,例如:

  • 同一SIMD中的4个线程,但是一个线程计算会生成一些NaN值,并进行额外的规范化(可能需要1-2个周期)。其他3个人应该等待完成,但它与数据相关的减速无关。

  • 同一波阵面中的4个线程处于循环中,其中一个线程永远停留。其中3个等待第4个永远完成或驱动程序检测并将其移动到另一个自由空的SIMD?或者第4个同时等待其他3个因为它们也没有移动!

  • 4个线程一个接一个地进行原子操作。

  • Amd的HD5000系列gpu的SIMD宽度为4(或5),但波前尺寸为64.

答案 1 :(得分:1)

Wavefronts保证锁步。这就是为什么在较旧的编译器上,如果本地组只包含一个wavefront,则可以省略同步。 (您不能再在较新的编译器上执行此操作,他们会解释错误的依赖关系,并为您提供错误的代码。但另一方面,如果您的本地组只包含一个wavefront,则较新的编译器会省略同步。)

一个流处理器就像CPU的一个核心。它将重复运行一次16宽矢量指令四次,以完成64个所谓的&#34;线程&#34;在波前。实际上,一个wavefront比我们在GPU上称为线程的线程更多。