GPU通用计算与CUDA

目前,主流计算机中的处理器主要是中央处理器CPU和图形处理器GPU。传统上,GPU只负责图形渲染,而大部分的处理都交给了CPU。

21世纪人类所面临的重要科技问题,如卫星成像数据的处理、基因工程、全球气候准确预报、核爆炸模拟等,数据规模已经达到TB 甚至PB量级,没有万亿次以上的计算能力是无法解决的。与此同时,我们在日常应用中(如游戏、高清视频播放)面临的图形和数据计算也越来越复杂,对计算速度提出了严峻挑战。

GPU在处理能力和存储器带宽上相对CPU有明显优势,在成本和功耗上也不需要付出太大代价,从而为这些问题提供了新的解决方案。由于图形渲染的高度并行性,使得GPU可以通过增加并行处理单元和存储器控制单元的方式提高处理能力和存储器带宽。GPU设计者将更多的晶体管用作执行单元,而不是像 CPU那样用作复杂的控制单元和缓存并以此来提高少量执行单元的执行效率。图1-1对CPU与GPU中晶体管的数量以及用途进行了比较。



受游戏市场和军事视景仿真需求的牵引,GPU性能提高速度很快。最近几年中,GPU的性能每一年就可以翻倍,大大超过了CPU遵照摩尔定律(每 18~24月性能翻倍)的发展速度。为了实现更逼真的图形效果,GPU支持越来越复杂的运算,其可编程性和功能都大大扩展了。

目前,主流GPU的单精度浮点处理能力已经达到了同时期CPU的10倍左右,而其外部存储器带宽则是CPU的5倍左右;在架构上,目前的主流GPU 采用了统一架构单元,并且实现了细粒度的线程间通信,大大扩展了应用范围。2006年,随着支持DirectX 10的GPU的发布,基于GPU的通用计算(General Purpose GPU,GPGPU)的普及条件成熟了。

NVIDIA公司于2007年正式发布的CUDA(Compute Unified Device Architecture,计算统一设备架构)是第一种不需借助图形学API就可以使用类C语言进行通用计算的开发环境和软件体系。与以往的传统 GPGPU开发方式相比,CUDA有十分显著的改进。经过两年多的发展,CUDA与支持CUDA的GPU在性能上有显著提高,功能上也在不断完善。

由于在性能、成本和开发时间上较传统的CPU解决方案有显著优势,CUDA的推出在学术界和产业界引起了热烈反响。现在,CUDA已经在金融、石油、天文学、流体力学、信号处理、电磁仿真、模式识别、图像处理、视频压缩等领域获得广泛应用,并取得了丰硕的成果。随着GPU的进一步发展和更多的开发人员参与到GPU通用计算的开发中来,可以预见,GPU将在未来的计算机架构中扮演更加重要的角色,甚至许多以往被认为不可能的应用也会因为GPU的强大处理能力而成为现实。


1.1  多核计算的发展

并行是一个广义的概念,根据实现层次的不同,可以分为几种方式。如图1-2所示,最微观的是单核指令级并行(ILP),让单个处理器的执行单元可以同时执行多条指令;向上一层是多核(multi-core)并行,即在一个芯片上集成多个处理器核心,实现线程级并行(TLP);再往上是多处理器(multi-processor)并行,在一块电路板上安装多个处理器,实现线程和进程级并行;最后,可以借助网络实现大规模的集群或者分布式并行,每个节点(node)就是一台独立的计算机,实现更大规模的并行计算。




伴随着并行架构的发展,并行算法也在不断成熟与完善。从历史上看,并行算法研究的高峰是在20世纪七八十年代。这一阶段,出现了很多采用不同互连架构和存储器模型的SIMD机,以及许多优秀的并行算法,在整个并行算法研究历史上谱写了辉煌的一页。20世纪90年代中期以后,并行算法的研究更加注重面向应用,不但研究并行算法的设计与分析,也兼顾并行机体系结构与并行应用程序的设计。

工艺、材料和功耗的物理限制,处理器的频率不会在短时间内有飞跃式的提高,因此采用各种并行方式提高计算能力势在必行。现代CPU的每个核心中都采用了超标量 、超级流水线 、超长指令字 、SIMD 、超线程、分支预测等手段发掘程序内的指令级并行,并且主流的CPU中也有多个处理器核心。而GPU与生俱来就是一种众核并行处理器,在处理单元的数量上还要远远超过CPU。

