Intel, AMD及VIA CPU的微架构(3)

3.      分支预测(所有处理器)

在现代微处理器中的流水线包含许多步骤,包括指令获取,解码,寄存器分配及重命名,μop重排,执行及回收。以流水线方式处理指令允许微处理器在同时做许多事情。在执行一条指令的同时,在获取及解码下一条指令。使用流水线的最大问题是代码中的分支。例如,一条条件跳转允许指令流进入两个方向中的任一个。如果仅有一条流水线,那么微处理器不知道向流水线填入两个分支中的哪个,直到分支指令被执行。如果微处理器不知道哪个分支填入流水线,流水线越长,微处理器浪费的时间越多。

微处理器通过将更可能的分支填入流水线,并推测性地(speculatively)执行之,尝试克服这个问题。推测执行意味着指令被解码且执行。但结果不会被回收到永久寄存器堆(registerfile),内存写被挂起,直到分支指令最终被决定。如果结果是猜错了,推测性地执行了错误的分支,那么流水线被冲刷,推测执行的结果被丢弃,另一个分支被获取到流水线。这称为分支误预测,其结果是浪费了几个时钟周期。浪费的时钟周期数大约等于流水线的长度。

为预测将进入哪一路分支,以尽量减少分支误预测的频率,设计师们不断发明越来越复杂的机制。分支行为的历史被保存下来,以预测将来的行为。这个预测有两方面:预测一个条件将被采用,以及预测一个有条件或无条件跳转去到的地址。一个称为分支目标缓冲(BranchTarget Buffer,BTB)的缓存保存所有跳转的目标地址。在第一次执行无条件跳转及条件跳转第一次被采用时,目标地址被保存在BTB中。在相同的跳转第二次执行时,BTB里的目标地址用来将预测目标放入流水线,尽管真实目标直到跳转到达执行阶段才计算出来。对无条件跳转,预测的目标很可能是正确的,但不确定,因为BTB可能没有大到能包含程序中所有的跳转,因此在BTB中不同的跳转可能共享同一项。误预测的风险远高于条件跳转。

3.1.      条件跳转的预测方法

在遭遇一个条件跳转时,微处理器不仅需要预测目标地址,还要预测该条件跳转是否被采用。如果猜测正确,且正确的目标被载入,那么流水线流进展平滑且快速。但如果预测错误,微处理器已经将错误的目标载入流水线,那么必须冲刷流水线,已经花费在错误分支的指令获取、解码以及可能的推测执行的时间被浪费。

饱和计数器(Saturatingcounter)


一个相对简单的方法是在BTB中保存过去执行最频繁分支的信息。这可以通过一个饱和计数器实现,如图3.1的状态机所示。

图3.1. 饱和的2比特计数器

这个计数器有四个状态。每次采用该分支时,计数器进到下一个状态,除非它已经是最高状态。每次没有采用该分支时,计数器进入上一个状态,除非它已经是最低状态。当计数器是最高两个状态之一时,它预测下一次将采用该分支。当计数器是最低两个状态之一时,它预测下一次将不采用该分支。如果该分支连续几次都没被采用,那么该计数器将在最低状态,称为“强不采用”。要预测变为采用,该分支必须被采用两次。类似的,如果该分支连续几次都被采用,它将在状态“强采用”。要预测变为不采用,该分支必须不被采用两次。换而言之,在预测改变前,该分支必须偏离其过去最常见行为两次。

对在大多数时间行为相同的分支,这是个好方法,但对经常改变的分支,这就不好了。P1使用这个方法,尽管有缺陷,正如11页所解释。

带有局部历史表的两层自适应预测器(Two-leveladaptive predictor with local history tables)

考虑对一个每两次采用一次的分支,图3.1中计数器的行为。如果它以“强不采用”状态开始,那么计数器将在“强不采用”与“弱不采用”状态交替。预测将总是“不采用”,这将仅有50%时间正确。类似的,如果以“强采用”状态开始,将预测总是“采用”。最糟的情形是恰好以“弱采用”状态开始,并在“弱不采用”及“弱采用”状态间交替。在这个情形里,分支总是被误预测。

提高具有这样一个规则重复模式分支预测率的一个方法是,记住该分支最后n次的历史,并对每2n个历史模式采用饱和计数器。这个方法,由T.-Y. Yeh与Y.N. Patt发明,显示在图3.2。


图3.2.自适应双层预测器

考虑n = 2的例子。这意味着该分支的最后两次出现保存在2比特移位寄存器中。这个分支历史寄存器可以有4个不同的值:00,01, 10及11;其中0表示“不采用”,1表示“采用”。现在,我们做一个有4项的模式历史表,每个对应合理的分支历史。在模式历史表中。每项包含一个与图3.1中相同的2比特饱和计数器。分支历史寄存器用于选择使用哪个饱和计数器。如果历史是00,那么使用第一个计数器。如果历史是11,那么使用最后一个计数器。

