计算机组成
7 流水线处理器
7.2 流水线的优化
相对于单周期处理器,流水线技术可以提升处理器的性能,但是,如果仅仅按照指令执行的步骤去切分流水线的话,不能够充分利用流水线这项技术的优势。那如何才能挖掘流水线技术的更多潜力呢?我们在这一节就来探讨这个问题。
我们还是用这个厨房做菜的例子来对流水线进行分析。现在我们将做菜的工作分为四步,每一步都需要一分钟。如果不采用流水线的方式,做一道菜需要四分钟,而采用流水线的方式,则需要4分钟多一些的时间。因为每一个阶段之间的交接还需要额外花一些时间。对应于流水线处理器,就是各流水级之间的流水线寄存器所需要的延迟。不过总体来说,这两种方式所用的时间还是大致相等的。而如果做多道菜,流水线方式的优势就会逐渐体现出来,而且在流水线充满的情况下,可以做到每一分钟上一道菜。而非流水线的方式,只能做到每4分钟上一道菜。这样我们就会发现,如果我们划分为4级的流水线,我们可以将性能提升为原来的4倍。
不过刚才这个情况非常的理想化,其实我们很难做到每一个阶段恰好花同样的时间。那我们不妨假设切菜这个环节非常复杂,需要花2分钟的时间,而其他每个环节仍然只花一分钟,那我们现在应该让这个吹号手隔多长时间吹一次号呢?显然他应该每两分钟才吹一次号。因为我们这个流水线的时钟周期必须按照各流水级当中时间最长的那一级来确定,不然如果还按照1分钟吹一次号,那上一道菜还没有切完,下一道菜就已经洗完了,并送到了切菜环节,那就把刚才还没有切完的菜给冲掉了,这样显然是不可以的。 所以,我们只能2分钟吹一号,这样只有切菜这个环节是饱满的工作,其他环节都是干一分钟歇一分钟。那我作为这个餐馆的老板,显然是无法接受这样的状况的。这个问题就出在了流水线的平衡性上。最终每个阶段花费时间不相等的流水线就被称为不平衡的流水线。那么对于这条流水线,我们发现,虽然他还可以做到每两分钟出一道菜,但是性能提升幅度就变小了很多,而且从单独做一道菜看来,非流水线方式只需要5分钟,而用流水线方式,反而需要8分多钟,这样就慢了很多。因此,如果是对于流水线处理器来说,不平衡的流水线对于整体的指令吞吐率,和单独一条指令执行时间,都有非常不好的影响。因此,在划分流水线的时候,应当做到每一级所花费的时间尽可能相等,这就有可能造成这级流水线的名称和它实际所完成的工作并不完全相符。比如说我们要求洗菜这个环节,就稍微多花一点时间把菜叶子先给撕碎了,这样切菜就可以少花一点时间。当然这只是一种方式,针对这个例子我们还可以考虑另一种方法。
那就是把切菜这个环节分为两步,既然他需要花2分钟的时间,那我们不如把它分为2个一分钟的环节。这样和其他环节的时间就变成一样的了,我们就可以设置其中周期为1分钟,每过一分钟,各个环节就把手中的成果送到下一个环节去。但我们要注意的是,这样的切分,并不是说要增加新的硬件资源,而应该是把原有的硬件资源切分成两个部分来使用。我们就还是说切菜,假设我们原来是要做土豆丝,那在切菜的时候,先用一把小刀完成削皮的工作,再用一把大刀完成切丝的工作,这样一共花了2分钟的时间。后来我们经过分析发现,削皮大概正好用一分钟,切丝也需要用一分钟,那我们就把它切分成两步,把削皮用的小刀放在第一步,切丝用的大刀放在第二步。这样我们并不需要购买新的工具,而只是把原有的工具分隔开来。那么这个调整后的流水线就变成了一个平衡的流水线。
对于这个流水线,我们发现,它单独做一道菜的时间已经降回到了5分钟,和非流水线的方式基本相当,更重要的是,在连续工作的情况下,它又可以做到每一分钟上一道菜。而非流水线的方式,只能是每5分钟上一道菜。因此,采用流水线的方式,性能可以是原来的5倍,如果我们切分4级流水线,那我们可以做到性能提升为原来的4倍。而切分5级流水,就可以把性能提升到5倍,那就着这个思路想下去,我们继续进行切分,是不是可以得到更高的性能呢?简单来看,这样是对的。这个技术就被称为“超级流水线”。
当然,这个技术并不没有它这个名字看起来那么神奇。实际上,我们是将五级流水线作为一个基本的流水线划分,如果在五级流水线的基础上,将其中一些流水级细分为更多的阶段,从而增加了流水线的深度。这样的流水线就会被称为超级流水线。
那么超级流水线就可以做到更高的时钟频率,从而提高了指令的吞吐率。比如这是基础的五级流水线,其中每个流水级的组合电路的延迟大约为200ps,而流水线寄存器的延迟为50ps,那这个流水线处理器的时钟周期就是250ps。而如果我们做一个十级的流水线,而且恰好能将这个五级流水线当中的每一级平均地切为两段,那这个处理器的时钟周期就是100ps,加上流水线寄存器的50ps,一共是150ps。那显然使用这样的超级流水线技术可以带来明显的性能提升,但是流水线的级数是越多越好吗?
我们还是要来深入地分析一下。对于五级流水线来说,其执行单条指令的延迟是1250ps,而对于这个十级流水线,它执行单条指令的延迟就变成了1500ps。因此,我们切分流水线之后,提高了时钟的频率,从而也提高了指令的吞吐率,但是单条指令的执行时间确实变长了的。这是因为我们增加了更多的流水线寄存器,在五级流水线当中,流水线寄存器的延迟大约占20%的比例。而在十级流水线当中,因为每级的组合逻辑电路的延迟减半了,但是流水线寄存器的延迟是不会发生变化的。因此,流水线级数划分的越多,流水线寄存器的延迟所占的比例就会越高,从而导致单条指令的延迟越来越大。而且不仅如此,当流水线级数变多之后,填满一个流水线所需要的指令就会变多,而这些同时处在流水线当中的指令,他们之间的关系也就会变得更加复杂,从而会带来更多的负面影响,这些负面的影响我们在后面还会进行深入的分析。但我们的结论是很明确的,流水线的级数显然不是越多越好。
那我们再来看看现实中的情况。比如说93年的奔腾处理器,它就采用了五级的流水线,而MIPS则是在更早就实现了流水线处理器,包括有五级的,和后来的八级的。因为MIPS在设计之初就充分考虑了用流水线进行实现,所以它很容易通过流水线以及超级流水线的技术获得性能上的提升。而X86指令系统在设计的时候,并没有考虑这一点,而且由于它自身比MIPS复杂得多,也很难进行流水线的切分。因此,在80年代到90年代初,以MIPS为代表的RISK处理器性能提升很快,对X86处理器构成了巨大的威胁。不过后来英特尔在非常困难的情况下,找到了一个应对的方法。
这个方法从95年的奔腾Pro开始实现。奔腾Pro是一个12级流水线的处理器,也有一些划分方法认为它是14级的。它的核心要点在于,在处理器内部,用硬件将复杂的X86指令切分成简单的RISK指令。从而可以运用这些先进的RISK处理器的技术,又保证了兼容之前用X86指令编写的软件。那么经过几番争斗之后,作为CISK代表的X86还是战胜了来势凶猛的RISK处理器厂商,虽然它用的也正是RISK的技术。
而现在作为RISK代表的ARM,在那时还并没有多大的影响力,至少在计算机的领域是这样的。这是97年的ARM9,采用了五级流水线的形式,这个流水线的划分和MIPS基本上是一样的。后来到02年,ARM推出了8级流水线的ARM11,这处理器凭借它低功耗的优势,在嵌入式领域获得了广泛的应用。但是由于其性能的不足,还是难以进入个人计算机的市场。
那么在这个阶段,英特尔在战胜了众多RISK厂商之后,又和AMD等厂商开始了X86体系结构内部的斗争。那么在这个时期,处理器的流水线级数变得越来越多。从10多级变到20多级,直到04年的奔腾4达到了顶峰,共有31级。 我们刚才已经分析过,流水线的级数并不是越多越好,过深的流水线反而会降低性能。那英特尔显然不会不知道这一点,但他为什么还要这么做呢?其中一个重要的原因就是流水线加深之后,可以带来的一个很明显的变化—时钟频率的提升。虽然我们现在知道了频率高不代表性能好,但其实很多普通的消费者并不清楚这一点,而且在那几年,英特尔和AMD等厂商,在广告中都是以处理器的频率作为主打的性能指标。这就造成了那时消费者购买计算机时,都只问“你这个计算机频率是多少?”,结果这就变成了这家出一个2G的,过几天那一家就出个2.5G的,那你出个2.5G的,再过几天,我就出个3G的。谁的频率高,来买的人就多。这就是那几年非常著名的CPU频率大战,这也带动了那时主流处理器的流水线深度变得越来越深。当然这样的事情是不能一直做下去的,它总归有一个限度,所以到后来频率大战打不下去之后,流水线的深度也就逐渐地回落了。比如06年 的Core 2是14级,08年的Core i7是16级。而到现在,13年的Core i7在正常工作情况下,也是14级。那这是桌面处理器的主要情况。
而随着乔布斯推出的iphone和ipad引爆了另外一个市场,我们也来看一看它的流水线深度。比如09年的Cortx-A8,这是ARM11后一代的处理器,它有13级流水线。而10年的Cortex-A9,则是11级的流水线。我们可以看到它的流水线级数不升反降。而11年的Cortex-A15,则是15级流水线,到13年的Cortex-A57,也仍然保持了这个数目。而A9,A15和A57,这些处理器,或者是与它们同架构的 一些别的处理器,广泛应用于中高端的智能手机和平板电脑。所以,从这里也可以看出,现在的主流处理器,其流水线深度基本维持在15级左右。
现在我们已经了解到,通过增加流水线的深度,可以有效地提高时钟的频率,从而提升指令的吞吐率。不过这个方法也有很大的限制,现在我们已经很难通过继续增加流水线的深度来获得性能上的提升了。那如果我们想继续挖掘流水线处理器的潜力,就还得寻找其他的优化方案。