再上一篇:并行处理计算机系统与多处理机系统的分类
上一篇:微指令的格式及执行方式
主页
下一篇:计算机系统的分层结构
再下一篇:计算机体系结构的概念
文章列表

流水线的相关问题

流水线只有连续不断地流动,不出现断流,才能获得高效率。如果处理不当,使流水线产生“断流”,就会使流水效率显著下降。流水过程中因为相关问题而产生冲突,是导致流水线断流的主要原因。一般来讲,流水线的相关主要分为以下三种类型。

1. 结构相关

结构相关是指当指令在重叠执行过程中,硬件资源满足不了指令重叠执行的要求,两条或两条以上指令争用同一资源而引起的冲突,因此,结构相关又称为资源相关。

例如,假设一条指令流水线由5段组成,分别为取指令(IF)、指令译码(ID)、取操作数(MEM)、执行运算(EX)和写寄存器(WR)。该流水线的时空图如图8-12所示。

图8-12 5段指令流水线

从图中可以看出,指令I2的取操作数和指令I4的取指令都需要访问存储器。若机器中只有一个单端口存储模块,那么I2的取操作数和指令I4的取指令就产生了访存冲突,两个操作无法同时进行,这就是一种典型的资源冲突。

一种解决这种冲突的方法是在机器中增加存储器模块,如使用双端口存储器,使指令和数据分别存放在不同的存储器模块中,这样,取指令和取操作数就不会发生冲突。另一种方法是,当发生取指令或取操作数冲突时,将其中一个操作的执行时间推迟,如图8-13所示。当然,这样的话也就是发生了流水线的断流,流水线的吞吐率就下降了。

图8-13 访存相关引起流水线断流

2. 数据相关

当一条指令需要用到前面指令的执行结果,而这些指令均在流水线中重叠执行时,就有可能产生数据相关。
在流水计算机中,指令的处理是重叠进行的,前一条指令还没有结束,第二、三条指令就陆续地开始工作。由于多条指令的重叠处理,当后继指令所需的操作数,刚好是前一指令的运算结果时,便发生数据相关冲突。例如,某一时间以下3条指令在图8-12的流水线中执行。
ADD R1, R2, R3 ;(R2)+(R3)→R1
SUB R4, R1, R5 ;(R1)-(R5)→R4
AND R6, R1, R7 ;(R1)∧(R7)→R6
其中,SUB指令的EX段需要执行R1减R5,而同一时间,其上一条指令正在执行写结果到R1的操作。这种情况下,有可能SUB指令的R1并不是ADD指令最终形成的R1结果,则程序的执行将发生错误。

数据相关包括的情况很多,如主存操作数相关、通用寄存器组的数相关及基址值或变址值相关等,它们都属于局部性相关,都是由于在机器同时解释多条指令时出现了对同一主存单元或寄存器要求“先写后读”的冲突而造成的。解决这种相关的一种方法是推后后续指令对相关单元的读,保证在先的指令写入先完成。例如,对于上面的例子,为了保证上述指令序列执行的正确性,流水线只能暂停SUB指令的执行,直到ADD指令将结果写入 R1寄存器后,再启动SUB指令的执行。

另外,任务在流水线中的流动顺序的安排和控制可以有两种方式。一种是任务流入和流出的顺序一致,称为顺序流动方式或同步流动方式;另一种是任务流出和流入的顺序可以不同,称为异步流动方式。
比如,有一个8段的流水线,其中第2段是读段,第7段是写段,如图8-14所示。一串指令h,i,j,k,l,m,n,……依次流入,当指令j的源操作数地址与指令h的目的操作数地址相同时,h和j就发生了“先写后读”的数相关。解决的办法见图8-14,设置“相关直接通路”,让h的结果直接写入j所要访问的存储单元,这样就可以保证j读到的操作数是h写入的结果;此外,当流水线采用异步流动方式时,会出现很多顺序流动不会发生的其他相关。比如,若指令i、k都有写操作且写入同一单元时,可能由于指令i执行时间长或有“先写后读”相关,就会出现指令k先于指令i到达“写”,结果错误地使得该单元的最后内容为指令i的写入结果。这种要求在先的指令先写入,在后的指令才写入的相关为“写—写相关”。此外,当指令i的读操作和指令k的写操作如果是对同一单元,若由于指令k越过指令i向前流,且它的写操作先于指令i的读操作开始前完成,那指令i就会读到错误的数据。这种对同一单元要求在先的指令先读出,在后的指令才写入的相关称之为“先读后写”相关。对于这两类相关,只有异步流动时才可能发生,同步(即顺序)流动是不可能发生的,解决它们的办法就是在控制机构上要保证写入与写入之间、读出与写入之间的先后顺序不变即可。

