在Pascal架构上如何处理嵌套分支?

时间:2018-11-16 15:38:55

标签: cuda

在阅读CUDA编程指南时:

https://docs.nvidia.com/cuda/cuda-c-programming-guide/#simt-architecture

我遇到了以下段落:

  

在Volta之前,warp使用了在warp中所有32个线程之间共享的单个程序计数器,以及指定了warp的活动线程的活动掩码。结果,来自不同区域或相同执行状态的同一线程的线程无法相互发出信号或交换数据,而需要细粒度共享由锁或互斥锁保护的数据的算法很容易导致死锁,具体取决于哪个线程。竞争线程来自。

但是,在同一部分的开头,它说:

  

组成经线的各个线程从同一程序地址一起开始,但是它们具有自己的指令地址计数器和寄存器状态,因此可以自由分支和独立执行。

另一段似乎与之矛盾,因为它提到线程具有自己的程序计数器,而第一段声称它们没有。

当程序具有嵌套分支(例如if语句)时,如何处理此活动掩码?

如果假定线程没有自己的程序计数器,线程如何知道何时不需要执行的发散部分完成?

1 个答案:

答案 0 :(得分:1)

这个答案是高度推测性的,但是基于现有的信息和一些有根据的猜测,我相信它在Volta之前的工作方式是每个扭曲基本上都具有一堆“返回地址”以及有效掩码或实际上可能是活动掩码的倒数,即返回后用于运行分支另一部分的掩码。通过这种设计,每个经线在任何时间点只能有一个活动分支。结果是,warp调度程序只能调度warp的一个活动分支。这使得公平,无饥饿的调度成为不可能,并带来了过去曾经存在的所有限制,例如,关于锁的限制。

我相信他们对Volta所做的基本工作是,每个分支(甚至可能每个线程)现在都有一个单独的堆栈和程序计数器;每个线程是否具有自己的物理程序计数器,或者是否每个线程都应该在功能上没有区别每个分支有一个共享的程序计数器;如果您真的想了解该实现细节,则可以根据检查堆栈空间用完的那一点来设计一些实验。此更改为所有当前分支提供了明确的表示形式,并使warp调度程序可以随时从任何分支中选择要运行的线程。结果,可以使warp调度免于饥饿,从而摆脱了早期体系结构的许多限制。