目前计算机中的处理器主流是拥有2~8个核心的多核CPU,及拥有数十乃至上百个核心的众核GPU,并且两者的核心数量仍会继续增加。多核和众核处理器的普及使得并行处理走入了寻常百姓家,不再是大型机和集群的专利。这也使得并行算法和并行编程成为程序员必须了解和掌握的内容。 


1.1.1  CPU多核并行

过去20年间,Intel、AMD等厂家推出的CPU性能在不断提高,但发展速度与20世纪80年代末90年代初的飞跃相比,已经不能相提并论。按照摩尔定律,每18~24个月芯片上可集成的晶体管数量就会翻倍,这一速度带来了处理能力和速度的飞速增长。

CPU提高单个核心性能的主要手段是提高处理器的工作频率,以及增加指令级并行。这两种传统的手段都遇到了问题:随着制造工艺的不断提高,晶体管的尺寸越来越接近原子的数量级,漏电流问题愈加显著,单位尺寸上的能耗和发热也越来越大,使得处理器的频率提高速度越来越慢。另一方面,通用计算中的指令级并行并不多,因此费尽苦心设计获得的性能提高与投入的大量晶体管相比,显得很不划算。使用流水线可以提高指令级并行,但更多更深的流水线可能会导致效率问题,例如,Intel的Pentium 4架构中有更长的流水线,但运算性能还不及同频的Pentium Ⅲ。为了实现更高的指令级并行,就必须用复杂的猜测执行机制和大块的缓存保证指令和数据的命中率。现代CPU的分支预测正确率已经达到了99%以上,没有什么提高余地。缓存的大小对CPU的性能有很大影响,过去低端的赛扬和主流的奔腾处理器用于计算的单元基本一样,主要区别就在于缓存的大小。但是继续增加缓存大小,最多也就是让真正用于计算的少量执行单元满负荷运行,这显然无助于CPU性能的进一步提高。

由于上述原因限制了单核CPU性能的进一步提高,CPU厂商开始在单块芯片内集成更多的处理器核心,使CPU向多核方向发展。2005 年,Intel和AMD正式向主流消费市场推出了双核CPU产品,2007年推出4核CPU,2009年Intel CPU进入8核时代,Intel CPU核心数量及制程的变化如图1-3所示。随着多核CPU的普及,现代的普通PC都拥有数个CPU核心,实际上已经相当于一个小型集群。可以预见,未来 CPU中的核心数量还将进一步增长。与此同时,多核架构对传统的系统结构也提出了新的挑战,如存储器壁垒、芯片、板极、系统级均衡设计以及可移植性等方面的问题。

随着CPU从单核发展为多核,越来越多的程序员也意识到了多线程编程的重要性。多线程编程既可以在多个CPU核心间实现线程级并行,也可以通过超线程等技术更好地利用每一个核心内的资源,充分利用CPU的计算能力。除了直接使用操作系统提供的线程管理API实现多线程外,还可以通过一些库或者语言扩展等方法实现多线程并行计算。目前常见的多线程编程语言扩展有OpenMP和Intel的TBB(Thread Building Block)等。


表1-1  计算机的Flynn分类

分类 说明
SISDSingle Instruction Single Data)系统 传统的计算机是单CPU,同一时刻只能执行一条指令,处理一个数据,即一个控制流和一个数据流的顺序执行。SISD也可以并行,只要各CPU执行不同的指令流,处理不同数据空间的数据流,就仍是SISD模式
SIMDSingle Instruction Multiple Data)系统 向量机中,一个指令部件同时控制多个执行部件,一条指令可以同时操作多个数据,即一个控制流多个数据流。向量机执行操作时,向量处理单元并行处理由同类数据组成的数组,结果按若干个周期的频率输出。相对于细粒度的SIMD,粗粒度的有SPMDSPMT等,可视作SIMD的子类
MISDMultiple Instructions Single Data)系统 MISD系统结构只适用于某些特定的算法。MISD机中,各个处理单元排成线性阵列,对流经的同一数据流,执行不同的指令流,这种应用非常有限
MIMDMultiple Instruction Multiple Data)系统 多处理器在不同的数据流上执行不同的指令流,与SISD的本质区别在于不同处理器处理的指令与数据彼此相关,往往是并行地在执行同一工作的不同部分。高性能服务器与超级计算机大多是MIMD



