提高桌面级计算机指令级并行度的方法[转]

并行计算从其并行的粒度来看,分为指令级、循环级、过程级、子程序级、作业级;而从并行计算机的体系结构而言,存在着核内并行、晶核级并行、PCB板级核间并行、机箱级并行、机架级并行、机群(异构)级并行,等多种并行等级。不同的并行粒度与不同的并行等级之间,是有着对应关系的。
  其指令级并行,与CPU内部结构有着紧密的关联,指令级并行包括核内多条指令的并行与多个核之间指令的并行。

       从计算机体系结构而言,就是核内并行与晶核级并行。如何提高这两种并行度,对于CPU结构有着不同的要求;对于并行程序的编制也有不同的要求。
  本文根据本人近期所阅读的书籍,以及从网络上获取的资料,通过分析目前较新的并行芯片结构,找到提高并行度的关键点。并从软、硬件方向预测为了进一步提升效率,未来并行芯片结构的发展方向,以及编制并行软件的改变。

一:核内并行
1:指令的流水线操作
  事实上从8086开始,就存在有核内并行。
  在8086以前的微处理器,对指令的操作都是串行的,即对每一条指令而言,都是先取指令,再分析、执行。具体可表示为:

取指令——【读操作数】——执行——【写操作数】——取(下一条)指令一……

方括号内的操作是操作数在内存中时所要进行的,当操作数是CPU内部的某个寄存器时,则不需要这一步。显然,在指令执行期间,总线(BUS)是空闲的,这一重要的系统资源没有得到充分利用。
  而8086是由它由两大部分组成:执行部件(Eu:Execute Unit)和总线接口部件(BIU :BUS Interface Unit)。前者负责指令的译码和执行,后者负责所有涉及外部总线的操作。二者既独立工作,又相互配合。
  而8086在执行部件执行指令期间,总线接口部件可利空闲,用总线预取后续指令或进行存储器操作数的读或写。这种不同指令在同一时间内处于不同执行状态的指令并行操作,或者说指令的重叠执行,通常被称为指令流水线操作。
  BIU使用了指令预取队列机制来实现指令流水线操作。该队列的容量为6个字节,即允许预取6个字节的指令代码。每当指令队列有两个或两个以上的字节空间,且执行部件未向BIU申请读/写存储器操作数时,BIU顺序地预取后续指令的代码,并填入指令队列。
  指令队列的工作方式是先进先出(First-in,First-out,FIFO),或者说是管道方式,先预取的指令即排在前面的指令先被取走执行,后面的依次向前推进,腾出的空间再放新预取的指令。
  而当执行部件执行指令时发现是一条转移指令,则总线接口部件清除队列,从新的地址取指令,并立即送给执行部件去执行,然后,从后续的指令序列中预取指令填满队列。可见,一遇到转移指令,就要重新预取指令队列中的下一条及下下一条指令。显然,这会明显影响机器的运行速度。 
  核内并行,可以极大的减少平均指令执行周期(CPI),如使普通的CISC架构处理器的CPI值从5-8降低到略大于1。

  从上述说明可以看出,要提高核内并行度,有做以下几个方面的提高。

(a)处理转移指令。
  8086乃至80386、80486,在遇到转移指令时,会放弃所有的指令预取队列,从而影响效率。直到Pentium出现,引入了分支指令预测技术,才得以克服。
  在Pentium微处理器中包含2个预取指令队列,指令的分支预测是由一个叫做分支预测逻辑和分支目标缓冲器(BTB)的功能部件完成的。2个预取指令队列不是同时工作,在同一时刻只有一个预取指令队列处在有效状态。指令预取器从指令Cache中取出指令以后,将它们顺序存放在那个有效的预取指令队列中,当预测分支指令将会发生转移时,预取器将跳转到分支指令的转移目标地址顺序取指,并将当时空闲的第二条指令队列激活,把取出的指令顺序存放在第二条指令队列中。
  同样可以看出,不能使用密集的转移指令,这仍将使分支预取实效。随着分支预取的进一步扩展(如Athlon64可以在16字节的范围内记录3条分支),这一限制正在不断缩小,但仍旧是可能影响效率的一个方面。

