● 硬件T&L单元催生GPU诞生
Geforce256之所以被称作GPU原因就在于Geforce256划时代的在图形芯片内部集成了T&L(几何光照转换)功能,使得GPU拥有初步的几何处理能力,彻底解决了当时众多游戏瓶颈发生在CPU几何吞吐量不够的瓶颈。
不可否认在成功的背后,离不开微软推出的图形API——DirectX 7.0的鼎力支持。DirectX 7.0最大的特色就是支持T&L,在T&L问世之前,位置转换和灯光都需要CPU来计算,CPU速度越快,游戏表现越流畅。使用了T&L功能后,这两种效果的计算用显示卡的GPU来计算,这样就可以把CPU从繁忙的劳动中解脱出来。同时从另一个角度提升了GPU在PC系统中的地位。
值得一提的是GeForce2首开了GPU通用计算的先河,凭借其强大的多纹理处理性能,结合纹理环境参数和纹理函数可以实现一些很灵活的应用。它具有Texture Shader以及Register Combiner单元,有一定的数值计算能力。开发人员可以利用Texture Shader的依赖纹理进行数据访问,用Register Combiner进行计算。GeForce2被用于求解数学上的扩散方程,成为GPU通用计算的最早应用。
● Shader单元概念形成,GPU开始走上“邪路”
面向图形计算,让GPU逐渐找到了自己的方向,这个方向就是给予用户更真更快地视觉体验,但是GPU架构也遇到一些问题亟待解决。首要问题就是,要实现更加复杂多变的图形效果,不能仅仅依赖三角形生成和固定光影转换。
可编程模型与旧有的预定义模型是不同的。这种模型中,数据是透过virtual machine以一个类似于带有特殊汇编指令集的pre-arranged(事先安排好)程序进行处理的,程序员可以直接对其进行编程。
Shader概念的提出,意味着程序员可通过它们实现3D场景构建的难度大大降低。通过VS和PS的渲染,可以很容易的宁造出真实的水面动态波纹光影效果。此时DirectX的权威地位终于建成。
Pixel Shader(顶点着色器)和Vertex Shader(像素着色器)硬件逻辑,真正支持像素和顶点的可编程。虽然当时可编程性很弱,硬件限制太多,顶点部分出现可编程性,像素部分可编程性有限。但这的确是硬件T&L之后PC图形技术的又一重大飞跃。3D娱乐的视觉体验也因此向接近真实迈进了一大步,波光粼粼的水面是那个时期用于演示Shader能力的典型DEMO,相比之下DirectX 7绘制的水面效果就单调得多。
● Shader Model 2.0时代到来,Shader编程性逐步增强
随后到来的DirectX 9.0时代,让Shader单元具备了更强的可编程性。2002年底微软发布的DirectX9.0中,PS单元的渲染精度已达到浮点精度,传统的硬件T&L单元也被取消。全新的Vertex Shader(顶点着色引擎)编程将比以前复杂得多,新的Vertex Shader标准增加了流程控制,更多的常量,每个程序的着色指令增加到了1024条。
PS 2.0具备完全可编程的架构,能对纹理效果即时演算、动态纹理贴图,还不占用显存,理论上对材质贴图的分辨率的精度提高无限多;另外PS1.4只能支持28个硬件指令,同时操作6个材质,而PS2.0却可以支持160个硬件指令,同时操作16个材质数量,新的高精度浮点数据规格可以使用多重纹理贴图,可操作的指令数可以任意长,电影级别的显示效果轻而易举的实现。
VS 2.0通过增加Vertex程序的灵活性,显著的提高了老版本(DirectX 8)的VS性能,新的控制指令,可以用通用的程序代替以前专用的单独着色程序,效率提高许多倍;增加循环操作指令,减少工作时间,提高处理效率;扩展着色指令个数,从128个提升到256个。
如果说DirectX 8中的Shader单元还是个简单尝试的话,DirectX 9中的Shader则成为了标准配置。除了版本升级到2.0外,DirectX 9中PS单元的渲染精度已达到浮点精度,传统的硬件T&L单元也被取消,在较低DirectX版本游戏运行时会使用VS单元模拟执行硬件T&L单元的功能。
● Shader计算能力快速发展,灵活度不断提升
在图形渲染中,GPU中的可编程计算单元被称为着色器(Shader),着色器的性能由DirectX中规定的Shader Model来区分。GPU中最主要的可编程单元式顶点着色器和像素着色器。
图形流水线中可编程单元的行为由Shader单元定义,并可以由高级的Shading语言(例如NV的Cg,OpenGL的GLSL,Microsoft的HLSL)编写。Shader源码被译为字节码,然后在运行时由驱动程序将其转化为基于特定GPU的二进制程序,具备可移植性好等优势。传统的图形渲染流线中有两种不同的可编程着色器,分别是顶点着色单元(Vertex Shader,VS)和像素着色单元(Pixel Shader,PS)。表一和表二比较详细地罗列出从Shader 2.0到Shader 4.0像素着色单元和顶点着色单元的演进过程。
表中:PS 2.0 = DirectX 9.0 original Shader Model 2 specification。
PS 3.0 = Shader Model 3。
PS 4.0 = Shader Model 4。
N = NO,Y = YES。
“32+64”指32个纹理指令和64个算术指令。
● Shader Model着色器模型快速发展
顶点着色单元(Vertex Shader,VS)和像素着色单元(Pixel Shader,PS)两种着色器的架构既有相同之处,又有一些不同。两者处理的都是四元组数据(顶点着色器处理用于表示坐标的w、x、y、z,但像素着色器处理用于表示颜色的a、r、g、b),顶点渲染需要比较高的计算精度;而像素渲染则可以使用较低的精度,从而可以增加在单位面积上的计算单元数量。在Shader Model 4.0之前,两种着色器的精度都在不断提高,但同期顶点着色器的精度要高于像素着色器。
Shader Model 4.0统一了两种着色器,所以顶点和像素着色器的规格要求完全相同,都支持32位浮点数。这是GPU发展的一个分水岭。过去只能处理顶点和只能处理像素的专门处理单元被统一之后,更加适应通用计算的需求,应用程序调用着色器运算能力的效率也更高。
在这一过程中,着色器的可编程性也随着架构的发展不断提高,下表给出的是每代模型的大概特点。
● GPGPU概念提出并付诸行动
2004年9月份,剑桥大学的BionicFx课题组宣布在NVIDIA的最新GPU产品中实现了专业的实时音频处理功能,并且准备进行商业化的运作,对其产品进行销售,给音乐创作者带来实惠。现在,该解决方案命名为“音视频互换技术”(Audio Video EXchange,AVEX)。BionicFx的工作流程是:待处理的音频数据—〉转换成图形数据—〉GPU处理—〉处理后的图形数据—〉转换成所需音频数据。这说明AVEX实际上是作为虚拟硬件层在与GPU通讯,但GPU不仅是图形处理器,而是变成了一颗独立的数字信号处理器(DSP)。
而后期的大量DirectX 9.0c游戏已经对Shader单元运算能力提出难以达到的要求,GPU必须适应游戏画面渲染发展趋势才能生存。根据ATI的研究,在2001年刚刚出现具备像素着色器的显示卡时,当时游戏的像素着色器程序中算术指令和纹理指令数量的比例在1:1左右,打这以后,算术指令的数量呈显著增加之势。
在2005年像素着色器程序中,平均每5条算术指令才会出现一条贴图指令,而这样的算术指令数量急剧增长趋势仍将继续保持下去。
我们对于一条像素流水线定义是“Pixel Shader(像素着色器)+TMU(纹理单元)+ROP(光栅化引擎,ATI将其称为Render Back End)。从功能上简单的说,Pixel Shader完成像素处理,TMU负责纹理渲染,而ROP则负责像素的最终输出,因此,一条完整的传统流水线意味着在一个时钟周期完成1个Pixel Shader运算,输出1个纹理和1个像素。但是目前的情况是TMU纹理填充单元和ROP单元并没有成为GPU设计的瓶颈,反倒是更长更复杂的着色器程序指令让多个像素渲染管线感受到前所未有的压力。
Radeon X1900系列最终做到了3个Pixel Shader对1个贴图单元,将Pixel Shader单元数量从X1800的16个推升到48个。这一改动使得GPU运算能力空前强大,其高端产品RADEON X1900XTX的FP32精度像素运算能力达到374.4GFLOPS,如果再加上顶点着色器的话,RADEON X1900XTX的FP32计算能力总共会是426.4 GFLOPS——R580因此得名“3:1黄金架构”。大幅提升的运算能力除了提高了对像素着色器运算需求饥渴的游戏之外,也引起了另一方的注意,那就是斯坦福大学。
该项目同时引来了全世界大量GPU高端玩家的参与,这是第一个可以让民用级别显卡开展大规模通用计算的尝试,也是目前最火爆的分布式计算项目。该项目在中国发展缓慢,主要是因为真正能理解GPU的玩家数量还是很少,甚至高端发烧友都对它一知半解。而事实上比较运算量可以得出,一款普通的9600GSO显卡的运算能力,已经远远超越一颗高端的4核心CPU。
中国分布式计算总站作为一个公益性团体,一直在致力于各个分布式计算项目的推广,特别是属于生命科学类别的Folding@home项目。该项目中国团队代码为3213,有兴趣或者想提升技术的玩家,可以尝试参与该项目,为自己的GPU通用计算能力找到一个“发泄”的空间。
● 统一着色器架构再次释放GPU运算能力
在GeForce 8800 GTX之后,AMD经过数月的延迟后推出了代号R600的RADEON HD 2900XT核心,这款产品和NVIDIA的新品一样使用了统一渲染架构,不同之处在于2900XT的64个SIMD着色器内包含了5路超标量(superscalar)的运算单元(ALU),我们习惯性称其拥有320个流处理器。组织形式方面,SIMD单元采用超标量+VLIW(甚长指令)设计,虽然从数量上看规模庞大(共拥有320个ALU,8800 GTX为128个),但是执行效率在实际运算特别是通用计算中会发生不可忽视地衰减。
为方便讨论,在后文分析中,我们将更多地把着色器Shader称为流处理器Stream Processor。
● 揭秘GPU为何如此强大
● 两种架构设计方向不同
CPU和GPU架构差异很大,CPU功能模块很多,能适应复杂运算环境;GPU构成则相对简单,目前流处理器和显存控制器占据了绝大部分晶体管。CPU中大部分晶体管主要用于构建控制电路(比如分支预测等)和Cache,只有少部分的晶体管来完成实际的运算工作。
而GPU的控制相对简单,而且对Cache的需求小,所以大部分晶体管可以组成各类专用电路、多条流水线,使得GPU的计算速度有了突破性的飞跃,拥有了惊人的处理浮点运算的能力。现在CPU的技术进步正在慢于摩尔定律,而GPU(视频卡上的图形处理器)的运行速度已超过摩尔定律,每6个月其性能加倍。
CPU的架构是有利于X86指令集的串行架构,CPU从设计思路上适合尽可能快的完成一个任务;对于GPU来说,它的任务是在屏幕上合成显示数百万个像素的图像——也就是同时拥有几百万个任务需要并行处理,因此GPU被设计成可并行处理很多任务,而不是像CPU那样完成单任务。
当今CPU仅前端部分就非常复杂,指令解码、分支预测等部分消耗晶体管数量巨大。CPU的设计目标是不仅要有很高的吞吐量,还要有良好的应用环境兼容性,CPU所要面对的应用面远远超过了GPU。CPU是设计用来处理通用任务的处理、加工、运算以及系统核心控制等等的。CPU中包含的最基本部件有算术逻辑单元和控制单元,CPU微架构是为高效率处理数据相关性不大的计算类、复杂繁琐的非计算类的等工作而优化的,目的是在处理日常繁复的任务中应付自如。
GPU设计的宗旨是实现图形加速,现在最主要的是实现3D图形加速,因此它的设计基本上是为3D图形加速的相关运算来优化的,如z-buffering消隐,纹理映射(texture mapping),图形的坐标位置变换与光照计算(transforming & lighting)等等。这类计算的对象都是针对大量平行数据的,运算的数据量大。但是GPU面对的数据类型比较单一,单精度浮点占到其处理数据的绝大多数,直到GTX200和HD 4800系列显卡才对双精度运算提供了支持。
● 两种架构运算能力不同
现在的CPU和GPU相比芯片规模也呈现出巨大的差异。从相关资料中我们可以了解到,GTX200使用台积电65nm工艺生产,集成多达14亿个晶体管,核心面积576平方毫米,是有史以来规模最庞大的图形芯片。45纳米Penryn家族处理器中的双核心版本内建4.1亿个晶体管,分析图片我们可知其中约2亿个晶体管用于SRAM二级缓存。
● GPU逐渐强化的双精度运算能力和存储子系统优势
容量足够大的共享缓存可以在运算时提高线程的挂起能力,这将直接提升GPU的分支运算能力。同样大容量的缓存在运算精度提升时可以确保更低的性能衰减,届时GPU将拥有更强的双精度能力,理论上会和其单精度运算能力一样远超CPU。这样的直接后果是让GPU更加适应混合精度环境,让通用计算走得更远。
目前GPU已经是足够强大的可编程处理器,非常适合大运算量的科学应用,诸如地质勘探,生物学,流体力学,金融建模等等。这使得GPU应用于地球科学、分子生物学和医学诊断领域的高性能计算为实现重大的发现提供了可能,这些发现会改变数十亿人的生活。
● GPU架构设计导致的运算能力差异
Radeon HD 4870与GTX 280最明显的区别就是流处理器结构,Radeon HD 4870选择延续上一代非统一执行架构GPU产品的SIMD结构,用庞大的规模效应压制对手,偏向于ILP(指令并行度)方向,而GTX 280则使用了G80以来创新的MIMD架构,更偏重于TLP(线程并行度)方向。在单指令多数据流(SIMD)的结构中,单一控制部件向每条流水线分派指令,同样的指令被所有处理部件同时执行。另外一种控制结构是多指令多数据流(MIMD),每条流水线都能够独立于其他流水线执行不同的程序。
其实在上一代非统一执行架构GPU中(如Geforce 6800 Ultra),顶点着色器流水线已经使用了MIMD方式控制,像素着色器流水线则继续使用SIMD结构。MIMD能比较有效率地执行分支程序,而SIMD体系结构运行条件语句时会造成很低的资源利用率。TLP要求强大的仲裁机制,丰富的共享cache和寄存器资源以及充足的发射端,这些都是极占晶体管的部件。不过SIMD需要硬件少,这是一个优势,这也就是为什么Radeon HD 4870拥有800个流处理器,晶体管集成度却低于240个流处理器的GTX 280。
此外在高密度并行运算中,AMD的R600和RV770的发射端资源面临一定程度的短缺。以RV770(Radeon HD 4870)为例,每个流处理器单元(“1大4小”5个流处理器)配备了1个发射端,所以如果要保证指令吞吐不受限制就通过VLIW,也就是超长指令打包的形式将若干个短指令打包在一起。VLIW应用在RV770中理论上可以做到1个4D+4个1D打成一个包一起丢进US,这样可以最大限度的避免发射端不足的问题。可是如果遇到条件分支,也就是说这个包里面有一个1D指令的结果很不凑巧是同一个包里另外一个1D指令的初始条件,整个架构的效率会受到影响。
还有一个不可忽视的问题是最小线程执行粒度。粒度越细,能够调用并行度来进行指令延迟掩盖的机会越大,性能衰减越小。细化粒度偏向TLP方向,对GPU的线程仲裁机制要求很大,最终会导致硬件开销过大。我们知道GPU通用计算中最小的执行单位是线程(Thread),多个线程会被打包成一个线程束,NV称线程束为Warp,AMD称之为Frontwave。但是在粒度上两家厂商做出了不同的选择,Frontwave包含64个线程,NV的线程管理粒度更小,每个Warp包含32个线程。R600和RV770每凑够64个线程,仲裁器就会动作一次,把一个Frontwave发送给空闲的一个SIMD Core。NV的G80和GT200比较特殊,存在Half-Warp,也就是说每16个线程就可以发送给SM一次。Half-Warp由线程中的前16个线程或者后16个线程组成。
总体来说,两家厂商的差异在于:AMD堆砌了更大规模的运算器单元,NVIDIA则更注重如何利用有限的运算器资源。AMD将更多的晶体管消耗在大量的SIMD Core单元上,NVIDIA则将更多的晶体管消耗在仲裁机制、丰富的共享缓存资源和寄存器资源以及充足的发射端方面。AMD的GPU偏向于ILP结构,NVIDIA偏向于TLP结构。TLP(线程并行度)考验线程能力和并行能力,ILP(指令并行度)则考验指令处理。从G80和R600的对垒开始,两大图形芯片厂商一直延续着这种竞争思路。
● Fermi GPU架构带给我们的思考
在经过漫长的4年开发期之后,众望所归的Fermi架构GPU终于诞生,这款GPU身上凝聚了众多“第一”,打破了很多芯片设计的世界记录。有人说Fermi拥有强大的Tessellation细分曲面单元,也有人说Fermi拥有高倍的AA特性,而实际上这都只是Fermi架构的毛皮,或者说在图形领域的一些细微改进。实际上Fermi的真正提升在于架构代差……
诸如曲面细分之类的东西在未来更长一段时间内将逐渐淡化,因为那些不过是体现了一个公司对微软历代DirectX要求的理解和按图索骥的能力罢了。真正体现水平的是运算单元部分,是每一个运算器的构成和组织方式。
1、更大更全的缓存体系:GF100核心和上一代GPU相比,除同样拥有12KB的L1纹理缓存之外,其拥有真正意义的可读写L1缓存和L2缓存。GF100核心使得GPU中首次出现了64KB的RAM支持可配置的shared memory和L1缓存。
为GPU引入缓存也意味着风险,首先缓存的可读写性带来了很多问题,它包括缓存一致性协议,这需要用复杂的逻辑进行控制。其次缓存的命中率等问题需要NVIDIA着手解决,如果缓存的命中率过低,引入缓存将带来数据读写减速。同时还不得不考虑缓存引入的大量晶体管开销(前文已经分析)。
2、底层计算单元不断改进:毫无疑问,G80到 GT200以来,NVIDIA的MIMD架构流处理器设计一直是图形芯片中效率最高的,虽然它很耗费晶体管,但是以最后实际性能衡量,还是和划算的。这次Fermi延续了这种设计,但是在计算单元和周边资源方面做了扩充,更高的精度和更小的衰减是永远的目标。
Fermi所支持的FMA指令在做乘运算和加运算的时候只在最后运算的时候作一次舍入,不会在执行加法的时候就出现精度损失。其次Fermi架构为支持双精度浮点运算进行了特别设计每一个SM在一个时钟周期内可以完成16个双精度浮点数的FMA操作。同时大量原子操作单元和L2缓存的使用,大大增强了Fermi GPU架构中的原子操作能力。
3、更强大的线程调度能力和分支论断:在Fermi上的一个重要特性,就是它的双层分布式调度机制。在片上的层面(SPA Streaming Processor Array,流式处理器矩阵级别),全局的分布式线程调度引擎(global work distribution engine)分发block到每一个SM上,在SM层面,每一个warp分布式调度引擎按照32个线程为一个warp执行。
Fermi实现了SM级别的双发射,意味着SPMD(单线程多任务)的实现。并行kernel下到最底层实际上就是靠的SM级别的双发射。SM级别的SPMD上升到GPU核心级别,Fermi就是MPMD(多线程多任务)。这种设计已经越来越像CPU,而且随着GPU的发展,每走一步,就多像一份。
PTX是NVIDIA针对支持并行线程处理器运作而设计的低级虚拟机和ISA,当程序执行之前,PTX指令会被GPU驱动转译为GPU的本机代码。Fermi所支持的PTX 2.0 ISA为所有的指令提供了predication(论断)支持,使得这个特性可以更容易、更快地去执行条件语言。在Fermi中为这一功能的初步实现提供了一个独立单元,它和仲裁器、Atomic单元的地位一样重要。分支论断只能算是分支预测的雏形或前身,但这种功能在以前的GPU上是可望而不可及的。
● GPU通用计算正在飞速发展
巨大的运算能力让人们对GPU充满期待,似乎在一夜之间,GPU用于通用计算(General Purpose GPU)及其相关方面的问题成为一个十分热门的话题。视频编码应用,比CPU快18倍;期货风险控制系统,整个系统性价比提升9倍;医疗行业应用,CT立体化且提速20倍;地理信息系统应用,速度提升可达50倍;生命科学研究,等待时间缩短12倍;矩阵计算以及仿真能力,比CPU快17倍……一个以GPU为中心的高效运算平台正在向我们走来。
———————————————————————————
本文参考文献:[1] 抛弃CPU 迎接 GPGPU计算新时代[2] 从平民到皇帝 NVIDIA产品14年发展回顾[3] 虚拟世界由此开始 追逐3D世界的脚步[4] 3D游戏的盛宴:DirectX10深入剖析[5] 16毫米攻防战 RADEON HD 4850测试报告[6] GPU,颠覆的不仅仅是视界[7] 改变翻天覆地 史上最全Fermi架构解读[8] GPU高性能计算之CUDA