人们为了让GPU发挥其强大的计算能力,也就是不单单只是图形计算,人们在2002年就开始研究如何利用GPU完成我们通常意思上的数据运算,这就是成为 GPGPU(General-Purpose computing on Graphics Processing Units,基于GPU的通用计算)。首先我来基本了解一下GPU的运算基础。
图形数据从CPU传输过来,进入GPU后进行处理,上颜色处理花纹等等的运算,处理后输出,如果要利用GPU来做通用计算,这就必须要把经过处理,这其实是很困难的事情。如果程序员想要调用GPU硬件资源,只能通过OpenGL或者Direct3D两种API接口。OpenGL或Direct3D严重的限制了GPU性能在 3D图形处理意外的应用领域。因为开发人员并不了解如何调用GPU的线程以及内核。
在2003年第一次出现了一个利用GPU进行并行运算。在起先的尝试当中使用的方法非常原始,并且不少GPU的硬件功能也被限制,例如rasterizing和Z -缓冲技术。但是出现“Shader”之后,大家开始尝试矩阵计算。早在2003年一个SIGGRAPH当中的部门开辟了GPU运算新篇章—— GPGPU。
这段时间最受大家所知道的编辑其就是Brook,开创了GPU在非图形领域的先河。是 Brook首次让C语言能够实现这一功能,让开发人员无需了解OpenGL或者Direct3D就能够对GPU资源进行调用。开发人员可以通过一个.br 文件进行编码和扩展,产生的代码能够被DirectX、OpenGL、或x86系统的代码链接库支持。当然其也有其具有的弊端。但是这也使得NVIDIA和ATI把眼光吸引到如何利用GPU做通用计算这点上。
在2004年,NVIDIA就专门请了相关硬件方面的设计师以及软件方面的设计师对于GPU进行重新的完全不同的以前的设计,它既适用于图形,也是适用于计算的。
伴随着随着统一渲染架构的诞生,也就是进入G80开始,GPU本身的计算方式由基于矢量计算转为了基于标量的并行计算。当摆脱了架构和计算方式所带来的限制之后,GPU所能处理的问题由图形领域扩展到了通用计算领域。而在开发领域,需要有一种灵活的开发方式,能够让用户直接使用GPU的计算能力,而CUDA正是为此而诞生。
Nvidia CUDA技术是当今世界上唯一针对Nvidia GPU(图形处理器)的C语言环境,该技术充分挖掘出Nvidia GPU巨大的计算能力。凭借CUDA技术,开发人员能够利用Nvidia GPU攻克极其复杂的密集型计算难题。现在,世界各地已经部署了数以百万计的支持CUDA 的GPU,数以千计的软件开发人员正在使用免费的CUDA软件工具来加快视频、音频编码、石油天然气勘探、产品设计、医学成像和科学研究等应用。
说了CUDA这么多,我们深入一点探讨CUDA到底是什么。它是我们需要的新颖的硬件和编程模型,能够让GPU的强大计算能力发挥,并将GPU暴露为一种真正通用的数据并行计算设备。
CUDA(Compute Unified Device Architecture)用于GPU计算的开发环境,它是一个全新的软硬件架构,这个架构可以使用GPU来解决商业、工业以及科学方面的复杂计算问题。是NVIDIA为自家的GPU编写了一套编译器及相关的库文件。它是一个完整的GPGPU解决方案,提供了硬件的直接访问接口,而不必像传统方式一样必须依赖图形API(OpenGL和Direct 3D)接口来实现GPU的访问。因此对于开发者来说,CUDA的开发门槛大大降低了。CUDA的GPU编程语言基于标准的C语言,因此任何有C语言基础的用户都很容易的开发CUDA应用程序。
CUDA是业界的首款并行运算语言,而且其非常普及化,目前有高达8千万的PC用户可以支持该语言。
CUDA在执行的时候是让host里面的一个一个的kernel按照线程网格(Grid)的概念在显卡硬件(GPU)上执行。每一个线程网格又可以包含多个线程块(block),每一个线程块中又可以包含多个线程(thread)。
用马路上的汽车来比喻,马路上面有很多辆汽车,但是如果同时开的话,那么肯定会出现塞车现象的。CUDA就好比一个指挥马路的警察。每一个汽车分成不同的路线kernel_1,kernel_2……kernel_M),然后每个子任务的司机(Grid),就负责自己的路线(Block),最后才是汽车(Thread)去执行完成。
通过CUDA编程时,将GPU看作可以并行执行非常多个线程的计算设备(compute device)。它作为主CPU的协处理器或者主机(host)来运作:换句话说,在主机上运行的应用程序中数据并行的、计算密集的部分卸载到此设备上。
经过了CUDA对线程、线程块的定义和管理,在支持CUDA的GPU内部实际上已经成为了一个迷你网格计算系统。在内存访问方面,整个GPU可以支配的存储空间被分成了寄存器(Register)、全局内存(External DRAM)、共享内存(Parallel Data Cache)三大部分。其中寄存器和共享内存集成在GPU内部,拥有极高的速度,但容量很小。共享内存可以被同个线程块内的线程所共享,而全局内存则是我们熟知的显存,它在GPU外部,容量很大但速度较慢。经过多个级别的内存访问结构设计,CUDA已经可以提供让人满意的内存访问机制,而不是像传统GPGPU那样需要开发者自行定义。
在CUDA的帮助下普通程序员只要学习一点点额外的GPU架构知识,就能立刻用熟悉的C语言释放GPU恐怖的浮点运算能力,通过CUDA所能调度的运算力已经非常逼近万亿次浮点运算(GeForce 280GTX单卡浮点运算能力为933GF LOPS)。而在此之前要获得万亿次的计算能力至少需要购买价值几十万元的小型机。
基于CUDA开发的程序代码在实际执行中分为两种,一种是运行在CPU上的宿主代码(Host Code),一种是运行在GPU上的设备代码(Device Code)。
CUDA其实是CPU和GPU协作运算数据,所有CUDA也会看到CPU和GPU的部分,比较串行的部分放到CPU上面,比较并行的部分放到GPU上面运算。
采用CUDA技术相比传统的GPGPU计算的优势:
CUDA的编程接口采用了标准的C语言程序进行扩展,有利于CUDA的学习
*
每个线程之间CUDA为他们提供了16kb的共享内存,可用于设置缓存,同时还拥有更高的带宽纹理
*
系统内存和显存之间更有效地进行数据传输
*
无需图形API接口进行连接
*
现行内存寻址、聚集和驱散,写入任意地址
*
硬件支持整数和bit操作