(b)对寻址方式的限制。
  对流水线进行分析,操作数如果是寄存器,自然不需要访问内存;如果是立即数,也已经进入预取队列,并进行了译码。但如果操作数不是寄存器或立即数,就必须重新从内存中读写数据。直接寻址还可以在译码后先期取得;而间址、变址,只能在执行到指令时才进行访问。
虽说L1、L2乃至L3的高速缓存越来越大,而且从片外移到了片内,提供了较高的命中率,但其速度仍旧无法同寄存器相比。对数据段内存的过多访问,会降低系统的运行效率。通过增加寄存器数量,减少内存访问来提高效率,促使了在上世纪90年代RISC技术的极大发展。
  RISC的load/restore指令只有在访问内存时才使用,所有其它的指令都是在寄存器内对数据进行运算。一条存取数指令从内存将数据取出放到寄存器中,在那里可以对数据进行快速处理,并把它暂存在寄存器里,以便将来还要使用。在适当的时候,一条存数指令可将这个数据送回到它在内存中的地址中去。RISC的设计技术与CISC的设计技术相比,有大量寄存器。由于允许数据在寄存器中保留较长的时间,这样就减少了存/取指令对内存访问的需要。
  RISC中所有指令采用固定长度,寻址方式不超过三种,简化了逻辑和缩短译码时间。确保单周期执行指令,由于指令的固定格式保证指令译码和取操作能同时进行,从而有利于流水线操作的执行。
  精简的指令更容易被流水线所操作。但由于软件的兼容性,以x86系列为代表的CISC仍占据着主要的市场。

(c)RISC与CISC的结合。
  RISC与CISC各自的优缺点,使其有相互结合的必要。
  从使用IA-32结构的Pentium PRO开始,其微体系结构就采用了RISC的设计思想,它将x86指令转换成多个易执行的微操作(mops),该操作为3操作数格式,对程序员透明,而与x86指令兼容。
  这样,即利用了RISC技术适宜流水线操作的优点,又兼顾了软件的兼容性。

2:指令的超标量技术
  从Pentium开始,在一个内核中出现了多条流水线。如Pentium就包含两条整型流水线U、V,和一条浮点流水线。这使得CPI首次在理论上可能小于1。
  需要说明的是,这并不是现在意义上的多核芯片,这是因为

(a)各条流水线使用了同样的指令cache、同一条指令预取队列、同样的寄存器组,根据指令配对法则,将满足一定条件的两条指令同时执行。每条流水线并不能成为完整的内核。
(b)U、V两条流水线并不相同。U流水线可以执行所有的x86指令,而V流水线只能执行部分的“简单”指令。而能够同时执行的两条指令,也必须都是“简单”指令,并且没有寄存器数据相关。所谓的“简单”指令是指由硬件逻辑、而非微码实现的单周期指令。

  而Pentium PRO中,各条流水线的功能已经相对独立。在实际操作时,各流水线使用独立的寄存器,并由分发 / 执行部件(DEU)将操作数无关的mops“乱序”执行。而在执行结束以后,通过退离部件(RU)按原指令流的顺序取走已执行完的mops,把物理寄存器还原成逻辑寄存器,把无序的执行按原始指令流输出结果。
  使用RISC设计思想而出现的mops、多物理寄存器结构,都被硬件所屏蔽,对用户透明;用户看到的只是一个可以部分并行的x86结构。

3:提高核内并行度的方法
  要提高核内并行度,其主要的方法有:

