在上期,我们介绍了代号为GK110的NVIDIA图形核心的规格和架构设计方面的内容。在这个史无前例的巨兽面前,之前所有的GPU设计都似乎黯淡了下来,超大规模的晶体管和无与伦比的规格参数,都让玩家对GK110充满了好奇。当然,除了硬件规格上的强悍外,GK110还带来了诸多新奇和震撼的功能。
就像上期介绍GK110规格时所说的那样,在GK110首次公开的信息中基本上不包含对其图形和游戏性能方面的介绍。因为从NVIDIA的设计思路来看,GK110将像首款Fermi产品GF100那样,除了具备超强的游戏性能之外,还是一颗面向高性能计算的GPGPU。可以说,GK110一大目的就是利用自己超强的架构、规模和功能设计,帮助NVIDIA在未来的高性能计算市场占据重要地位。因此,NVIDIA针对目前GPU并行计算中存在的问题进行了一些改进,并带来了部分新的功能。下面本文就对GK110的重要功能一一进行介绍。
在传统的GPU-CPU的计算架构中,CPU往往用于控制、逻辑处理等,自己贡献的计算能力不多,GPU则会利用大规模并行计算能力提供强大的计算性能。在这种系统中,GPU需要在CPU的控制下才可以运作。
NVIDIA给出的动态并行控制的示意图,可见在kepler上,CPU的工作被大大简化了。
NVIDIA给出有关动态并行控制的实例图。三幅图片中,左边的一副图片是低精度,但是速度快;中间的是高精度,但是速度很慢;右边图片展示的的是自动控制,在右边图片的左侧变化较小的部分使用低精度,图片右侧变化较快的部分使用高精度,既保证了计算进度又兼顾了效能。
在Fermi执行程序的过程中,任何一个任务都是由CPU分发给GPU,GPU执行完成后再告诉CPU,然后CPU再给GPU新的任务。举例来说,A任务执行完成后,如果结果为真,那么执行B任务,否则执行C任务。这是一个简单的条件判断。一般用类似“if……else……”的语句来处理。在Fermi上,这个任务的执行过程是这样:
1.CPU分配A任务给GPU,GPU执行计算并完成计算。
2.GPU请求CPU判定,CPU判定结果为真(或者假)。
3.CPU指定GPU处理B(或者C)任务,GPU执行计算并完成计算。
4.GPU向CPU报告任务完成,等待CPU确认。
5.CPU分配下一个计算任务给GPU。
Fermi拥有很不错的并行计算能力,但无法处理类似的判断语句。用“正规”一些的语言来描述,也就是说,在CUDA执行中,Femri的任何一个Kernel只能由CPU给予,自己基本无法执行判断和逻辑操作,即使这个逻辑非常简单。Kernel是CUDA的专用数据,汉译为“核心、要点”,在CUDA中,在GPU上执行的程序或者计算,可以被称之为kernel。
这种GPU和CPU的紧密相关性,让CPU在很多情况下占用率变高,对CPU的性能也有一定要求。实际上这种简单的判定工作需要的处理电路并不复杂,于是在GK110上,动态并行控制的加入,让GPU在执行类似语句时有了判定的能力。
我们依旧用上面的例子来打比方。在上述过程中,对CPU来说,很大部分时间都用于帮GPU做判定、给GPU指派任务。拥有动态并行控制后,上述流程将变为:
1.CPU给GPU任务A。
2.GPU处理A,然后自动判定,并生成新的任务,自动处理C或者B。
3.GPU报告CPU处理完成。
这样的过程变得更为清晰简单,在整个流程中,CPU只需要关心开始和结束,对中间的内容几乎不需要参与。这可以节约大部分CPU的工作量,让CPU去进行更复杂的任务或者干脆使用一颗性能较低的CPU即可完成。此外,动态并行控制可以让GPU在同时间内启动更多的计算进程,并且能够自我判断、自动控制计算,也能为程序人员节约大量的时间。
NVIDIA给出了一个例子展示动态并行控制的计算方式。在对一些流体或者热量的计算中,为了取得比较合理的数据,通常要么使用一个比较粗的计算粒度来获得比较宽泛的数据,这样对GPU来说计算压力很小,但精度不够;要么使用极为精细的计算粒度来获得精确数据,但这样对GPU的性能压力又太大了。因为GPU不能动态进行并行控制,并且不能自己指定计算kernel,因此只能机械地以某种固定的值来进行计算。对程序编制人员来说,找出一个合适的值,来既保证精确度,又保证GPU不会由于计算强度过高而浪费时间,也是一件颇为头疼的事情。
在动态流程控制启用后,这样的事情就变得简单多了。程序员可以制定命令,让GPU自己去判断是否需要更高的计算精度。在NVIDIA的例子中,左侧的部分变化很小,因此不需要经常刷新、计算要求不高,但越往右侧,变化越频繁,越需要更精确的计算。在这种情况下,GPU可以自动判断左侧的部分并使用低精度计算,右侧计算精度则高一些。这样既可以节约计算能力,又能获得需要的计算精度。
传统的多核心CPU在和GPU沟通工作任务时存在一些问题。举例来说,在Fermi架构上,Fermi架构支持多1个信息传递界面(Message Passing Interface,简称为MPI),只能接受来自于CPU的一个工作任务。造成这样的原因主要是考虑到伪相依性问题(主要指在GPU计算过程中的排列问题,比如谁先写入、谁后写入、谁先占用寄存器等)。对CPU来说,由于只有一个MPI,CPU多核心运作效率往往不高。并且由于MPI数量单一,如果任务不繁重的话,可能出现GPU效率不高、无法达到满载的情况。虽然在很多情况下,通过重新排布等方法,这样的问题可以得到一定程度的缓解,但面对越来越复杂的程序,单一MPI本身对GPU利用不高、浪费CPU性能的问题逐渐变得令人关注。
在GK110上,NVIDIA使用了名为Hyper-Q的技术来大幅度提高CPU的效率和GPU的占用率。Hyper-Q的主要改进在于增加了CPU和GPU内的CUDA Work Distributor(直译为CUDA工作分发设备,简称为CWD)之间的链接总数。再加上其他的改进,新的GK110可以接受来自多个CUDA命令以及MPI的进程,甚至一个进程内部的多个工作执行单元都可以在新的GK110上并行执行。现在GK110可以执行多32个并行的MPI。为了达到这个目的,每个CUDA进程的内部工作序列管理,以及相依关系等需要重新处理以达到佳化,并且GK110在某进程内部的计算不会扰乱或阻挡其他进程。如果不同进程不存在严格的相依性,也可以同时并行执行,大大提升了效率。
NVIDIA给出了例子用于解释Hyper-Q的工作方式,在Fermi上,A-B-C、P-Q-R、X-Y-Z之间的CP、RX之间存在伪相依关系。也就是说,C的执行结果虽然和P完全没有任何关系,但C可能会和P使用同样的寄存器(或者其他原因),那么Fermi只有等C执行完了以后,才能开始P的执行。但是在GK110上,由于伪相依的关系被Hyper-Q移除,A-B-C、P-Q-R、X-Y-Z三个程序可以分别同时执行。就像本文前面描述的那样,CPU可以充分发挥多核心优势,同时给GK110提供多个并行的任务,提高CPU占用率,GK110本身也可以达到高效率、满载运行的状态,让计算在短时间内完成。
为了更好地完成动态并行技术、Hyper-Q等新技术的操作,NVIDIA还特别设计了全新的网格管理单元,对Grid进行操作。
Hyper-Q可以让MPI界面链接增加到32个,远远超过Fermi的1个,在极限条件下,Kepler效能会达到Fermi的32倍。
什么是Grid呢?直译Grid的意思是栅格、网格。在CUDA中,线程低等级是Thread,多组线程组成了Warp(上期已经介绍过),再上一层是Thread Block,上层是Grid。简单来说,Grid类似与一个在CUDA中的完整程序功能组,这个功能组可以实现自己独特的功能,与别的程序相关性很差。每一个Grid拥有自己独立的全局内存、常数内存和纹理内存。
在Fermi上,每一个Grid在接受CPU命令启动后,会直接执行到结束,中途不会停止也不会被暂停替代。在GPU上,Grid会由CWD建立一个CPU到SM的单向工作流。这个单向工作流由CPU发出,目标是SM。SM在没有执行完成之前,是不能得到CPU任何指令的。
这样的做法足够简单,但稍显粗暴,GK110需要的动态流程控制等功能显然和这样的设计相悖。举例来说,在GK110上,第一个Grid依旧由CPU启动,但是新的Grid也可以由GPU内部的SMX单元内、以新程序的方式由CUDA建立—这是动态并行控制工作的重要方式。为了达到这个目的,NVIDIA设计了一个新的、被称作Grid Management Unit(网格管理单元,简称GMU)的新部件,控制这些新生成的Grid并给予Grid更多自由的功能。
GK110在执行CUDA程序时,GMU能够调度在CWD中准备好的32个执行中的Grid。和之前CWD直接单向链接SM不同的是,GMU以双向链接和CWD相搭配,这种双向链接设计,可以让GMU暂停新的Grid,分配新的Grid或者保留等待的Grid在存储器中以便需要的时候再进一步发配。GMU和SMX单元直接链接,新的动态并行控制功能也可以在GMU的控制下,根据工作任务的优先级来排列,以更好地确保GPU的工作效率。
简单来说,GMU实际上是NVIDIA在GK110中加入的一个全新逻辑处理区域,它的使用使得GK110进一步降低了对CPU的需求。GMU和之前的动态并行控制等功能一起,极大地提升了GK110的并行计算效能,让GPU能够真正以更聪明、更智能、更接近CPU的方式工作。
目前的大规模并行计算早已不满足于使用单一GPU来进行计算,多GPU进行“并行之上的并行”是迅速提升计算能力的重要技术。之前的GPU比如Fermi,虽然可以很好地进行并行计算,但每个GPU本地显存中存储的数据却不能互相访问。
在使用了GPUDirect后,整个数据访问会变得更为简单,跨设备和跨区域的访问成为可能,这可以节约大量时间并极大的提升效率。
这就带来了一个数据互联互通的问题。在并行计算中,将任务分配给多个GPU同时计算时,如果GPU之间的计算数据不能有效通讯,那么只有等待计算完成后才能统一将数据和结果再次综合并分配下去,这样无疑降低了效率并浪费时间。NVIDIA在Kepler上引入了GPUDirect功能,GK110更是支持GPUDirect中的RDMA功能。这个功能的特点在于可以让第三方设备,比如网卡、SSD等设备直接读取GPU显存,从而降低中转步骤并提高性能。此外,在一些需要多GPU并行分布计算的任务中,不同的GPU借助GPUDirect和CUDA 5.0,可以互相访问对方显存中的数据,GPU和GPU的直接通讯可以不经过CPU以及PCI-E控制器,速度和访问延迟都得到了极大的改善。
NVIDIA在GPU通用计算的道路上已经走了很远。现在,NVIDIA GPU的设计已经基本上彻底GPGPU化。和图形处理器发展中GPU不断用新的功能代替CPU计算一样,目前NVIDIA在通用计算中,一步一步地在加强GPU本身的功能,加入了更多类似逻辑判断、流程控制等功能,以期望在未来的发展中进一步降低CPU在整个CPU-GPU体系中的重要性。比如采用性能更低的CPU(比如ARM架构)也可以组建性能强大的超大规模并行计算体系,这和NVIDIA本身的产品缺陷和发展方向是一脉相承的。
NVIDIA没有足够强大的CPU产品,即不能像AMD那样以APU为名,实现CPU和GPU的片上融合;也不能像英特尔那样以强大的CPU性能搭配众核架构来实现超大规模并行计算。因此,NVIDIA只有不断地加强自己的GPU,让GPU做更多的工作,再搭配未来可能出现的强大的采用ARM架构的CPU来实现自己跨越发展的梦想。
通用计算目前的难题依旧在并行本身,如何让程序更进一步并行化并有效率的工作,是所有程序员需要面对的困难。英特尔的众核计划产品Xeon Phi已经向NVIDIA步步逼来,不过Xeon Phi也要面对并行化的困扰。相信凭借英特尔强大的技术研发实力和市场能力,在超大规模并行计算市场上分一杯羹显然不算太难。NVIDIA需要进一步加强实力,因此我们看到了GK110,这个71亿晶体管的巨兽,它带来的不仅仅是NVIDIA创新的图形和通用计算技术,还有NVIDIA的希望。