1.1.2  超级计算机、集群与分布式计算

超级计算机一般指在性能上居于世界领先地位的计算机,通常有成千上万个处理器,以及专门设计的内存和I/O系统。它们采用的架构与通常的个人计算机有很大区别,使用的技术也随着时代和具体应用不断变动。尽管如此,超级计算机与PC的关系仍然十分紧密。一部分超级计算机使用的处理器在PC市场上也能找到;而超级计算机使用的一些技术,如SIMD向量机、多核处理器,以及处理器封装技术等也都已普及到普通计算机中。支持CUDA的GPU可以看成是一个由若干个向量处理器组成的超级计算机,性能也确实可以和小型的超级计算机相比。为了将更多的资源用于计算,过去的超级计算机的界面往往都很简单,往往拆掉显卡以降低功耗。CUDA技术推出以后,越来越多的超级计算机开始安装GPU以提高性能,降低计算成本。

计算机集群(简称集群)是一种通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作的系统。分布式计算则将大量的计算任务和数据分割成小块,由多台计算机分别计算,在上传运算结果后,将结果统一合并得出结果,组织较为松散。两者一般都采用网络将各个节点连接起来,性价比都高于专门的超级计算机。例如进行蛋白质折叠计算的Folding@home分布式计算项目,现在有大约十万台计算机参加,计算能力甚至超过了大多数超级计算机。值得一提的是,在该项目中,仅有的11370颗支持CUDA的GPU提供了总计算能力的一半;而运行Windows的CPU共计208268颗,却只能实现198万亿次浮点运算,仅相当于该项目总处理能力的6%。

目前在超级计算机、集群与分布式计算程序开发中常用的工具是MPI(Message Passing Interface,消息传递接口)。MPI是一个免费和开源库,可以被C/Fortran77/C++/ Fortran90调用,几乎得到所有并行计算机制造商的支持。它是一种消息传递编程模型,广泛应用于多类并行机,特别适用于分布式存储的并行机和服务器集群。



1.1.3  CPU+GPU异构并行

目前主流计算机的处理能力主要来自CPU和GPU。CPU与GPU一般经北桥 通过AGP或者PCI-E总线连接,各自有独立的外部存储器,分别是内存和显存。在一些芯片组中使用的集成GPU没有采用独立的显存芯片,直接从内存中分出一块区域作为显存。Intel和AMD提出的CPU-GPU融合产品还准备直接将CPU和GPU通过QPI或者HT总线连接,集成在一块芯片内。可以预见,受面积、功耗和散热的限制,此类融合产品不大可能集成性能很高的GPU,并且有可能不为GPU提供独立显存。
传统的CPU+GPU异构并行处理的典型任务是图形实时渲染。在这类应用中,CPU负责根据用户的输入和一定的规则(如游戏的AI)确定在下一帧需要显示哪些物体,以及这些物体的位置,再将这些信息传递给GPU,由GPU绘制这些物体并进行显示。两者的计算是并行的:在GPU绘制当前帧的时候,CPU可以计算下一帧需要绘制的内容。

在这些处理中,CPU负责的是逻辑性较强的事务计算,GPU则负责计算密集度高的图形渲染。为了满足事务计算的需要,CPU的设计目标是使执行单元能够以很低的延迟获得数据和指令,因此采用了复杂的控制逻辑和分支预测,以及大量的缓存来提高执行效率;而GPU必须在有限的面积上实现很强的计算能力和很高的存储器带宽,因此需要大量执行单元来运行更多相对简单的线程,在当前线程等待数据时就切换到另一个处于就绪状态等待计算的线程。简而言之,CPU对延迟将更敏感,而GPU则侧重于提高整体的数据吞吐量。CPU和GPU的设计目标的不同决定了两者在架构和性能上的巨大差异,具体来说有:


1.CPU线程与GPU线程

