两个连续的内核或全网格协作组同步?

Two consecutive kernels or whole-grid cooperative group synchronization?

假设我有两个任务要在 GPU 上 运行,其中第二个任务基本上依赖于第一个任务的所有工作。传统上,我基本上必须将这些任务编写为两个单独的内核,并在第一个之后的某个时间安排第二个到 运行。但是 - 使用 CUDA 9,我现在可以在整个网格上同步完成其在第一个任务上的工作 - using the cooperative groups feature,然后继续让网格完成其第二个任务工作。

我的问题是:

将此作为 CW 答案,以便其他人可以随意添加他们的意见和编辑。

grid-wide sync feature in cooperative groups carries with it a requirement to limit the thread complement (size of the grid) to whatever is the carrying capacity of the GPU you are running on. This isn't a major performance limiter, but it requires you to write code that can flexibly use different grid sizes while still achieving max performance. grid-stride loops 是此类编码策略的典型组成部分。

因此,网格范围的同步功能通常需要仔细编码和额外的代码开销(例如使用占用 API)以实现最佳性能,尤其是与简单或朴素的内核相比。

为了抵消这种可能降低的程序员工作效率,一些可能的好处是:

  1. 在启动开销占整个运行时间很大一部分的情况下,协作式网格范围的同步可能会带来显着的好处。除了融合 2 个独立的内核之外,可以在循环中调用内核的算法,例如 jacobi iteration/relaxation 或其他时间步模拟算法,可能会显着受益,因为启动循环可以有效地 "moved onto the GPU" , 用单个内核调用替换内核启动循环。

  2. 在片上有大量"state"(例如寄存器内容,共享内存内容)的情况下,需要在全网同步之前加载,并且将在网格范围同步之后使用,那么合作组可能是一个重要的胜利,节省了内核中本应遵循网格范围同步的时间,这些时间将用于重新加载状态。例如,这似乎是动机 here(参见第 4.3 节)。我不是在暗示他们在使用合作小组(他们没有)。我建议他们积极寻求网格范围的同步,使用当时可用的临时方法,以消除状态重新加载的成本,以及可能的内核启动开销成本。