CUDA 10添加了运行时API调用,用于将流(=队列)置于“捕获模式”,以便在执行“图形”时返回而不是执行。然后可以使这些图实际执行,也可以将其克隆。
但是此功能背后的原理是什么?难道两次执行同一张“图形”是不可能的吗?毕竟,即使您确实运行“相同的代码”,至少数据也是不同的,即内核采用的参数可能会更改。或者-我错过了什么吗?
PS-我略读了this slide deck,但还是听不懂。
答案 0 :(得分:1)
任务图非常可变。
有用于更改/设置各种任务图节点参数的API调用,因此一个可以使用任务图作为模板,从而不必在每次执行之前先排队各个节点,则在每次执行之前更改每个节点的参数(也许并不是所有节点实际上都需要更改其参数)。
例如,请参阅cudaGraphHostNodeGetParams and cudaGraphHostNodeSetParams的文档。
答案 1 :(得分:1)
我对图形的经验确实是,它们并不是那么易变。您可以使用'cudaGraphHostNodeSetParams'更改参数,但是为了使参数更改生效,我不得不使用'cudaGraphInstantiate'重建图形可执行文件。这个调用花费了很长时间,以至于失去了使用图形的任何收益(就我而言)。仅当我手动构建图形时,设置参数才对我有用。通过流捕获获取图形时,由于您没有节点指针,因此无法设置节点的参数。您会认为在流捕获图上调用'cudaGraphGetNodes'将返回您的节点。但是,即使'numNodes'变量具有正确的数字,返回的节点指针对我来说还是NULL。该文档明确提到了这种可能性,但是没有解释原因。
答案 2 :(得分:1)
另一个有用的功能是并发内核执行。在手动模式下,可以在图中添加具有依赖性的节点。它将使用多个流自动探索并发性。该功能本身不是新增功能,但是使其自动运行对于某些应用程序很有用。
答案 3 :(得分:0)
在训练深度学习模型时,经常发生的是,以相同的顺序重新运行同一组内核,但使用更新的数据。另外,我希望Cuda通过静态了解下一个内核会进行优化。我们可以想象Cuda在了解整个图形时可以获取更多指令或调整其调度策略。
答案 4 :(得分:0)
CUDA Graphs 正试图解决在存在太多小内核调用的情况下,您会看到相当多的时间花费在 GPU 的 CPU 调度工作上(开销)。
它允许您交换资源(时间、内存等)来构建内核图,您可以使用来自 CPU 的单次调用而不是进行多次调用。如果你没有足够的调用,或者你的算法每次都不同,那么构建图就不值得了。
这对于任何在底层使用相同计算的迭代都非常有效(例如,需要收敛到某些东西的算法)并且它在许多非常适合 GPU 的应用程序中非常突出(例如,想想 {{3 }}).
如果你有一个只调用一次的算法或者如果你的内核很大,你不会看到很好的结果;在这种情况下,CPU 调用开销不是您的瓶颈。 Jacobi method 中有关于何时需要它的简洁说明。
基于任务图的范式闪耀的地方在于,当您将程序定义为在它们之间具有依赖关系的任务时。您为驱动程序/调度程序/硬件提供了很大的灵活性,以便在无需开发人员进行太多微调的情况下自行调度。我们花费数年时间探索 HPC 中 Getting Started with CUDA Graphs 的想法是有原因的。