在分支被交替采用及不采用的情形里,分支历史寄存器将总是包含01或10。当历史是01时,我们将使用,在模式历史表中,具有二进制数01B的计数器。这个计数器将很快获悉,在01之后会来一个0。类似的,10B计数器将知道10之后会来一个1。在一小段时间学习后,预测器将做出100%正确的预测。在这个情形里,计数器00B与11B将不会使用。

交替采用两次及不采用两次的分支也可以通过这个预测器100%地预测。这个重复模式是0011-0011-0011。在模式历史表中计数器00B将知道00后会来一个1。计数器01B将知道01后会来一个1。计数器10B将知道10后会来一个0。而计数器11B将知道11后会来一个0。但重复模式0001-0001-0001将不能总是正确地预测,因为00可以跟随一个0或一个1。

图3.2中的机制称为双层自适应预测器。具有n比特分支历史寄存器的双层自适应预测器的通用规则如下:

任何具有n+1或更短的周期的重复模式,都可以在一段不超过3个周期的预热时间后,被完美预测。具有超过n+1且不超过2n周期的重复模式,如果所有p个n比特子序列都不相同,可以被完美预测。

为了展示这个规则,考虑上例中的重复模式0011-0011-0011。2比特子序列是00,01, 11, 10。因为它们都不相同,它们将使用n = 2双层预测器的模式历史表中不同的计数器。n = 4,我们可以预测周期为6的重复模式000011-000011-000011,因为6个4比特子序列:0000,0001, 0011, 0110, 1100, 1000,都是不同的。但模式000001-000001-000001,也具有周期6,不能被完美预测,因为子序列0000可以后跟一个0或一个1。

PMMX,Ppro,P2与P3都使用n = 4的双层自适应预测器。这对每个分支要求36比特储存:模式历史表中16个计数器每个2比特,用于分支历史寄存器的4比特。

在完全随机、无规率的序列情形下,模式识别的强大能力有一个小缺点。下表列出了完全随机采用或不采用序列的实验性的误预测比例:

采用/不采用比例

误预测比例

0.001/0.999

0.001001

0.01/0.99

0.0101

0.05/0.95

0.0525

0.10/0.90

0.110

0.15/0.85

0.171

0.20/0.80

0.235

0.25/0.75

0.300

0.30/0.70

0.362

0.35/0.65

0.417

0.40/0.60

0.462

0.45/0.55

0.490

0.50/0.50

0.500

表3.1. 误预测随机分支的几率

误预测比例比没有模式识别稍高,因为处理器持续尝试在一个没有规律的序列里找出重复的模式。表3.1的值也适用于下面描述的,带有全局历史表的预测器,以及约定(agree)预测器。

带有全局历史表的双层自适应预测器

因为双层预测器的储存随历史比特数n指数级增长,我们可以使用的n存在现实的局限。克服这个局限的一个方式是在所有分支间共享历史寄存器及模式历史表,而不是每个分支一套。

想象一个带有保存最后n个分支历史的全局分支历史寄存器,及一个共享模式历史表的双层预测器。分支的预测在最后n个分支事件基础上进行。这些事件的一些或所有可能发生在相同的分支上。如果程序中最里层循环包含m个条件跳转,那么这个循环内一个分支的预测依赖于分支历史寄存器中相同分支的出现次数floor(n/m),而余下项来自其他分支。如果这足以定义这个分支的模式,或者如果它与其他分支高度相关,那么我们可以预期良好的预测率。许多现代处理器使用这个方法n值从8到16的各种变种。

约定预测器(Theagree predicator)

使用全局表的缺点是,在全局模式历史表中,行为迥异的分支可能共享相同的项。可以通过对每个分支保存一个偏移比特(biasingbit)来减轻这个问题。偏移比特表示该分支是否多半会采用,还是不采用。现在,模式历史表中的预测器不再表示分支是否预测被采用或不采用,而是预测它是否与偏移比特同向,还是反向。预测更可能与偏移比特一致,恰好使用模式历史表中相同项的分支间负面影响的可能性降低,但没有消除。我的研究表明P4使用了这个方法的一个版本,如图3.3所示。

图3.3.约定预测器

每个分支有一个局部预测器,它只是一个图3.1所示的饱和计数器。全局模式历史表,由全局分支历史寄存器索引,表示该分支是否被预测为与局部预测器的输出一致。

在P4中全局分支历史寄存器有16比特。显然,因为216各异历史模式中的一些要比其他常见得多,如果模式历史表仅由分支历史索引,我们会有模式历史表中某些项将被几个分支使用,而许多其他项将完全不使用的问题。为了使这些项的使用更为均匀,减少两个分支使用相同项的可能性,模式历史表可由全局历史及分支地址的一个组合索引。文献建议模式历史表的索引由历史比特及分支地址的一个XOR产生。不过,我的实验结果没有证实这样的设计。图3.3中的索引函数可能是历史比特与分支地址一个复杂得多的哈希函数,或者它可能涉及分支目标地址,BTB项地址或追踪缓存地址。