(a)内存大小匹配:当不同的指令操作相同的数据时,要避免内存大小失配。当一条指令读写了一个数据,随后另一条指令又读写这个数据,则要保证数据是对齐的,即保证两次都以相同的大小读写这一内存数据;
(b)适当的内存拷贝程序:内存的复制是在程序中经常使用,而且占据相当时间周期的操作,要充分利用其内存带宽,使用专用的读写指令,如读:PREFETCH、写:PREFETCHW等;
(c)分支指令的对齐:指令的预取是按块进行的,如16B。不要将分支指令与这样的块边界交叉,跨边界的指令不能进行分支预取。会影响执行的效率;
(d)分支指令的密度:指令分支预取的分支数量是有限的,如果有集中的多条分支出现,就会出现没有预取的分支;
(e)使用读取—执行的指令:不要使用分别的指令来进行读取和执行,而使用直接读取操作数并执行的方式。以提高cache的命中率;
(f)避免代码段与数据段的重叠:避免代码的自修改,避免代码段被放到数据段,这些都会引起L1 cache的效率降低;
(g)使用正确的数据类型:对于浮点指令避免使用整型操作数,SSE、SSE2指令等使用相对应的数据类型;

  上面的方法都可以提高流水线的效率,为整个程序的执行提高也许不到1%的速度。当然要提高指令并行度(ILP),成倍提高运行速度,最关键的是:减少相邻指令的关联度。这样多条指令才能乱序执行,做到真正的指令级并行。

  从计算机体系结构的概念——“程序员所看到的计算机”——而言,让每一个程序员都去了解核内的流水线结构是不现实的。较可行的方法是由优化编译程序来完成。
  上述提高流水线效率的几点,都可以很方便的由编译程序来完成。减少用户程序的指令关联度可能较难;但是可以对所有的库函数进行优化,重新编写出相邻无关的指令序列,从而提高整体的执行效率。

  这里提到了并行计算的最细粒度——指令级并行。由上所述,要提高核内指令级并行,需要的是提高核内的超流水线、超标量技术,并由目标程序充分利用这些技术;最重要的是利用编译程序减少相邻指令的关联度,乱序执行指令。

二:晶核(DIE)级并行
1:从单核到多核
  为了提高CPU的性能,通常做法是提高CPU的时钟频率和增加缓存容量。不过目前CPU的频率越来越快,如果再通过提升CPU频率和增加缓存的方法来提高性能,往往会受到制造工艺上的限制以及成本过高的制约。 
  提高计算机的性能已经从单纯的提高速度,转变为由单核向多核发展,通过提高芯片内的并行处理能力,来提高整体的性能。
  大型并行计算机主要有SIMD,PVP,SMP,MPP,DSM,COW六种。多核芯片的模式也将会有类SMP、类MPP、类DSM、类COW等多种形式(SIMD、PVP的结构不利于扩展,发展前途不如其他几种形式)。

(1)类SMP:随着大规模集成电路技术的发展以及半导*造工艺的提高,人们已经将大规模并行处理器中的SMP(对称多处理器)集成到同一芯片内,从而实现单芯片多处理器(CMP),各个处理器并行执行不同的进程。SMP技术已经相当成熟,因此此类的多核处理器芯片,结构设计起来相对容易。
  在高端服务器领域,IBM Power5芯片最多可以包含8个处理器;而AMD K8、Intel Pentium D 9xx等桌面级芯片也是实际意义上双核心处理器,目前正向四核发展。
  与传统的SMP相比,CMP尺寸更小、功耗更低、速度更快。
  目前的多核处理器在内核中只放置了较小数量的高速缓存,而没有统一编址的内存(内存与高速缓存的关系见下文)。如果高速缓存的数量极大增加,并且可以统一编址供各个内核对等使用。那么单单一块芯片就能够完成以往一台SMP并行计算机的工作。
  与SMP并行计算机一样,类SMP多核芯片在内核数量增加时,会出现存储总线的访问瓶颈,不利于系统的扩展。

(2)类MPP:芯片的发展一方面是向多核发展,而另一个方向是向SOC(System on Chip)发展,不仅在芯片中包含控制器、运算器,还包含内存及输入、输出部件。类MPP实际就是这两个发展方向的结合。在一块芯片上集成多个核心,以及内存等其他部件。按照片内内存与内核连接方式的不同,就产生出类MPP与类DSM两种不同结构。
  如果所有的内核对所有的片内内存,可以进行对等存取,那么这仍旧是不利于扩展的SMP结构。类MPP与类DSM都会拥有各自独立的核内内存。
  MPP与DSM的区别在于是否存在内存的统一编址。而对于MSOC而言,芯片是由一个厂商统一规划、设计、生产的。应当较容易实现片内内存的统一编制。
  如果内核不需要访问到其他的核间内存,不进行统一编制,那就是类MPP;而如果核间通讯量大,需要访问核间内存,进行了统一编制,那就是类DSM。

