OpenCL 工作组是否同时执行?

Are OpenCL workgroups executed simultaneously?

我的理解是,每个工作组都在GPU上执行,然后再执行下一个。

不幸的是,我的观察得出的结论是这是不正确的。 在我的实现中,所有工作组共享一个大的全局内存缓冲区。 所有工作组对该缓冲区的不同位置执行读写操作。

如果内核直接对其进行操作,则不会产生冲突。 如果工作组将块加载到本地内存,执行一些计算并将结果复制回来,则全局内存会被其他工作组破坏。

那么我该如何避免这种行为呢?

我能否以某种方式告诉 OpenCL 一次只执行一个工作组或重新安排执行顺序,这样我就不会以某种方式发生冲突?

答案是视情况而定。整个工作组必须在设备上同时执行(尽管不一定并行),至少在存在障碍时是这样,因为工作组必须能够同步和通信。没有规则说工作组必须并发——但也没有规则说他们不能。通常硬件会将单个工作组放置在单个计算核心上。大多数硬件都有多个内核,每个内核都会有一个工作组,为了弥补延迟,如果有可用容量,许多硬件还会将多个工作组放在一个内核上。

您无法控制工作组执行的顺序。如果您希望它们序列化,您最好只启动一个工作组并在内部编写一个循环以序列化同一工作组中的一系列工作块。即使有多个工作组,这通常也是一个很好的策略。

如果您真的一次只需要一个工作组,那么您可能只会使用硬件的一小部分。大多数硬件无法在整个设备上分布单个工作组 - 因此,如果您坚持使用 32 核 GPU 上的一个核心,您将无法充分利用该设备。

您需要将全局大小和维度设置为单个工作组的大小,并为每个组排队一个新的 NDRange。本质上,将对内核的调用分解为许多较小的调用。确保您的命令队列不允许乱序执行,这样内核调用就会阻塞。

这可能会导致性能下降,但您将获得所需的专用全局内存访问。

是的,组可以并行执行;这通常是一件非常好的事情。 Here is a related question.

可以在 ComputeUnit (AMD) 或 SMX (Nvidia) 上同时启动的工作组数量取决于 GPU 硬件资源的可用性,重要的是矢量寄存器和工作组级内存**(称为AMD 的 LDS 和 Nvidia 的共享内存)。如果您只想在 CU/SMX 上启动一个工作组,请确保该工作组消耗大量这些资源并阻止同一 CU/SMX 上的其他工作组。但是,您仍然会有其他工作组在其他 CUs/SMXs 上执行 - GPU 通常有多个这样的工作组。 我不知道有任何 API 可以让您将内核固定到单个 CU/SMX.

** 它还取决于调度程序可以处理的并发数 wavefronts/warps。