CPU的一个核心通常在一个时刻只能运行一个线程的指令。CPU的多线程机制通过操作系统提供的API实现,是一种软件粗粒度多线程。当一个线程中断,或者等待某种资源时,操作系统就保存当前线程的上下文,并装载另外一个线程的上下文。这种机制使得CPU切换线程的代价十分高昂,通常需要数百个时钟周期。某些具有超线程功能的CPU可以将一个物理核心虚拟成多个核心,但每个虚拟核心在一个时刻也只能运行一个线程。

GPU采用的则是由硬件管理的轻量级线程,可以实现零开销的线程切换。线程的切换在这里成为一件好事:当一个线程因为访问片外存储器或者同步指令开始等待以后,可以立即切换到另外一个处于就绪态的线程,用计算来隐藏延迟。当线程中的计算指令需要的时间较多,而访存相对较少,即计算密集度比较高时,延迟就可以被计算隐藏,而且线程越多,延迟隐藏得更好。


2.多核与众核

当前的主流CPU中一般有2~8个核心,每个核心中有3~6条执行流水线。这些核心极采用了很多提高指令级并行的技术,如超标量超深流水线、乱序执行、预测执行,以及大容量缓存等,也采用了如SSE、3Dnow!一类的数据级并行技术。由于缓存和控制逻辑需要很大面积,因此在一块芯片上能够集成的核心数量也就被限制了。

当前的NVIDIA GPU中有1~30个包含完整前端的流多处理器,每个流多处理器可以看成一个包含8个1D流处理器的SIMD处理器。CUDA就利用了多个流多处理器间的粗粒度任务级或数据级并行,以及流多处理器内的细粒度数据并行。

尽管GPU的运行频率低于GPU,但更多的执行单元数量还是使GPU能够在浮点处理能力上获得优势,即使是芯片组里集成的低端GPU,在单精度浮点处理能力上也能和主流的CPU打成平手,而主流GPU的性能则可以达到同时期主流CPU性能的10倍左右,如图1-4所示。

  





3.外部存储器

GT200 GPU的显存带宽达到了140GB/s,是同时期CPU最高内存带宽的5倍,图1-5是CPU与GPU同期带宽的比较。造成GPU与CPU外部存储器带宽差异的主要原因有两个:

   



首先,显存中使用的GDDR存储器颗粒与内存的DDR存储器颗粒在技术上基本相同,但显存颗粒是直接固化在显卡的PCB板上的,而内存则为了兼顾可扩展性的需要,必须通过DIMM插槽与主板相连。直接焊在PCB板上的显存的信号完整性问题比通过插槽连接的内存更容易解决,显存的工作频率也通常比使用相同技术的内存要高一些。

其次,目前的CPU存储器控制器一般基于双通道或者三通道技术的,每个通道位宽64bit;而GPU中则存在数个存储器控制单元,例如GTX280 GPU中就有8个存储器控制器,每个控制两片位宽32bit的显存芯片,使总的存储器位宽达到512bit。这样,尽管内存中的DDR存储器颗粒比显卡上的GDDR存储器颗粒还要多,但CPU能够同时访问的存储器颗粒反而少于GPU。


4.缓存

CPU中的缓存主要用于减小访存延迟和节约带宽。缓存在多线程环境下会发生失效反应:在每次线程上下文切换之后,都需要重建缓存上下文,一次缓存失效的代价是几十到上百个时钟周期。同时,为了实现缓存与内存中数据的一致性,还需要复杂的逻辑进行控制。

在GPU中则没有复杂的缓存体系与替换机制。GPU缓存是只读的,因此也不用考虑缓存一致性问题。GPU缓存的主要功能是用于过滤对存储器控制器的请求,减少对显存的访问。所以GPU上缓存的主要功能不是减小访存延迟,而是节约显存带宽。

从上面的分析可以看出,GPU的主要设计目标是以大量线程实现面向吞吐量的数据并行计算,适合于处理计算密度高、逻辑分支简单的大规模数据并行任务。而CPU则有复杂的控制逻辑和大容量的缓存减小延迟,能够适应各种不同的情况,尤其擅长复杂逻辑运算。使用GPU处理数据并行任务,而由CPU进行复杂逻辑和事务处理等串行计算,就可以最大限度地利用计算机的处理能力,实现桌面上的超级计算。CPU+GPU并行不只是计算能力的提高,也不只是节省了成本和能源;将高性能计算普及到桌面,使得许多以往不可能的应用成为了现实,这种灵活性本身就是一种革命性的进步。