(3)类DSM:此类芯片中包含有多个内核,每个内核中仍可能有多条流水线,甚至于每个内核仍是一台SMP。如2007年5月新推出的Power6芯片,每个微处理器(MPU)内核都作为2路CMP设计来实现,而在一块芯片上集成2或4块MPU。当然Power6从本文定义的结构上来说,还是类SMP,但在内核结构上已经有了类DSM的影子。
  每个内核都拥有自己独立的核内内存,或是由CMP内核共享的核内内存。该内存的存取速度应当接近于目前L1缓存。每个内核通过特殊的存取指令,可以访问到其他内核的核内内存。虽然内存已经统一编制,但是我仍然建议对于核间内存的访问使用与核内内存不同的指令,程序员应当了解到这两种内存的不同。
  核内内存应当存放被频繁访问的数据。如可以将程序中函数定义的局部变量放到核内内存中。这种方法可以被编译程序所使用,但是程序员无法直接控制。
  另在C语言中有register关键字。在目前条件下,由于寄存器数量较少,人工干预寄存器的分配反而会影响整体的效率。而如果将register关键字对应的变量放入核内内存,则能够极大的提高效率。这就相当于在使用高速缓存的芯片中,一个变量被固定在L1中,还不需要考虑回写。

(4)类COW:COW与其他结构的并行计算机相比,最大的不同是使用了通用的网络结构来进行连接。而如果将整个COW结构封装到一块芯片中,芯片内各个内核之间的连接必定是专用的。所以在这里的类COW只是套用了这一概念,实际是指多块多核芯片之间的互联。相对与芯片内的连接,PCB板上芯片间的连接网络更加“通用”。
  目前的类SMP结构芯片,已经存在有芯片间的互联。如IBM p5系列小型机,最多可以有64个内核(p5的并发多线程能力(SMT)使得从软件运行角度看,会有128个内核),也就是说会多达有8块Power5芯片互联。
  这里谈谈我对类DSM结构多核芯片互联的一些预测。
  对于每个内核而言,有着核内内存,片内核间内存,片间内存三个层次。这些存在于内核中的内存从整台计算机的角度被统一编制,但是这三个层次内存的访问速度逐级降低。目前意义上的主存,依旧存在,但是从其功能和用途看,更接近于当前意义上的外存储器。
  在当前的计算机中,程序和数据使存放在外设,如硬盘上。需要通过输入输出指令将其读入内存才能进行操作,并在需要的时候回写。而对未来可能的多片类DSM芯片组成的计算机而言,存在有易失性内存与非易失性内存(如FLASH)。非易失性内存取代硬盘作为外设存在;易失性内存临时数据、临时文件的存贮(如数据库的TEMP表空间)。

  类MPP、类DSM、类COW都只是本人的一点预测,从目前的文献以及网络资源上都还没有发现类似的讲法。

