GPU 中的同步

Posted

技术标签:

【中文标题】GPU 中的同步【英文标题】:Synchronizations in GPUs 【发布时间】:2011-10-04 07:39:26 【问题描述】:

我对 GPU 如何执行同步有一些疑问。 据我所知,当一个经线遇到障碍时(假设它在 OpenCL 中),它知道同一组的其他经线还没有出现。所以它必须等待。但是,在等待期间,这个经线到底做了什么? 它仍然是一个活跃的经线吗?或者它会做某种空操作吗?

我注意到,当我们在内核中进行同步时,指令数量会增加。我想知道这个增量的来源是什么。同步是否分解为许多较小的 GPU 指令?还是因为空闲的 warp 执行了一些额外的指令?

最后,我非常想知道,与没有同步的情况相比,同步所增加的成本(比如说屏障(CLK_LOCAL_MEM_FENCE))是否受工作组(或线程块)中的扭曲数量的影响? 谢谢

【问题讨论】:

【参考方案1】:

一个活跃的warp是一个驻留在SM上的warp,即所有资源(寄存器等)都已分配,并且warp可用于执行,前提是它是可调度的。如果一个 warp 在同一个线程块/工作组中的其他 warp 之前到达障碍,它仍然是活动的(它仍然驻留在 SM 上并且它的所有寄存器仍然有效),但它不会执行任何指令,因为它是尚未准备好安排。

插入屏障不仅会停止执行,还会充当编译器的屏障:编译器不允许跨屏障执行大多数优化,因为这可能会使屏障的目的无效。这是您看到更多指令的最可能原因 - 没有障碍,编译器能够执行更多优化。

屏障的成本很大程度上取决于您的代码在做什么,但是每个屏障都会引入一个气泡,在该气泡中,所有经线都必须(有效地)在它们重新开始工作之前变得空闲,所以如果您有一个非常大的线程块/那么工作组当然有可能比一个小块更大的泡沫。气泡的影响取决于您的代码 - 如果您的代码非常受内存限制,那么屏障将在可能隐藏之前暴露内存延迟,但如果更加平衡,则可能会产生不太明显的影响。

这意味着在一个非常受内存限制的内核中,您最好启动大量较小的块,以便当一个块在屏障上冒泡时可以执行其他块。您需要确保占用率因此增加,并且如果您使用块共享内存在线程之间共享数据,则需要进行权衡。

【讨论】:

感谢您的详细回答。如果您可以分享一些您从中获得知识的文档,那就太好了。我想在我的研究中引用。你能解释一下为什么内存绑定内核会暴露内存延迟吗?正如我现在所了解的那样,应该被某些计算隐藏的同步附近的内存请求(出现在同步之前)将被停止,直到数据到达。这是正确的吗?另一方面,如果内核不是内存绑定的,那么同步会暴露什么?指令流水线延迟? (假设没有分歧,是的,这一切与分歧有什么关系?)

以上是关于GPU 中的同步的主要内容,如果未能解决你的问题,请参考以下文章

在 CPU 和 GPU 之间同步静态分配的结构实例

Android中的GraphicBuffer同步机制-Fence

GPU怎么优化?

MPI+OpenACC编程中的GPU间通信

cuda学习3-共享内存和同步

我正在使用 systrace 对其 GPU 的 android 应用程序进行性能调查。 systrace 中的“GPU 完成”线程是啥意思