1.2  GPU发展简介

自1999年NVIDIA发布第一款GPU以来,GPU的发展就一直保持了很高的速度。为了实时生成逼真3D图形,GPU不仅采用了最先进的半导体制造工艺,在设计上也不断创新。传统上,GPU的强大处理能力只被用于3D图像渲染,应用领域受到了限制。随着以CUDA为代表的GPU通用计算API的普及,GPU在计算机中的作用将更加重要,GPU的含义也可能从图形处理器(Graphic Processing Unit)扩展为通用处理器(General Purpose Unit)。


1.2.1  GPU渲染流水线

GPU的渲染流水线的主要任务是完成3D模型到图像的渲染(render)工作。常用的图形学API(Direct3D/OpenGL)编程模型中的渲染过程被分为几个可以并行处理的阶段,分别由GPU中渲染流水线的不同单元进行处理。GPU输入的模型是数据结构(或语言)定义的对三维物体的描述,包括几何、方向、物体表面材质以及光源所在位置等;而GPU输出的图像则是从观察点对3D场景观测到的二维图像。在GPU渲染流水线的不同阶段,需要处理的对象分别是顶点(vertex)、几何图元(primitive)、片元(fragment)、像素(pixel)。如图1-6所示,典型的渲染过程可以分为以下几个阶段:


1.顶点生成

图形学API用简单的图元(点、线、三角形)表示物体表面。每个顶点除了(x,y,z)三维坐标属性外还有应用程序自定义属性,例如位置、颜色、标准向量等。


2.顶点处理

本阶段主要是通过计算把三维顶点坐标映射到二维屏幕,计算各顶点的亮度值等。这个阶段是可编程的,由vertex shader完成。输入与输出一一对应,即一个顶点被处理后仍然是一个顶点,各顶点间的处理相互独立,可以并行完成。


3.图元生成

根据应用程序定义的顶点拓扑逻辑,把上阶段输出的顶点组织起来形成有序的图元流。顶点拓扑逻辑定义了图元在输出流中的顺序,一个图元记录由若干顶点记录组成。


4.图元处理

这一阶段也是可编程的,由geometry shader完成。输入和输出不是一一对应,一个图元被处理后可以生成0个或者多个图元,各图元处理也是相互独立的。本阶段输出一个新的图元流。


5.片元生成 

这一阶段将对每一个图元在屏幕空间进行采样,即光栅化。每一个采样点对应一个片元记录,记录该采样点在屏幕空间中的位置、与视点之间的距离以及通过插值获得的顶点属性等。


6.片元处理

片元处理阶段是可编程的,由pixel shader完成,主要完成图形的填色功能。模拟光线和物体表面的交互作用,决定每个片元的颜色及透明程度等属性。


7.像素操作

用每个片元的屏幕坐标来计算该片元对最终生成图像上的像素的影响程度。本阶段计算每个采样点离视点的距离,丢弃被遮挡住的片元。当来自多个图元的片元影响同一个像素时,往往都根据图元处理输出流中定义的图元位置进行像素更新。

下面以绘制一朵玫瑰为例来说明GPU图形流水线的工作流程。首先,GPU从显存读取描述玫瑰3D外观的顶点数据,生成一批反映三角形场景位置与方向的顶点;由vertex shader计算2D坐标和亮度值,在屏幕空间绘出构成玫瑰的顶点;顶点被分组成三角形图元;geometry shader进行进一步细化,生成更多图元;随后,GPU中的固定功能单元对这些图元进行光栅化,生成相应的片元集合;由pixel shader从显存中读取纹理数据对片元上色和渲染;最后一个阶段,根据片元信息更新玫瑰图像,主要是可视度的处理。由ROP完成像素到帧缓冲区的输出,帧缓冲区中的数据经过D/A输出到显示器上以后,就可以看到绘制完成的玫瑰图像了。

  




图形渲染过程具有内在的并行性:顶点之间、图元之间、片元之间的数据相关性很弱,对它们的计算可以独立并行进行。这使得通过并行处理提高吞吐量成为可能。

首先,渲染流水线具有时间上的功能并行。流水线的各级可以同时工作,当各级都能满负荷工作时,能够获得最高性能。