因为索引函数未知,无法预测两个分支是否将使用模式历史表中相同的项。出于相同的原因,我无法测量模式历史表的大小,只能依靠文献中的传说。

(文献:E.Sprangle, et. al.: The Agree Predictor: A Mechanism for Reducing NegativeBranch History Interference. Proceedings of the 24th International Symposium onComputer Architecture, Denver, June 1997. J. Stokes: The Pentium 4 and the G4e:an Architectural Comparison: Part I. arstechnica.com,Mar. 2001)。

循环计数器

控制一个循环的分支通常朝一个方向前进n-1次,然后在另一个方向前进一次,其中n是周期。例如,循环for(i=0; i<6; i++)将产生分支模式000001-000001或111110-111110,依赖于分支指令是在循环的顶部还是底部。具有大周期,且循环体内有几个分支的循环,在一个双层预测器中要做出好的预测,将要求一个很长的历史表,以及有许多项的模式历史表。这个问题最好的解决方法是对循环使用别的,称为循环计数器或开关(switch)计数器的预测方法。在第一次执行该循环时,一个计数器统计周期n,重复次数与n比较,当次数等于周期时,预测循环退出。对一个循环计数器,必须保存在BTB中的信息包括:该分支是否有循环行为,在循环退出时是否采用该分支,周期,当前重复次数,以及分支目标。

PM与Core2有一个6比特循环计数器,可以完美预测最大64周期的循环。

(文献:USPatent 5909573)。

间接跳转预测

间接跳转或调用是一个具有两个以上可能目标的控制转移指令。C++程序可以使用switch语句、函数指针或virtual函数产生一个间接跳转或调用。在汇编里,通过将一个寄存器或内存变量或一个索引数组声明为一条跳转或调用指令的目标,生成一个间接跳转或调用。更旧的处理器仅能将一个BTB项用于间接跳转或调用。这意味着它将总是被预测去到与上次相同的目标。

随着带有多态类的面向对象编程越来越普遍,预测带有多个目标的间接调用的需要持续增长。这可以通过将一个新BTB项分配给新遇到的跳转目标来实现。对每个跳转事件,历史缓冲与模式历史表必须有多于1比特的空间,以区分两个可能的目标。

PM是第一个实现这个方法的x86处理器。第7页的预测规则修改为:“理论可以完美预测的最大周期是mn,其中m是每个间接跳转的不同目标数,因为存在mn个可能的、长度为n的子序列”,仍然适用。不过,这个理论最大不可能到达,如果它超出BTB或模式历史表的大小。

(文献:KarelDriesen and Urs Hölzle: Accurate Indirect Branch Prediction. Technical ReportTRCS97-19, 1998. Department of Computer Science, University of California)。

子例程返回预测

子例程返回是一个回到该子例程被调用处的间接跳转。子例程返回的预测在第28页描述。

混合预测器

一个混合预测器是多个分支预测机制的实现。一个元预测器预测哪个预测机制会给出最好的预测。元预测器可以简单如一个两比特饱和计数器,记住对一个特定的分支指令,过去工作得最好的两个预测方案。

PM使用一个由一个带有长度为8的全局历史表的双层自适应预测器,结合一个循环计数器组成的混合预测器。

将来的分支预测方法

随着流水线变得更长,在将来分支预测方法将进一步改进。根据技术文献与专利文献,可能是以下发展:

·        混合预测器。在将来,带有一个循环计数器与一个双层预测器的混合预测器可能实现在更多的处理器中。

·        融合(alloyed)预测器。可以通过使用局部与全局历史比特的一个组合作为模式历史表的索引,改进双层预测器。这消除了约定预测器的必要性,改进了与任何前导分支无关的分支的预测。

·        将不重要的分支排除在全局历史寄存器外。在典型的程序中,很多一部分分支总是朝着同一个方向前进。这样的分支可以排除在全局历史寄存器外,以增加其信息量。

·        解码两个分支。流水线的部分或全部是双倍的,因此两个分支可以同时解码及推测执行。只要可能,或在预测不确定时,可以解码这两个分支。

·        神经网络。双层预测器的储存要求随着n指数级增长,并且预热时间也可能随n指数级增加。这限制了双层预测器可以实现的性能。可能会实现其他具有更少储存要求的方法。这样新的方法可能使用神经网络原理。

·        减少上下文切换的影响。预测器收集的信息通常因为任务切换及其他上下文切换而丢失。随着,更先进的预测方法要求更长的预热时间,很可能将实现新的方法来减少上下文全局期间的损失。


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值