分支指令预测技术
1.分支指令预测
在程序中一般都包含有分支转移指令,据统计,平均每七条指令中就有一条是分支转移指令.在指令流水线结构中,对于分支转移指令相当敏感。假设在80486 的指令流水线中的第一条指令已进入到译码阶段,而第二条指令已进入到提取阶段(准备进入译码器),如果发现第一条指令是分支指令(如跳转到某个地址),则指令预取队列中下一条及下下条等指令预取无效。这时(确切地说,等到第一条指令执行期间形成了分支的目标地址),需从目标地址中现取指令,并交付执行,同时应立即清除指令预取队列,再将目标地址后面的指令预取过来填到队列中。这表明,一遇到分支指令,整个指令流水线就被打乱一次,稍后才能恢复到正常。显然,这影响了机器的运行速度。为此,在Pentium处理器中使用了分支目标缓冲器(Branch Target Buffer,BTB)来预测分支指令。
BTB实际是一个能存若干(通常为256或512)条目的地址存储部件。当一条分支指令导致程序分支时,BTB就记下这条指令的目标地址,并用这条信息预测这一指令再次引起分支时的路径,预先从该处预取。下面看一下BTB在循环程序中应用。循环程序在程序设计中使用得十分普遍。在指令级目标程序中构成循环程序需要用转移指令(条件转移指令或无条件转移指令)。看下例:
MOV CX.100
LOOP: ……
……
DEC CX
JNZ LOOP
……
在第一次执行到JNZ指令时,预测的转移地址是存在BTB中的前面一条JNZ指令的目标地址,不是LOOP,这一次预测是错误的。但执行后目标地址 LOOP便存入到BTB中。等到下一次执行到JNZ指令,就按BTB中的内容来预测,转移到LOOP,这是正确的。如此,一直到cx的值变为0之前,也都是对的。当再循环一次CX的值变为0时,JNZ指令因条件不成立而不实行转移,而预测仍是LOOP,预取仍按该预测进行,这是第二次预取错误。可见,该例中100次循环,有98次预测,确切地说,有98次预测指导下的预取是正确的。同理,对于1000次循环,就会有998次的预取是正确的。即循环次数越多,BTB带来的效益就越高。
图8.1所示是Pentium处理器的分支预测机制示意图。指令预取器从位于CPU内
部的L1指令Cache中预取指令(一般情况,从中可以取到,如果其中没有则访问位于主板上的L2 Cache,若再没有则访问主存储器),指令预取队列中的指令按照管道方式(即先进先出)依次进入指令译码器,当译码时发现是一条分支指令,则检查BTB 中有无该种分支指令的记录,若有,则立即按照所记录的目标地址进行预取(目标地址对应的指令及其后面的指令),替代原先已进入指令预取队列中的指令。在这条指令执行完毕前夕,将该指令的实际目标地址再添入BTB中(当然,在预测正确时,目标地址不会变),以使BTB中总保持最近遇到的分支指令及其目标地址。
细心的读者可能会发现,这似乎和上面提到的没有分支预测的80486差不多。应该指出,Pentium的分支预测确实是晚了一些,但毕竟作了预测,并根据预测的结果进行了预取。说它进行了预测和预取,是因为这些是在译码后立即做的,从80386开始指令部件中设置了已译码指令队列(参看第七章的图 7.1),指令从译码到执行还有一段时间。此外,对条件分支指令判断条件是否成立以及分支目标地址的形成也需要时间,而这些是在指令执行时进行的。说它预测晚了一些,是因为总是希望预测在译码之前,即在指令预取的过程中进行预测。实际上,这就是在第六代微处理器中得以实现的动态分支预测。
2.推测执行与动态分支预测
推测执行技术又称预测执行技术。它的基本思想是:在取指阶段,在局部范围内预先判断下一条待取指令最有可能的位置,即在取指部件就具有部分执行功能,以便取指的分支预测,保证取指部件所取的指令是按照指令代码的执行顺序取入,而不是完全按照程序指令在存储器中的存放顺序取入。
动态分支预测是推测执行的一种具体做法,它是相对静态分支预测而言的。静态分支预测在指令到了译码器,进行译码时,利用BTB中目标地址信息预测分支指令的目标地址(如Pentium处理器那样);而动态分支预测的预测发生在译码之前,即对指令缓冲器(与8086、80386的指令预取队列基本相同,但有区别。)中尚未进入译码器中的那部分标明每条指令的起始和结尾,并根据BTB中的信息进行预测,这样发现分支指令要早。因此,对动态分支预测,一旦预测有误,已进入到流水线中需要清除的指令比静态分支预测时要少,从而提高了CPU的运行效率。
Everest的测试项目:
CPU Queen是测试CPU的分支预测能力,以及预测错误时所造成的效能影响。
CPU PhotoWorxx著重於CPU的整数运算能力,利用模拟数位影像处理来进行CPU效能的评估
CPU ZLib是另一项针对CPU整数运算的测试,利用Zlib这个压缩函式库,来计算CPU在处理压缩档案时的能力。
FPU Julia是利用朱利亚碎形几何运算,来评估CPU的单精度(32bit)浮点运算能力。
FPU Mandel则利用了"Mandelbrot″碎形几何运算,来评估CPU的倍精度(64bit)运算能力。
FPU SinJulia则是利用修改过的朱利亚碎形运算,来评估CPU的延伸精度(80bit)浮点运算能力。