2:超标量、超线程与多核
  虽然CMP相对简单,但对于注重价格因素的桌面系统而言仍是一项复杂的工作。为此业界提出了一个折中的方案——多线程处理器(SMT)。多线程处理器对线程的调度与传统意义上由操作系统负责的线程调度是有区别的,它完全由处理器硬件负责线程间的切换。由于采用了大量的硬件支持,所以线程的切换效率更高。线程高效调度的目的就是要尽可能减少处理器处于闲置状态,通过有效的线程切换来获取处理器在相同工作时间内更高的工作效率。而SMT最具吸引力的是它只需小规模改变处理器核心的设计,几乎不用增加额外的成本就可以获得显著的效能提升。此类技术的代表就是超线程(HT/Hyper –Threading)。

  超线程技术是在一颗CPU同时执行多个程序而共同分享一颗CPU内的资源,理论上要像两颗CPU一样在同一时间执行两个线程,P4处理器需要多加入一个Logical CPU Pointer(逻辑处理单元),用以资源的分配。因此新一代的P4 HT的晶核(DIE)的面积比以往的P4增大了5%。而其余部分如ALU(整数运算单元)、FPU(浮点运算单元)、L2 Cache(二级缓存)则保持不变,这些部分是被分享的。 
  虽然采用超线程技术能同时执行两个线程,但它并不象两个真正的CPU那样,每个CPU都具有独立的资源。当两个线程都同时需要某一个资源时,其中一个要暂时停止,并让出资源,直到这些资源闲置后才能继续。因此超线程的性能并不等于两颗CPU的性能。
  HT技术造就了PENTIUM 4的一个辉煌时代的武器,尽管它被评为失败的技术,但是却对P4起一定推广作用。其实引用《现代计算机》杂志所比喻的HT技术好比是一个能用双手同时炒菜的厨师,并且一次一次把一碟菜端上桌;而真正的双核心处理器好比2个厨师炒两个菜,并同时把两个菜端上桌。很显然双核心处理器性能要更优越。按照技术角度PENTIUM D 8xx系列不是实际意义上的双核心处理器,只是两个处理器集成,但是PENTIUM D 9xx就是实际意义上双核心处理器,而K8从一开始就是实际意义上双核心处理器。 
  需要注意的是,含有超线程技术的CPU需要芯片组、BIOS、操作系统和应用软件支持,才能比较理想的发挥该项技术的优势。
  目前支持超线程技术的芯片组包括如: Intel 845E以后的芯片组,如845PE/GE/GV、865/875和915/925系列芯片组;VIA的P4X400、P4X533、PT800、PT880、PM800和PM880芯片组;SIS的SIS655、SIS648FX、SIS661FX、SIS655FX、SIS655TX、SIS649和SIS656芯片组;ULI的M1683和M1685芯片组。
  操作系统如:Microsoft Windows XP、Microsoft Windows 2003,Linux kernel 2.4.x以后的版本也支持超线程技术。
  一般来说,只要能够支持多处理器的软件均可支持超线程技术,但是实际上这样的软件并不多,而且偏向于图形、视频处理等专业软件方面。应用软件有Office 2000、Office XP等。但事实上如果有用户并发的操作,就能享用到一定的性能提升。

  双芯虽然比超线程更复杂,但事实上双核芯片早以有之。 “双核”的概念最早是由IBM、HP、Sun等支持RISC架构的高端服务器厂商提出的,不过由于RISC架构的服务器价格高、应用面窄,没有引起广泛的注意。比如拥有128MB L3缓存的双核心IBM Power4处理器的尺寸为115x115mm,生产成本相当高。
  而Intel和AMD公司的桌面产品正从单核多流水线、伪双核(超线程)向着真正的双核、多核进展。把多核并行从高端带到了平民阶层。而这两家公司的“真”双核产品还存在着很多结构上的不同。
  AMD Opteron 处理器从一开始设计时就考虑到了添加第二个内核,两个CPU内核使用相同的系统请求接口SRI、HyperTransport技术和内存控制器,兼容90纳米单内核处理器所使用的940引脚接口。是将两个内核做在一个晶核上,通过直连架构连接起来,集成度更高。从用户端的角度来看,AMD的方案能够使双核CPU的管脚、功耗等指标跟单核CPU保持一致,从单核升级到双核,不需要更换电源、芯片组、散热系统和主板,只需要刷新BIOS软件即可。
  而Intel则是将放在不同晶核上的两个完整的CPU内核封装在一起,连接到同一个前端总线上。可以说,AMD的解决方案是真正的“双核”,而英特尔的解决方案则是“双芯”。可以设想,这样的两个核心必然会产生总线争抢,影响性能。不仅如此,还对于未来更多核心的集成埋下了隐患,因为会加剧处理器争用前端总线带宽,成为提升系统性能的瓶颈,而这是由架构决定的。
  因此可以说,AMD的技术架构为实现双核和多核奠定了坚实的基础。AMD直连架构(也就是通过超传输技术让CPU内核直接跟外部I/O相连,不通过前端总线)和集成内存控制器技术,使得每个内核都自己的高速缓存可资遣用,都有自己的专用车道直通I/O,没有资源争抢的问题,实现双核和多核更容易。而Intel是多个核心共享二级缓存、共同使用前端总线的,当内核增多,核心的处理能力增强时,肯定要遇到堵塞的问题。