其次,渲染流水线具有数据并行性。不仅可以通过SIMD提高每一个可编程着色器的性能,还可以在一个GPU内集成多条渲染流水线实现更高的吞吐量。



1.2.2  着色器模型

在图形渲染中,GPU中的可编程计算单元被称为着色器(shader),着色器的性能由DirectX中规定的shader model来区分。GPU中最主要的可编程单元是顶点着色器和像素着色器。为了实现更细腻逼真的画质,GPU的体系架构从最早的固定功能流水线到可编程流水线,再到DirectX 10时代的以通用的可编程计算单元为主、图形固定功能单元为辅的形式。在这一过程中,着色器的可编程性也随着架构的发展不断提高。附录G给出了不同版本着色器模型的性能参数,这里的表1-2给出了每代模型的大概特点。

表1-2  Shader Model版本

 

Shader Model

GPU代表

显卡时代

特点

 

1999年第一代NV GeForce 256

DirectX 7

19992001

GPU可以处理顶点的矩阵变换和进行光照计算(T&L),操作固定,功能单一,不具有可编程性

SM 1.0

2001年第二代NV GeForce3

DirectX 8

将图形硬件流水线作为流处理器来解释,顶点部分出现可编程性,像素部分可编程性有限(访问纹理的方式和格式受限,不支持浮点)

SM 2.0

2003年第三代NV GeForceFxATI R300

DirectX 9.0b

顶点和像素可编程性更通用化,像素部分支持FP16/24/32浮点,可包含上千条指令,纹理使用更加灵活:可用索引进行查找,也不再限制在[0,1]范围,从而可用作任意数组(这一点对通用计算很重要)

SM 3.0

2004年第四代NV GeForce 6ATI X1000

DirectX 9.0c

顶点程序可以访问纹理VTF,支持动态分支操作,像素程序开始支持分支操作(包括循环、if/else等),支持函数调用,64位浮点纹理滤波和融合,多个绘制目标

SM 4.0

2007第五代NV G80AMD/ATI R600

DirectX 10

20072009

统一渲染架构,支持IEEE754浮点标准,引入geometry shader(可批量进行几何处理),指令数从1K提升至64K,寄存器从32个增加到4096个,纹理规模从16+4个提升至128个,材质texture格式变为硬件支持的RGBE格式,8192*8192的最高纹理分辨率比原先的2048*2048高很多

 

 


传统的分离架构中两种着色器的比例是固定的。在GPU核心设计完成时,各种着色器的数量便确定下来,比如著名的"黄金比例"--顶点着色器与像素着色器数量为1∶3。但不同的游戏对顶点着色器和像素着色器计算能力的需求是不同的,如果场景中有大量的小三角形,顶点着色器就必须满负荷工作,而像素着色器则会被闲置;如果场景中只有少量的大三角形,又会发生相反的情况。因此,固定比例的设计无法完全发挥GPU中所有计算单元的性能。

两种着色器的架构既有相同之处,又有一些不同。两者处理的都是四元组数据(顶点着色器处理用于表示坐标的w、x、y、z,但像素着色器处理用于表示颜色的a、r、g、b)顶点渲染,需要比较高的计算精度;而像素渲染则可以使用较低的精度,从而可以增加在单位面积上的算术单元数量。在shader model 4.0前,两种着色器的精度都在不断提高,但同时期顶点着色器的精度要高于像素着色器。

shader model 4.0对顶点着色器和像素着色器的规格要求完全相同,都支持32位浮点数。这是GPU发展的一个分水岭:过去只能处理顶点和只能处理像素的专门处理单元被通用的统一着色器(Unified Shader)架构取代了。统一渲染架构能够充分利用可编程着色器的处理能力,也更加适应通用计算的需要。

 

 


1.2.3  NVIDIA GPU发展简介

NVIDIA公司是全球视觉计算技术的行业领袖及GPU的发明者。作为高性能处理器的GPU可在工作站、个人计算机、游戏机和移动设备上生成令人叹为观止的互动图形效果。 

1993年,黄仁勋与Curtis Priem和Chris Malachowsky共同成立了NVIDIA公司,在接下来的几年里研制了NV-1和NV-2显示芯片,并在市场上推出了自己的产品,做出了最初的尝试。David Kirk也在这一阶段加入了NVIDIA。

