GPU 内核如何相互通信?



GPU在用于通用计算时,非常强调与SIMD和SIMT的细粒度并行性。它们在具有高算术强度的常规数字处理工作负载上表现最佳。

尽管如此,为了适用于尽可能多的工作负载,它们还必须能够实现粗粒度 MIMD 并行性,其中不同的内核在不同的数据块上执行不同的指令流。

这意味着 GPU 上的不同内核在执行不同的指令流后必须相互同步。他们是怎么做到的?

在 CPU 上,答案是存在缓存一致性以及一组选择与 CAS 或 LL/SC 等良好配合使用的通信原语。但据我了解,GPU 没有缓存一致性 - 避免这样的开销是它们首先比 CPU 更高效的最大原因。

那么GPU核心之间用什么方法进行同步呢?如果它们如何交换数据的答案是通过写入共享主内存,那么它们如何同步,以便发送方可以通知接收方何时读取数据?

如果答案取决于特定的架构,那么我对支持 CUDA 的现代 Nvidia GPU 特别感兴趣。

编辑:从Booo链接的文档来看,这是我到目前为止的理解:

他们似乎使用"流"这个词来表示同步完成的大量工作(包括像SIMD这样的细粒度并行性);问题是如何在多个流之间同步/通信。

正如我推测的那样,这比在 CPU 上要明确得多。 特别是,他们谈到:

  • 页面锁定内存
  • cudaDeviceSyncing ()
  • cudaStreamSync ( streamid )
  • cudaEventSync
  • (事件)

因此,流可以通过将数据写入主内存(或L3缓存?)进行通信,并且没有像CPU上的缓存一致性那样,而是有锁定的内存页和/或显式同步API。

我的理解是,有几种方法可以使用 CUDA "同步":

  • CUDA 流(在功能级别):cudaDeviceSynchronize()在整个设备上同步。此外,您可以将特定流与cudaStreamSynchronize(cudaStream_t stream)同步,或者将嵌入在某些流中的事件与cudaEventSynchronize(cudaEvent_t event)同步。参考文献 1, 参考文献 2.

  • 协作组(>CUDA 9.0 和>CC 3.0):您可以在组级别进行同步,组可以是一组合并线程、线程块或跨多个设备的网格。这要灵活得多。使用 定义您自己的组

    (1) 当前合并的线程集的auto group = cooperative_groups::coalesced_threads(),或

    (2)auto group = cooperative_groups::this_thread_block()对于当前线程块,可以在块内进一步定义细粒度组,例如auto group_warp = cooperative_groups::tiled_partition<32>(group),或

    (3) 跨多个设备的网格auto group = cooperative_groups::this_grid()auto group = cooperative_groups::this_multi_grid()

    然后,您只需调用group.sync()进行同步。您需要拥有支持cooperativeLaunchcooperativeMultiDeviceLaunch的设备。请注意,对于合作组,您已经可以在共享内存中执行传统的块级同步,__syncthreads()。参考文献 1, 参考文献 2.

相关内容

  • 没有找到相关文章

最新更新