摘要:NVIDIA公司在1999年发布GeForce256时首先提出GPU(图形处理器)的概念,随后大量复杂的应用需求促使整个产业蓬勃发展至今。GPU在这十多年的演变过程中,我们看到GPU从最初帮助CPU分担几何吞吐量,到Shader(着色器)单元初具规模,然后出现Shader单元可编程性,到今天GPU通用计算领域蓬勃发展这一清晰轨迹。本报告首先根据搜集到的资料记录GPU通用计算的发展过程中硬件和软件的演变,然后介绍并简要比较现在比较流行的GPU通用计算编程模型,最后对GPU通用计算在不同领域的成功应用进行概述。
关键词:GPU GPU通用计算 可编程单元 编程模型 GPGPU应用
1、GPU通用计算的背景和动机
GPU英文全称Graphic Processing Unit,中文翻译为“图形处理器”。GPU从诞生之日起就以超越摩尔定律的速度发展,运算能力不断提升。业界很多研究者注意到GPU进行计算的潜力,于2003年SIGGRAPH大会上提出了GPGPU(General-purpose computing on graphics processing units)的概念。GPU逐渐从由若干专用的固定功能单元(Fixed Function Unit)组成的专用并行处理器向以通用计算资源为主,固定功能单元为辅的架构转变。
1.1 为什么要用GPU进行计算
GPU在处理能力和存储器带宽上相对于CPU有明显优势,在成本和功耗上也不需要付出太大代价。由于图形渲染的高度并行性,使得GPU可以通过增加并行处理单元和存储器控制单元的方式提高处理能力和存储器带宽。GPU设计者将更多的晶体管用作执行单元,而不是像CPU那样用作复杂的控制单元和缓存并以此来提高少量执行单元的执行效率[1]。图1 对CPU与GPU中的逻辑架构进行了对比。
图1 CPU和GPU逻辑架构对比
CPU的整数计算、分支、逻辑判断和浮点运算分别由不同的运算单元执行,此外还有一个浮点加速器。因此,CPU面对不同类型的计算任务会有不同的性能表现。而GPU是由同一个运算单元执行整数和浮点计算,因此,GPU的整型计算能力与其浮点能力相似。目前,主流GPU都采用了统一架构单元,凭借强大的可编程流处理器阵容,GPU在单精度浮点运算方面将CPU远远甩在身后[1]。最顶级的英特尔Core i7 965处理器,在默认情况下,它的浮点计算能力只有NVIDIA GeForce GTX 280的1/13,与AMD Radeon HD 4870相比差距就更大。
图2 CPU 和 GPU 的每秒浮点运算次数和存储器带宽
GPU运算相对于CPU还有一项巨大的优势,那就是其内存子系统,也就是GPU上的显存[1]。当前桌面级顶级产品3通道DDR3-1333的峰值是32GB/S,实测中由于诸多因素带宽在20 GB/S上下浮动。AMD HD 4870 512MB使用了带宽超高的GDDR5显存,内存总线数据传输率为3.6T/s或者说107GB/s的总线带宽。NVIDIA GTX280使用了高频率GDDR3显存,但是其显存控制器支持的位宽达到了512bit,搭载16颗0.8ns GDDR3显存,带宽高达惊人的142GB/s。而主流GPU普遍拥有40-60 GB/s显存带宽。存储器的超高带宽让巨大的浮点运算能力得以稳定吞吐,也为数据密集型任务的高效运行提供了保障。
还有,从GTX200和HD 4870系列GPU开始,AMD和NVIDIA两大厂商都开始提供对双精度运算的支持,这正是不少应用领域的科学计算都需要的。NVIDIA公司最新的Fermi架构更是将全局ECC(Error Checking and Correcting)、可读写缓存、分支预测等技术引入到GPU的设计中,明确了将GPU作为通用计算核心的方向。
GPU通用计算被越来越多的采用,除了GPU本身架构的优越性,市场需求也是重要的原因。比如很多企业或科研单位无法布置昂贵的的计算机集群,而大部分普通用户PC上装配的GPU使用率很低,提高GPU利用率的有效途径就是将软件的部分计算任务分配到GPU上,从而实现高性能、低功耗的最终目标。
1.2 什么适合GPU进行计算
尽管GPU计算已经开始崭露头角,但GPU并不能完全替代X86解决方案,很多操作系统、软件以及部分代码现在还不能运行在GPU上,所谓的GPU+CPU异构超级计算机也并不是完全基于GPU进行计算。一般而言适合GPU运算的应用有如下特征[2]:
• 运算密集。
• 高度并行。
• 控制简单。
• 分多个阶段执行。
符合这些条件或者是可以改写成类似特征的应用程序,就能够在GPU上获取较高的性能。
2、GPU通用计算的前世今生
GPU通用计算其实是从GPU渲染管线发展来的。GPU渲染管线的主要任务是完成3D模型到图像的渲染工作。常用的图形学API(DirectD/OpenGL)编程模型中渲染过程被分成几个可以并行处理的阶段,分别由GPU中渲染管线的不同单元进行处理。在GPU渲染管线的不同阶段,需要处理的对象分别是顶点(Vertex)、几何图元(primitive)、片元(fragment)、像素(pixel)。图形渲染过程具有内在的并行性:顶点之间、图元之间、片元之间的数据相关性很弱,对它们的计算可以独立并行进行,这使得通过并行处理提高吞吐量成为可能[3]。这儿不对GPU渲染管线进行详细介绍,而是着重于介绍GPU可编程器件和编程模型的发展历程。
2.1 GPU可编程器件的发展
1999年8月,NVIDIA正式发表了具有跨世纪意义的产品NV10——GeForce 256。GeForce256是业界第一款256bit的GPU,也是全球第一个集成T&L(Transforming&Lighting几何光照转换)、动态光影、三角形设置/剪辑和四像素渲染等3D加速功能的图形引擎。通过T&L技术,显卡不再是简单像素填充机以及多边形生成器,它还将参与图形的几何计算从而将CPU从繁重的3D管道几何运算中解放出来。可以说,T&L技术是显卡进化到GPU的标志。
从某种意义上说,GeForce 256开创了一个全新的3D图形时代,再到后来GeForce 3开始引入可编程特性,能将图形硬件的流水线作为流处理器来解释,基于GPU的通用计算也开始出现。GeForce3被用于实现矩阵乘法运算和求解数学上的扩散方程,这是GPU通用计算的早期应用。
研究人员发现,要实现更加复杂多变的图形效果,不能仅仅依赖三角形生成和硬件T&L实现的固定光影转换,而要加强顶点和像素运算能力。Shader(着色器)就是在这样的背景下提出的。Pixel Shader(顶点着色器)和Vertex Shader(像素着色器)的硬件逻辑支持可编程的像素和顶点,虽然当时可编程性很弱,硬件限制太多,顶点部分出现可编程性,像素部分可编程性有限,但这的确是硬件T&L之后PC图形技术的又一重大飞跃。3D娱乐的视觉体验也因此向接近真实迈进了一大步。可编程管线的引入,也为GPU发展翻开了新的篇章,GPU开始向SIMD(Single Instruction Multiple Data,单指令多数据流)处理器方向发展,凭借强大的并行处理性能,使得GPU开始用有了部分流式处理器特征。
随后到来的DirectX[1] 9.0时代,让Shader单元具备了更强的可编程性。2002年底微软发布的DirectX 9.0中,Pixel Shader单元的渲染精度已达到浮点精度,传统的硬件T&L单元也被取消。全新的Vertex Shader编程将比以前复杂得多,新的Vertex Shader标准增加了流程控制,更多的常量,每个程序的着色指令增加到了1024条。
Shader Model 2.0时代突破了以前限制PC图形图像质量在数学上的精度障碍,它的每条渲染流水线都升级为128位浮点颜色,让游戏程序设计师们更容易更轻松的创造出更漂亮的效果,让程序员编程更容易。而从通用性方面理解,支持浮点运算让GPU已经具备了通用计算的基础,这一点是至关重要的。
图形流水线中可编程单元的行为由Shader单元定义,着色器的性能由DirectX中规定的Shader Model来区分,并可以由高级的Shading语言(例如NV的Cg,OpenGL的GLSL,Microsoft的HLSL)编写。Shader源码被译为字节码,然后在运行时由驱动程序将其转化为基于特定GPU的二进制程序,具备可移植性好等优势。传统的图形渲染流线中有两种不同的可编程着色器,分别是顶点着色单元(Vertex Shader,VS)和像素着色单元(Pixel Shader,PS)。
在Shader Model 4.0之前,VS和PS两种着色器的架构既有相同之处,又有一些不同。两者处理的都是四元组数据(顶点着色器处理用于表示坐标的w、x、y、z,但像素着色器处理用于表示颜色的a、r、g、b),顶点渲染需要比较高的计算精度;而像素渲染则可以使用较低的精度,从而可以增加在单位面积上的计算单元数量。传统的分离架构中,两种着色器的比例往往是固定的。在GPU核心设计完成时,各种着色器的数量便确定下来,比如著名的“黄金比例”——顶点着色器与像素着色器的数量比例为1:3。但不同的游戏对顶点资源和像素资源的计算能力要求是不同的。如果场景中有大量的小三角形,则顶点着色器必须满负荷工作,而像素着色器则会被闲置;如果场景中有少量的大三角形,又会发生相反的情况。因此,固定比例的设计无法完全发挥GPU中所有计算单元的性能。
Shader Model 4.0统一了两种着色器,顶点和像素着色器的规格要求完全相同,都支持32位浮点数。这是GPU发展的一个分水岭。过去只能处理顶点和只能处理像素的专门处理单元被统一之后,更加适应通用计算的需求,应用程序调用着色器运算能力的效率也更高。
DirectX 11提出的Shader Model 5.0版本继续强化了通用计算的地位,微软提出的全新API—Direct Compute将把GPU通用计算推向新的巅峰。同时Shader Model 5.0是完全针对流处理器而设定的,所有类型的着色器,如:像素、顶点、几何、计算、Hull和Domaim(位于Tessellator前后)都将从新指令集中获益[4]。
着色器的可编程性也随着架构的发展不断提高,下表给出每代模型的大概特点[1]。
Shader Model |
GPU代表 |
显卡时代 |
特点 |
|
1999年第一代NV Geforce256 |
DirectX 7 1999~2001 |
GPU可以处理顶点的矩阵变换和进行光照计算(T&L),操作固定,功能单一,不具备可编程性 |
SM 1.0 |
2001年第二代NV Geforce3 |
DirectX 8 |
将图形硬件流水线作为流处理器来解释,顶点部分出现可编程性,像素部分可编程性有限(访问纹理的方式和格式受限,不支持浮点) |
SM 2.0 |
2003 年 ATI R300 和第三代NV Geforce FX |
DirectX 9.0b |
顶点和像素可编程性更通用化,像素部分支持FP16/24/32浮点,可包含上千条指令,处理纹理更加灵活:可用索引进行查找,也不再限制[0,1]范围,从而可用作任意数组(这一点对通用计算很重要) |
SM 3.0 |
2004年 第四代NV Geforce 6 和 ATI X1000 |
DirectX 9.0c |
顶点程序可以访问纹理VTF,支持动态分支操作,像素程序开始支持分支操作(包括循环、if/else等),支持函数调用,64位浮点纹理滤波和融合,多个绘制目标 |
SM 4.0 |
2007年 第五代NV G80和ATI R600 |
DirectX 10 2007~2009 |
统一渲染架构,支持IEEE754浮点标准,引入Geometry Shader(可批量进行几何处理),指令数从1K提升至64K,寄存器从32个增加到4096个,纹理规模从16+4个提升到128个,材质Texture格式变为硬件支持的RGBE格式,最高纹理分辨率从2048*2048提升至8192*8192 |
SM 5.0 |
2009年 ATI RV870 和2010年NV GF100 |
DirectX 11 2009~ |
明确提出通用计算API Direct Compute概念和Open CL分庭抗衡,以更小的性能衰减支持IEEE754的64位双精度浮点标准,硬件Tessellation单元,更好地利用多线程资源加速多个GPU |
表1 Shader Model版本
2.2 AMD与NVIDIA最新GPU架构比较
本文来源:http://www.cnblogs.com/chunshan/archive/2011/07/18/2110076.html