相邻工作项上的 OpenCL 矢量化
Posted
技术标签:
【中文标题】相邻工作项上的 OpenCL 矢量化【英文标题】:OpenCL vectorization on adjacent workitems 【发布时间】:2016-12-08 22:19:10 【问题描述】:假设我有一个 OpenCL 内核,其中每个工作项执行一次 int_32 操作,并且我的 GPU 支持 256 位 SIMD 操作,OpenCL 是否能够将 8 个工作项打包在一起以利用 SIMD?即一个处理单元同时执行多个工作项。如果是这样,那么什么时候会发生这种情况?在“clBuildProgram”阶段,还是在 GPU 上实际执行二进制文件时(JIT 编译)?
第二个似乎更合理,因为这只能在我定义工作组大小后决定,例如,如果我说每个工作组 1 个工作项,那么矢量化就不会发生?
我在“clBuildProgram”之后查看了 Nvidia ptx 文件,我仍然看到了标量 IR,但我不确定是 Intel 还是 AMD。
【问题讨论】:
【参考方案1】:一般来说,如果 GPU 要对您的数据执行 SIMD 指令,它将决定何时编译您的代码(无论是通过在线编译器,还是通过离线编译器)。它可能不会根据您定义工作组的方式/时间来决定。
至于你的数据是否会被矢量化……那就有点复杂了。
这取决于您如何准确地布置数据和内核逻辑,以及(可能是在线的)编译器选择多少来优化您的代码。它还很大程度上取决于实际的硬件,但我稍后会谈到。
矢量数据类型(如float4
、int4
、float8
等)是最容易矢量化的,而且可能甚至不需要优化通过,因为代码非常明确地说“这些数据都属于一起,并且(可能)将对其应用相同的操作,所以如果你有硬件来做到这一点 (但正如我将在下面解释的那样,那就是一个相当大的 'if') 让我们对这些类型使用 SIMD 指令!”
除非你有一个非常聪明的编译器,否则标量数据类型可能不会被优化。不是每个编译器都能解决“嗯,你有int
s 称为i1
、i2
、i3
、i4
,它们都应用了相同的操作,所以让我们 SIMD 吧!”。
工作组内的标量数据类型几乎肯定不会被矢量化。它们仍将同时执行(因为如果不是,那我们为什么还要编写 GPGPU 代码????)但编译器和运行时几乎肯定无法围绕它们进行优化。
编辑:正如所指出的,有Compiler Tricks 可以使这种矢量化成为可能。但值得记住的是,这些技巧发生在编译时,而不是运行时,这意味着它高度依赖于代码的编写方式,以及使用哪个编译器(以及哪些优化标志,如果它们存在)来编译内核代码。
最重要的是要记住,所有这些都取决于您卡的硬件功能。至少在消费级计算卡(翻译:GPU)中,硬件工程师实际上并没有对其矢量化能力进行重大升级,事实上,他们经常选择减少矢量化以专注于制造更小的内核,然后他们可以堆叠更多到芯片上。例如,拥有一张具有 128 个内核的卡,每个内核都可以执行 256 位 SIMD 指令,这是一种很好的奢侈,但通常情况下,拥有一张没有(或不能)的小内核的卡要容易得多t) 处理 SIMD 指令,并简单地堆叠如此多的内核(如 NVidia 最近推出的 4k 以上),这些内核可以简单地并行运行,执行相同的工作(通常更快),而不依赖于程序员编写明确的 SIMD 指令。
我确实相信(但不要引用我的话)AMD 和 NVidia 都保证浮点数的 128 位矢量化,因为 float4
-type 对象在图形编程中非常常见,如果你正在做任何类型的图形处理(这是这类应用程序的标准)他们将从对这类对象的 SIMD 操作中受益匪浅,但任何非可能不会看到任何 SIMD 优化的东西。
【讨论】:
AMD GCN 对每个波前都有 16 宽度的 SIMD(每个 cu 有 4 个),因此它应该在硬件级别处理 float16,并且在向量元素之间转换可能有更多增益。最新的 AMD(vega 或 somthing)将在硬件级别同时具有 16、8、4、2、1、1,因此无论您提供什么,它将在硬件上(例如使用 16+8+4+2 的 30 或使用 15 8+4+2+1) @huseyintugrulbuyukisik 我承认对 AMD 的硬件有一定程度的无知,但 IIRC,“波前”不是单核,它们是核心组。因此,您所描述的更多的是对如何提交和执行工作组的优化。所以这更像是我在回答的倒数第二段中所说的。 对于您的第三点“几乎可以肯定跨不同工作组的标量数据类型不会被矢量化”,您是说跨不同的工作项吗?我同意跨工作组没有办法进行矢量化,但我读了这个llvm.org/devmtg/2011-11/Rotem_IntelOpenCLSDKVectorizer.pdf,我觉得英特尔可以跨工作项进行矢量化。 @Han 该演示文稿中讨论的是我在第二点中所讨论的内容,特别聪明的编译器将使用技巧来尝试将指令合并在一起。再说一遍:这是在编译时完成的,而不是在您定义工作组大小的时候。是的,引用“内部”工作组可能更相关,而不是跨工作组:我会更新语言。 @Xirema 我假设您将编译时间称为“clBuildProgram”,并且在您的第四点“这种矢量化”意味着对相邻内核进行矢量化,那么我的问题是编译器如何在我之前做到这一点定义工作组大小?就像我的问题一样,如果我说每个工作组有 1 个工作项,那么 GPU 应该无法找到另一个工作项来进行矢量化,因为我认为不允许工作组之间的通信。所以我认为这必须在运行时发生。 (或者您实际上是在将“这种矢量化”提到您的第二点?)以上是关于相邻工作项上的 OpenCL 矢量化的主要内容,如果未能解决你的问题,请参考以下文章