1997年,NVIDIA发布了NV-3显示芯片,即RIVA-128。RIVA-128具有在当时来说优秀的2D性能和不错的3D性能,在市场上获得了成功。与当时的PCI接口Voodoo图形加速卡相比,RIVA-128是一块基于AGP接口的完整的显卡。在1997年底,NVIDIA又发布了 RIVA-128ZX和TNT显示芯片。

1999年2月,TNT-2显示芯片发布并投放市场。TNT-2具有当时最强大的3D图形性能,并且有面向不同市场的多个版本。TNT-2在市场上取得了空前的成功,奠定了NVIDIA在视觉计算领域的领导地位。

1999年8月,NVIDIA发布了全球第一颗GPU--GeForce-256。它主要由两个模块组成,一个是顶点转换和顶点光照处理器,由进行 32位浮点数运算的固定功能单元组成;另一个是像素着色流水线(或片元着色流水线),由进行定点数运算的固定功能单元组成。GeForce 256 可以支持OpenGL和微软公司的DirectX 7标准API接口。在DirectX 7时代,NVIDIA推出了GeForce 2系列产品。

2001年,NVIDIA推出了第一款拥有可编程顶点着色器的GPU--GeForce 3。它使用了可编程的顶点处理器和不可编程的像素处理器(或片元处理器),并且两者都能完成32bit单精度浮点运算。GeForce 3可以支持DirectX 8和OpenGL API。在DirectX 8时代,NVIDIA的主要产品是GeForce 3系列和GeForce 4系列,以及面向低端市场的GeForce MX系列,其中GeForce MX系列只支持DirectX 7。

2002年,NVIDIA推出的GeForce Fx是第一款使用32位浮点流水线作为可编程的顶点处理器的GPU,可以支持DirectX 9.0,呈现电影级画质。随后几年推出的GeForce 6系列和GeForce 7系列能够支持DirectX 9.0C API,改进了着色引擎,能够支持更多的特效。

2006年的GeForce 8系列GPU率先采用了统一渲染架构,以通用渲染单元替代了原来分离的顶点着色单元和像素着色单元,能够支持DirecrtX 10.0。从GeForce 8系列开始,NVIDIA的GPU开始支持CUDA。

2007年,CUDA正式发布,引发了GPU通用计算的革命。

2008年,NVIDIA发布了能够支持CUDA计算能力1.1的GeForce 9系列GPU,以及支持CUDA计算能力1.3的GT200 GPU。NVIDIA在GT 200中引入了大量重要改进,使得GT200不仅具有极高的处理能力和存储器带宽,用于通用计算时的可编程性和灵活性也更加出色。同年,NVIDIA发布了Tegra系列产品,进军移动处理器市场。

目前,NVIDIA在桌面、专业设计、高性能计算及嵌入式等不同领域推出了性能出众的GPU产品,分别对应不同的产品线。

GeForce系列主要面向家庭和企业的娱乐应用,能够为用户提供身临其境的视觉体验。该系列又可以分为面向性能的GTX系列,面向主流市场的 GTS和GT系列,以及具有高性价比的GS系列。

Quadro系列主要应用于图形工作站中,对专业领域应用进行了专门优化。Quadro系列按照不同应用领域划分,有为AutoCAD设计优化的 VX系列,为专业图形渲染优化的FX系列,用于移动和专业显示的NVS系列,以及为图像和视频应用优化的CX系列。

Tesla系列是专门用于高性能通用计算的产品线,以有限的体积和功耗实现了强大的处理能力。Tesla系列包括以扩展卡形式安装的C系列,包含两个GPU的D系列和包含4个GPU的S系列,以及将CPU和GPU安装于同一单元内的M系列。D、S和M系列适合作为集群或者超级计算机的基本单元,而C 系列则可以为普通研究人员提供强大的计算能力。

Tegra系列是NVIDIA为便携式和移动领域推出的全新解决方案,在极为有限的面积上集成了通用处理器、GPU、视频解码、网络、音频输入输出等功能,并维持了极低的功耗。Tegra可以提供长达数天的续航能力及强大的图形和视频功能,是一种革命性的新产品。未来Tegra系列产品可能引入 GPU通用计算功能,这将极大地提高移动便携设备的计算能力和应用领域。