图8-14 顺序流动和异步流动

3. 控制相关

控制相关冲突是由转移指令引起的。当执行转移指令时,依据转移条件的产生结果,可能为顺序取下条指令;也可能转移到新的目标地址取指令,从而使流水线发生断流。

为了减小转移指令对流水线性能的影响,常见的解决办法如下。

(1)猜测法

顾名思义,猜测法就是当遇见转移指令i时,会形成两个分支,i+1、i+2、……,是转移不成功时继续执行的一路分支,另一路分支是转移成功时转向执行指令p、p+1、……。流水意味着同时解释多条指令,i 进入流水线后,后面到底是执行i+1还是p指令那要等指令i的条件码建立以后才知道,而i的条件码建立一般要等到条件转移指令i快流出流水线时才行,那么在没有建立i的条件码之前,i之后的指令停等下来的话,流水就断流了,性能肯定下降。为了不断流,可采用猜测法猜取i+1和p两个分支中的一个继续向前流动。

可是,猜哪个分支好呢?如果程序中这两个分支被执行的概率相近的话,应首选i+1分支,因为至少它已经取进了指缓里了,可以很快从中取出指令i+1进入流水线而不必等待。反之,因为p可能尚未取进指缓,需花时间访存取出,导致流水断流。如果两个分支被执行的概率不均等的话,当然还是选高概率的分支。那么怎么判断两者谁是高概率的分支呢?一种办法是静态地根据转移指令类型或程序执行期间转移的历史状况来预测,这种静态策略意味着需要事先对大量程序的转移类型和转移概率进行统计,且不一定能保证有较高的猜测准确度。也可以采用动态策略,就是由编译程序根据执行过程中转移的历史记录来动态地预测未来可能的转移选择。

问题是,不管怎么猜选,如果猜对了倒好,可要是猜错了怎么办呢?当然是尽快回到原分支点去转入执行另一分支。就这么简单么?当然不是,因为猜错了意味着分支点原先的现场很可能已被修改了。所以不管怎么猜选,都要能保证猜错时可恢复原先的现场信息。解决的办法是设置后援寄存器,把那些可能被破坏的原始状态信息都用后援寄存器保存起来,一旦猜错就取出后援寄存器的内容来恢复分支点的现场。

(2)加快和提前形成条件码

尽快尽早地获得条件码,就可以提前知道流水线将流向哪个分支。

其一,加快单条指令内部的条件码的形成,尤其是某些反映运算结果的条件码完全可以不必等到指令执行完就可以提前形成。比如,根据运算规律来看,乘、除运算的结果是正是负的条件码就完全可以在运算前形成。

其二,在一段程序内提前形成条件码,比如循环程序,一般是根据循环条件判断是否继续转移。很多循环程序的循环次数虽然是在循环末端语句对循环次数减1,然后再判断循环次数是否为0来决定是否结束循环的。细想一下不难发现,循环次数减1和判断循环次数是否为0的操作,完全可以提前完成,甚至可以提前到循环体开始时就进行。

(3)采用延迟转移

采用延迟转移办法是用软件方法进行静态指令调度的技术,就是在编译生成目标指令程序时,将条件转移指令与它前面不相关的一条或多条指令交换位置,让成功转移总是延迟到在这一条或多条指令执行之后再进行。延迟转移方法因为思路简单,而且不必增加硬件,故比较实用。

(4)加快短循环程序的处理

其一,为避免短循环程序取进了指缓后,由于指令预取导致指缓中需循环执行的指令被冲掉,为减少访存次数,可将短循环程序一次性整个地装入指缓内,以加快短循环程序的处理。
其二,由于循环分支概率高,让循环出口端的条件转移指令恒猜循环分支,就可以降低因为条件分支而造成的流水线断流的机率。