下面仍然针对NVIDIA当前最新的Maxwell架构GPU谈谈其执行模型。NVIDIA GPU架构由一组可扩展的多线程流处理器(SM)构成。当一个OpenCL程序在主机端调用一个内核程序NDRange执行时,工作组上的每个线程块(对应于AMD GPU的wavefront,只不过NVIDIA GPU中的一个线程块由32个连续的工作项构成)会被枚举,然后根据当前执行可用资源等情况分发到SM上。一个线程块中的所有工作项在一个SM上并发执行,并且在一个SM上可同时并发执行多个线程块。当一个SM上执行的线程块完成执行时,新的线程块能在被腾出来的SM上启动执行。这一点与AMD GPU的工作组调度执行也非常类似。
一个SM被设计为并发执行上百个工作项。为了要管理如此大量的工作项,SM引入了称为SIMT(单指令多线程)的独特架构。在单个线程内指令被流水线化管理并利用了指令级并行,并且广泛地通过硬件并发多线程机制利用线程级并行。当然,GPU与CPU不一样,它不包含分支预测,也没有投机执行引擎。
一个SM以32个并行线程(即工作项)为一单位创建、管理、调度以及执行这些线程,这一单位称为warp。组成一个warp的所有工作项一起在同一个程序地址处开始执行,但是它们具有各自的指令地址计数器以及寄存器状态,从而对于分支和执行都是相互独立的。
一个warp一次执行一条公共的指令,所以当一个warp的32个工作项走同一条执行路径时就能实现完整的效果。如果一个warp的工作项由于数据依赖而分岔到不同的条件分支,那么该warp会串行地执行每条所要走的分支路径,对于不在该路径上的工作项会禁止其执行,当所有路径都完成后,这些工作项会重新汇合到同一条执行路径。分支分叉只会发生在一个warp内;不同warp都是独立执行而不管它们执行一条公共的还是分叉的代码路径。
在warp上当前执行路径上的工作项被称为活跃工作项,而不在当前执行路径上的工作项被称为非活跃(禁用的)工作项。工作项处于非活动状态,可能因为它们比其他在同一warp中的工作项更早退出执行,或者是因为处于在当前warp所执行的不同分支路径上,又或者是因为它们是一个线程块最后的一些工作项,而这些工作项的个数并非warp大小的倍数。
如果由一个warp所执行的非原子指令,该指令由warp中多个工作项执行,并且写到全局存储器或局部存储器中同一个地址,那么这些工作组的写根据不同设备型号会有所不同,有些设备上这些写操作将被串行化,而有些可能直接被广播,从而使得最终写进去的内容是不确定的。
如果一个warp执行一条原子指令,那么对于该warp中多个工作项对全局存储器或局部存储器的同一地址执行读-修改-写操作时,每个读-修改-写操作依次发生并且被串行执行,但是最终访存操作发生次序是未定义的。
由一个SM所处理的每个warp的执行上下文(包括程序计数器、寄存器等)在该warp的整个生命周期内被维护着。因此,从一个执行上下文切换到另一个没有任何开销,并且在每条指令发射时,一个warp调度器选择其中一个已经准备好执行的warp执行其下一条指令(warp的活跃线程)并对那些线程发射该指令。