假设我有两个任务要在 GPU 上运行,第二个任务基本上依赖第一个任务的所有工作。传统上,我基本上必须将这些任务编写为两个单独的内核,并安排第二个在第一个之后的某个时间运行。但是 - 使用 CUDA 9,我现在可以在整个网格上同步,完成第一个任务的工作 -使用协作组功能,然后继续让网格完成第二个任务的工作。
我的问题是:
- 我们能否就编写两个内核的性能以及何时使用全网格同步提供一个经验法则?
- 如果是这样,那会是什么?
- 如果不是 - 为什么很难确定在哪些情况下哪个更可取?
假设我有两个任务要在 GPU 上运行,第二个任务基本上依赖第一个任务的所有工作。传统上,我基本上必须将这些任务编写为两个单独的内核,并安排第二个在第一个之后的某个时间运行。但是 - 使用 CUDA 9,我现在可以在整个网格上同步,完成第一个任务的工作 -使用协作组功能,然后继续让网格完成第二个任务的工作。
我的问题是:
将此作为 CW 答案,以便其他人随意添加他们的意见和编辑。
协作组中的网格范围同步功能需要将线程补充(网格的大小)限制为您正在运行的 GPU 的承载能力。这不是主要的性能限制因素,但它要求您编写可以灵活使用不同网格大小的代码,同时仍能实现最大性能。 网格步长循环是这种编码策略的典型组成部分。
因此,网格范围的同步功能通常需要仔细编码和额外的代码开销(例如使用占用 API)才能实现最大性能,尤其是与简单或幼稚的内核相比。
为了抵消程序员生产力的这种可能的降低,一些可能的好处是:
在启动开销占整个运行时间的很大一部分的情况下,协作式全网格同步可能会带来显着的好处。除了融合 2 个单独的内核之外,可能会在循环中调用内核的算法(例如 jacobi 迭代/松弛或其他时间步长模拟算法)可能会显着受益,因为启动循环可以有效地“移动到 GPU 上”,用单个内核调用替换内核启动循环。
在存在大量片上“状态”(例如寄存器内容、共享内存内容)的情况下,需要在网格范围同步之前加载,并将在网格范围同步之后使用,那么合作组可能是一个重大的胜利,节省了内核中遵循网格范围同步的时间,这将用于重新加载状态。例如,这似乎是这里的动机(参见第 4.3 节)。我并不是说他们在使用合作小组(他们不是)。我建议他们使用当时可用的临时方法来寻求网格范围的同步,以消除状态重新加载的成本,以及可能的内核启动开销的成本。