1.3  从GPGPU到CUDA

传统上,GPU的应用被局限于处理图形渲染计算任务,无疑是对计算资源的极大浪费。随着GPU可编程性的不断提高,利用GPU完成通用计算的研究渐渐活跃起来。将GPU用于图形渲染以外领域的计算称为GPGPU(General-purpose computing on graphics processing units,基于GPU的通用计算)。GPGPU计算通常采用CPU+GPU异构模式,由CPU负责执行复杂逻辑处理和事务管理等不适合数据并行的计算,由GPU负责计算密集型的大规模数据并行计算。这种利用GPU强大处理能力和高带宽弥补CPU性能不足的计算方式在发掘计算机潜在的性能,在成本和性价比方面有显著优势。但是,传统的GPGPU受硬件可编程性和开发方式的制约,应用领域受到了限制,开发难度也很大。


1.3.1  传统GPGPU开发

DirectX 10.0规范推出前的GPU中的主要可编程单元是顶点着色器和像素着色器。在没有采用统一渲染架构的GPU中,两者在物理上是分离的,数量上的比例也是固定的。一个具体的应用程序很难同时完全利用两种可编程着色器的性能。此外,传统GPU不允许计算单元之间通过片内的存储器进行通信,因此GPGPU也只能采用严格的SIMD模型。不允许数据间的通信,限制了很多算法,也就制约了传统GPGPU的应用范围和代码效率。

最早的GPGPU开发直接使用了图形学API编程。这种开发方式要求编程人员将数据打包成纹理,将计算任务映射为对纹理的渲染过程,用汇编或者高级着色器语言(如GLSL、Cg、HLSL)编写shader程序,然后通过图形学API(Direct3D、OpenGL)执行。这种"曲线救国"的方式要求编程人员不仅要熟悉自己需要实现的计算和并行算法,还要对图形学硬件和编程接口有深入的了解。由于开发难度大,传统GPGPU没有被广泛应用。

2003年,斯坦福大学的Ian Buck等人对ANSI C进行扩展,开发了基于NVIDIA Cg的Brook源到源编译器。Brook可以将类似C的brook C语言通过brcc编译器编译为Cg代码,隐藏了利用图形学API实现的细节,大大简化了开发过程。但早期的Brook编译效率很低,并且只能使用像素着色器进行运算。受GPU架构限制,Brook也缺乏有效的数据通信机制。AMD/ATI公司在其GPGPU通用计算产品Stream中采用了Brook的改进版本Brook+作为高级开发语言。Brook+的编译器的工作方式与Brook不同,提高了效率。在2009年推出Brook+ 1.3以前,Brook+早期版本与Brook相比在语法和编程模型上没有显著改进,同样缺乏有效的线程间数据通信手段。


1.3.2  CUDA开发

2007年6月,NVIDIA推出了CUDA(Compute Unified Device Architecture,统一计算设备架构)。CUDA是一种将GPU作为数据并行计算设备的软硬件体系。到目前为止,CUDA的版本已经进行了三次版本提升,功能不断完善,能够很好地支持新硬件的特性。

CUDA不需要借助于图形学API,并采用了比较容易掌握的类C语言进行开发。开发人员能够从熟悉的C语言比较平稳地从CPU过渡到GPU,而不必重新学习语法。当然,要开发高性能的GPU通用计算程序,开发人员仍然需要掌握并行算法和GPU架构方面的知识。

与以往的GPU相比,支持CUDA的GPU在架构上有了显著的改进,这两项改进使CUDA架构更加适用于GPU通用计算。一是采用了统一处理架构,可以更加有效地利用过去分布在顶点渲染器和像素渲染器的计算资源;二是引入了片内共享存储器,支持随机写入(scatter)和线程间通信。

CUDA为开发人员有效利用GPU的强大性能提供了条件。自推出后,CUDA被广泛应用于石油勘测﹑天文计算﹑流体力学模拟﹑分子动力学仿真﹑生物计算﹑图像处理﹑音视频编解码等领域,在很多应用中获得了几倍、几十倍,乃至上百倍的加速比。

猜你喜欢

转载自blog.csdn.net/prinstinadl/article/details/80869821