3:现有的高并行度多核芯片
  目前已经存在的高并行度多核芯片,不是哪家厂商生产的CPU,而是被称为GPU的显示处理芯片。
  单就浮点性能而言,现在的处理器已经远不如显示处理芯片,比如Intel Pentium 4 3.0 GHz约为6Gflops(每秒十亿次浮点操作),四路双核心Itanium 2也不过45Gflops,而最新的AMD R600可达到475Gflops。
  当今最强大的超级计算机是IBM的蓝色基因/L,拥有65536个双核心处理器,也就是131072个处理核心,峰值运算性能367TFlops。如果换算成R600,理论上只需不到800个图形处理器就能达到蓝色基因/L的性能水平。
  ATI早先发布的催化剂7.4驱动已经能够支持斯坦福大学的蛋白质折叠分布式计算,只要拥有一块X1000系列显卡,接入互联网,并且安装了斯坦福大学GUP分布式计算应用程序。那么就可以在显卡空闲时(非3D模式)为科学计算做一份贡献。由于所有的计算都是由显卡来完成,因此它不会占用您的CPU和内存资源,在上网和文字处理时不会受到任何影响,仅仅是占用少量的网络带宽,另外要消耗一部分电能。
  一家软件公司Peakstream声称,他们已经开发出一套新的软件平台,结合普通处理器的处理能力和显卡的资源即可打造出超级计算机。只需在已有计算机内简单地增加显卡,Peakstream就能将原有系统的能力提高20倍之多。根据Peakstream提供的数据,该平台性能与传统的处理器系统相比,在Monte Carlo Simulation测试中成绩可提高16倍,在Kirchhoff Migration中可提高21倍。GPU已经超越CPU成为当今桌面电脑系统里最强大的部件。

  GPU的主要部件包括顶点着色单元、象素着色单元、纹理单元、光栅化引擎。而随着DirectX10的发布,nVidia最新的G80(06年11月推出)与AMD(ATI)的R600(07年5月推出)都采用了统一渲染结构,使用较为通用的处理内核来进行顶点运算和象素运算。G80使用了128个并行的流处理器;R600使用了64个流处理器单元,而每个单元中有5个ALU,其中一个还能进行诸如Sin、Cos的复杂运算。

  除了内核数量的增多,显示处理芯片所能够达到的高性能还有以下一些原因。
(a)流水线程度高:CPU中就使用了流水线来提高核内并行度,如Pentium 4就有20级的流水线。但是流水线级数越多,一条指令从开始进入流水线到最后被执行完毕这之间的延迟间隔会相当大。而CPU的设计目标是不仅要有很高的吞吐量,还要求很小的延迟,这是CPU并不采用过多流水线级数的原因之一。另外流水线只有在满载时,才能发挥出最佳效率来。由于CPU执行的代码中有很多分支语句,因此长流水线需要用有效的技术来预测分支,尽量保持流水线在满负荷状态。但是一旦预测分支失败,就会清除流水线中滞留的大量无用指令,如果流水线阶段过多的话,再次充满整个流水线就需要很长的时间,速度反而下降了。所以权衡利弊,CPU不会使用深度流水线。
  但是GPU却采用了几百级的流水线,比如GeForce 3的流水线有800个阶段。这是因为1:显示可以有相当的延迟,只需要满足人眼的视觉暂留即可;即便是为了增强互动程度而提高帧速到100,也不过需要在10ms中完成,这对于只有几ns的时钟周期来说,根本就是天文数字,完全可以延迟。2:在GPU中执行的Shader程序中,分支语句用的很少(在早期的GPU中,甚至不提供动态的分支语句),流水线可以长时间的保持满负荷状态。因此,GPU的流水线深度变大后,利大于弊,大大提升了整体性能。
(b)并行线程的切换:GPU的执行速度很快,但是当运行到慢速指令,如从内存中获取纹理数据这样的指令时(由于内存访问是瓶颈,而且纹理越练越大,此操作比较缓慢),整个流水线便出现长时间停顿。在GPU内部Cache命中率不高,只用Cache解决不了这个问题。所以,为了保持流水线保持忙碌,GPU中使用了多线程机制。由硬件完成对这一线程的切换,对另一个像素进行处理。等到慢速指令完成时,可再切换到原先线程。
(c)并行数据的无关性: 无论是CPU送给GPU的顶点数据,还是GPU光栅生成器产生的像素数据都是互不相关的,可以并行地独立处理。而且顶点数据(xyzw),像素数据(RGBA)一般都用四元数表示,适合于并行计算。在GPU中专门设置了SIMD指令来处理向量,一次可同时处理四路数据。GPU中的各个执行部件,可以各自独立的获取数据,并进行计算,从而提高总体的运行效率。
(d)内存访问的限制:纹理片要么只能读取,要么只能写入,不允许可读可写,从而解决了存贮器访问的读写冲突。GPU这种对内存使用的约束也进一步保证了并行处理的顺利完成。

