基本概念
-
主机: CPU+内存的组合;
-
设备: GPU+显存的组合;
-
运行时API: "CUDA运行时API"是在"驱动API"的基础上封装而成的,简化CUDA的开发;
-
驱动API: "CUDA驱动API”,相比于"运行时API"更接近于设备,可灵活运用设备的特性开发CUDA,可实现运行时API无法实现的功能;
-
warp:多处理器激活、管理、调度和执行并行任务的单位。计算能力2.x的设备warp为32个线程。未来的设备可能不同,可以通过内置变量warpSize查询;
-
bank:为了获得较高的存储器带宽,共享存储器被划分为多个大小相等的存储器模块,成为存储体,这些存储体叫做bank,可以同步访问;
-
函数类型限定符: CUDA C中特有,用来修饰是主机函数、设备调用的设备函数、还是主机调用的设备函数,有__device__、global、host;
-
变量类型限定符:修饰设备变量,有__device__、constant、shared;
-
thread: 设备中的线程,与主机中的线程是同一个概念;
-
block:线程块,由一组线程组成。一个线程块中的所有线程会在同一个多处理器上执行,一个多处理器上可以同时执行多个线程块;
-
grid:所有线程块组成的网格;
-
计算能力:是Nvidia GPU不同架构的计算能力;
-
SIMT:单指令多线程,与单指令多数据SIMD类似。一个指令多个线程一同执行,实现程序的并行化;
-
内置变量:有threadIdx, blockDim, blockIdx, gridDim, warpSize. threadIdx表示此线程在线程块中的位置,blockDim指线程块维度;blockIdx指线程块在网格中的位置;gridDim指线程块网格维度;warpSize指一个warp多少个线程;
-
纹理: 纹理参考、纹理绑定、纹理获取;
-
CUDA数组:区别于线性存储器,对数据进行了对齐等的处理,包括一维、二维和三维。其中的数据为:一元、二元或四元组;
线程thread(寄存器/本地存储器)->线程块block(共享存储器)->线程块网格grid(常量存储器/全局存储器/纹理存储器);
运行时API
运用“运行时API”开发CUDA程序需要了解:初始化、设备管理、存储器管理、流管理、事件管理、纹理参考管理、OpenGL互操作和Direct3D互操作;
参考文档
驱动API
驱动API是一种基于句柄、命令式的API,大多数对象都通过不透明的句柄引用。运用“驱动API”开发CUDA程序需要了解:初始化、设备管理、上下文管理、模块管理、执行控制、存储器管理、流管理、事件管理、纹理参考管理、OpenGL互操作、Direct3D互操作。
参考文档
注意:Cuda不支持windows的默认远程登录客户端mstsc登入远程主机执行设备,需要远程登录主机执行CUDA设备,可使用VNC工具。
性能优化
主要:warp中减少控制指令、合理使用共享内存、防止共享内存bank冲突、单个线程中寄存器的使用的量、block中线程数、常量存储器的合理利用、线程对全局存储器的合理访问等。
- 多处理器是以warp为单位处理线程的,有控制指令时,会执行完所有的控制指令对应的指令后才会继续执行下面的命令。例如,if/else语句两个方向的线程在同一个warp中,线程1执行if方向,线程2执行else方向,他们可能的执行顺序为:线程1执行if方向,2等待;线程1执行if方向完毕等待,2执行else方向;线程2执行else方向完毕,线程1和2共同执行后面的指令。
- 共享内存属于片上缓存,比全局存储器的读写速度快。将一部分全局存储器上的数据放入共享内存中处理可有效提高性能。共享存储器的访问速度和寄存器差不多,大约读写4B的数据需要两个时钟周期。共享存储器的读取是以半warp为单位的,当半warp中所有的线程都访问同一个bank中同一块4B的数据时也不会发生bank冲突,称为广播访问,此时只访问一次bank。每个多处理器中的共享存储器大小是有限的,应按照block的大小分配合适的共享存储器。Block的大小会影响多处理器每次激活的block数。
- 每个多处理器寄存器数量是有些的,而且在每个线程中寄存器是线程私有的。按照每个多处理器激活的线程数,合理分配寄存器。如果每个线程分配太多线程,则每个多处理器同时激活的线程数就会减少,从而影响并行效果。
- Block中的线程数(NThread)也会影响每个多处理器同时激活的线程数。每个多处理器有最大同时激活线程数(NMThread),且每个多处理器有最大同时激活block数(NMBlock)。Block中的线程数满足:NThread >= NMThread / NMBlock会激活在一个多处理器中可激活的所有block。在其他资源可充分利用的情况下,多处理器上同时激活的线程数越多,效率越高。
- 常量存储器也是带片上缓存的存储器。充分利用常量存储器可有效提升性能。
- 最新的设备,全局存储器都带有片上缓存。可以利用多处理器处理线程的特性合理访问全局存储器的数据,可使更多数据命中。