7.1_概况

7.1 概况

CUDA内核程序在GPU上执行,并且从最早期的CUDA版本开始就一直与CPU并发执行。换句话说,内核启动是异步的:控制权会在GPU完成请求的操作之前返回给CPU。在CUDA最初引进时,开发者并不需要关心内核启动的异步执行(或缺少此机制)。此外,数据显式地复制到GPU并从GPU复制回,而内存复制命令则会在启动内核程序的命令请求后进行排队。想要通过编写CUDA代码来暴露内核启动的异步特性是不可能的,异步执行的主要附带作用是在连续执行多个内核启动时隐藏驱动程序的开销。

从前面对映射锁页内存(主机内存可以直接被GPU访问)的介绍中可以看出,特别是对于写入主机内存的(相反的,从其中读取的)内核程序而言,内核启动的异步执行是多么的重要。如果一个内核在没有显式同步(例如采用CUDA事件)的情况下启动或写入主机内存,代码将面临CPU与GPU之间的竞争并会出现运行错误。对于通过映射锁页内存进行读操作的内核,一般不需要显式同步,这是因为CPU的任何待定写操作都会在内核启动之前被发送出来。要是内核程序通过写入映射锁页内存来给CPU返回结果,就必须使用同步避免读后写了。

一旦内核启动,它以一个网格的形式运行,其中该网格包含多个线程块,每个线程块又由多个线程构成。但并非线程块的运行都是并

发的。每个线程块都被分配给一个SM,而每个SM都可以为多线程块维持上下文。为了掩盖内存和指令带来的延时,SM通常会需要多于单线程块可以包含的线程束(SM 2.0及以上,一个线程块最多可以包含1024条线程)。每个SM中线程块的最大数目是无法通过API查询的,但在英伟达文档中已经写明,该数目在SM 3.x版本之前的硬件中为8,SM 3.x及其之后的为16。

编程模型并不能保证执行的次序,抑或是某些线程块或线程是否可以并发运行。开发者一定不要假定内核启动中的所有线程都是并发执行的。通常很容易就启动了比机器所能维持的要多的线程,而且其中的一些在其他线程结束之前不会执行。鉴于线程次序无法确定,甚至连内核启动开始处进行全局内存的初始化都是个困难的任务。

动态并行——特斯拉K20(GK110)(第一个支持SM 3.5的GPU)中新增的特性,使内核程序可以启动其他的内核程序,并完成它们之间的同步。这些特性解决了一些以前的硬件上CUDA所呈现的局限性。例如,一个动态并行内核可以通过启动和等待一个子网格来完成初始化。