4:GPU的并行结构适合于并行科学计算
  以R600为例,其64个流处理器单元,每个单元中有5条流水线,从本文涉及的并行计算角度来讲,这就比G80多了一级核内并行。这5个ALU既可以一同执行一条5维向量运算,也可以同时执行5条标量运算,甚至是2+2+1、4+1等多种组合形式。而这一分配正是由分支执行单元(Branch Execution Unit)进行乱序分配而实现的,符合本文所述的核内指令级并行情况。
  而G80的128个流处理器被分为8组并行的阵列,每组16个流处理器;这16个处理器共享L1缓存(这一阵列的核内内存),每个处理器中只有一条流水线。这一个阵列就类似于一台CMT。而8组CMT合并成为一台类DSM。而线程的是通过线程处理器(Thread Processor)来进行分配。

  随着高速缓存的逐步扩大,cache块表所占据的容量也将增加,会使缓存实际容量的减少,造成浪费。个人认为当L1缓存从k级别大小上升到M级别时,就会拥有自己的地址,允许程序员自行将所需要的数据、变量放入其中。这主要是针对数据cache,当容量足够大时,由程序员自行定义会比硬件自动预取高效;而对于指令cache,由于指令的顺序执行特性,由硬件完成自动预取同样可以有很高的命中率。这可能会成为哈佛结构cache的一种发展方向。
其实这种拥有地址的高速内存,与RISC结构中数量成百上千的寄存器起到了同样的作用。将缓存改为内存,其实就是增加了程序员对缓存的直接干预;并由于取消了缓存与主存的映射,避免的回写问题。
  如果高速内存进一步扩大,大到能够放下整个进程运行所需要的代码段和数据段。那就达到了晶核级并行的理想状态。只有进程间的通讯才需要访问到核外的内存,每个线程在独立的内核中运行,由多流水线乱序执行指令,来实现核内并行;内核中的多路CMP共享核内内存,执行一个进程中各自的线程,执行晶核级并行;各个进程使用各自的CMP,执行核间并行。
这一层次的并行被称为晶核级并行,是因为与内核与核内内存之间的访问,必须有极其快的速度,从工艺上将,只有将内核与核内内存放置在同一晶核上才能实现,所以将这一层次的并行称为晶核级的并行。
  GPU正是使用类似的方式来实现极高的并行度,达到大大超越CPU的运算能力。从上述对两款最新GPU的表述中,可以发现AMD的芯片结构,其核内并行、核间并行层次清晰,更有利于科学并行计算。

  由此,可以看出,要提高晶核级核间指令级并行,需要编写多线程程序,利用芯片的超线程、同一晶核内的多核,能够同时运行多个线程的能力,并行执行多个线程。
  这就需要改变并行程序的编写习惯。在细粒度上编写多线程程序。如将每一个CMT内核所运行的进程,按照输入、合法性判断、计算、输出等不同功能,分别编制线程;这些线程形成实际上的流水线,将各自生成的结果交由队列管理,并由下一线程处理。不同的线程使用共同的核内内存,可以高效的并行执行。

三:芯片与并行操作系统的定制
  GPU之所以能够提供如此强大的并行计算能力,与其所使用的“并行操作系统”——DirectX有着密不可分的关系。

1:硬件设备无关性
  微软不仅开发了DirectX标准平台,并且根据硬件制造厂商和游戏厂商合作共同更新升级DirectX的标准。硬件制造商按照此标准研发制造更好的产品,游戏开发者根据这套标准开发游戏。也就是说,无论硬件是否支持某种特效,只要DirectX标准中有,游戏开发者就可以把它写到游戏中,当这个游戏在硬件上运行,如果此硬件根据DirectX标准把这个效果做到了此硬件驱动程序中,驱动程序驾驭其硬件算出结果,用户就可以欣赏到此效果。这就是“硬件设备无关性”,是DirectX真正意义所在。
  这句话换一下几个名词,就成了。应当提供并行硬件抽象层(PHAL/Parallel Hardware Abstraction Layer),硬件制造商按照此标准研发制造更好的并行芯片、并行计算机,并行软件开发者根据这套标准开发并行程序。也就是说,无论硬件是否支持功能,只要PHAL标准中有,程序开发者就可以把它写到程序中,当这个并行程序在硬件上运行,如果此硬件根据PHAL标准把这个功能做到了此硬件驱动程序中,驱动程序驾驭其硬件实行并行计算,用户就可以享受到并行的优势。这就是“硬件设备无关性”,是PHAL真正意义所在。

  当并行计算还是大型计算机的专属时,开发这样的PHAL属于得不偿失,但是当并行计算已经进入桌面,可以为几乎所有的应用程序提供服务的时候。把并行处理交给PHAL,就可以解放并行程序的开发人员,使其将精力集中到应用程序本身的算法,而不是如何并行上。
当图形加速卡刚出现时,是需要应用程序直接操纵硬件来取得加速性能的。而诸如DirectX、OpenGL等图形API接口,也是到了一个开发瓶颈阶段才出现,并逐渐被游戏开发人员所采用。
到DirectX7.0为止,DirectX的工作主要是逐步实现图形卡已有的功能,并提供API以简化开发。而从8.0开始,DirectX已经领先于图形卡的设计,每一个版本的DirectX都对应了新的一代显示核心,标准的定义已经超前于实现。
  目前正是并行计算刚刚进入桌面系统的时代,目前的并行能力都需要应用程序来实现。而PHAL将逐步简化这一过程,并最终成为引领并行计算机结构发展的源动力。

2:并行操作系统、并行编译系统的结合
  DirectX内含的Shader Model提供了对GPU中流处理器的编程控制。在编程中,需要为每一个顶点(Vertex)或象素(Pixel)编制对应的Shader,该Shader负责对这一对象的显示。在最新的DirectX10所定义的Shader Model 4.0中最大指令数从512条增加到了64k条;临时暂存器数量也从原先的32个增加到惊人的4096个;允许同时对128个纹理(Texture)进行操作,对于纹理的尺寸Shader Model4.0也有惊人的提升,8192x8192的最高纹理分辩率比原先最高2048x2048的分辩率要高出4倍。
  从计算机结构的角度讲,上述内容的含义就是:每一个对象有其所对应的线程负责显示,每个活动线程所使用的代码cache为64k;数据cache为64k(每个寄存器存放4维向量,每维32bit);L2 cache由于受到纹理压缩比的影响,不容易计算。这些数以万计的这些线程,在运行时,在GPU内部被硬件调度,实现高度的并行。
  这些参数,既是DirectX技术标准的定义,也是各种支持DirectX10图形处理器的实际配置。
  所以说DirectX决不仅仅是一组API,还提供了并行程序编写语言及其编译器,并同硬件一同实现并行操作系统。

  综上所述,如果能够实现PHAL,那么PHAL也必定是并行编译系统与并行操作系统的结合。只有这样才能编写出“细粒度”的线程,以满足晶核级并行的要求。

四:结束语
  整篇文章主要写了为了提高指令级并行,在未来软硬件所可能的发展方向。
  本来是想把后面的循环级、过程级、子程序级、作业级写个遍的,但是时间有限。
  以一己之力来推断未来并行技术(主要指桌面级计算机的并行技术)的发展,自然谬误不断。但从逻辑上,本文所述的各种技术都合理可行。但是否能够真正实施,需要时间和实践的检验。本人所准备编写的“推箱子的并行算法”正是对这些推断的一点小小证明。
  现在看本文,也许嗤之以鼻;十年后看本文,也许一笑了之。
  下面再写一些本人的武断,要把这些东西全部说清,或许还要十倍的篇幅。

结论:
1:CPU的结构向着类DSM发展
2:核内缓存的数量增加——cache块表过大——成为核内内存——其区别在于,可以由人工直接填写数据,而没有映射。
3:并行科学计算的编程,成为细粒度的多线程编程。PHAL的出现,使线程的分配变的简单。
4:CPU的制造,可以定制,根据不同需求,可以配备不同的特定部件。
5:一个过程从宏观上看,就是一条超长的指令。所以过程级并行是宏观的指令级并行。其主要由刀片机内多PCB板间并行来实现。
6:类DSM结构的CPU组成的机群,是并行计算机发展的方向。
7:并行程序的设计语言必须有全新的关键字来进行定义。对不同内存的读写,有不同的指令。
8:不同级别的并行度,是由不同手段的并行解决方法。

转自:http://ce.sysu.edu.cn/hope2008/Education/ShowArticle.asp?ArticleID=13367