分支预测(Branch Prediction)

 

 在写代码的时候,有时会遇到在循环遍历一个数组时,如果代码块里有做if判断的操作时,我们有个优化的经验,就是先将数组先排序,然后再进行遍历比较操作时,效率会有比较大的提升。

 

一个简单的测试:

 

 

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class Test3 {
  public static final void main( String argc[] ) throws Exception {
    //生成十万个随机数
    List<Integer> randomNumbers = new ArrayList<Integer>();
    Random rnd = new Random();
    for(int i=0; i <= 100000; i++){
      randomNumbers.add(rnd.nextInt(10));
    }
    //未将randomNumbers排序,将randomNumbers大于五万的数放入results1
    List<Integer> results1 = new ArrayList<Integer>();
    long start = System.nanoTime();
    for(int i=0; i <= 100000; i++){
      Integer a = randomNumbers.get(i);
      if(a > 50000){
        results1.add(a);
      }
    }
    long end = System.nanoTime();
    System.out.println(end - start);
    //将randomNumbers排序,将randomNumbers大于五万的数放入results1
    Collections.sort(randomNumbers);
    List<Integer> results2 = new ArrayList<Integer>();
    long start1 = System.nanoTime();
    for(int i=0; i <= 100000; i++){
      Integer a = randomNumbers.get(i);
      if(a > 50000){
        results2.add(a);
      }
    }
    long end1 = System.nanoTime();
    System.out.println(end1 - start1);
  }
}

  

 

运行结果:
1138865
762985

 

那为什么排好序的代码在判断的时候效率会更高呢?原因在于本文的主题:分支预测。


简单来说,就是在做if语句判断时,结果要么是A,要么是B,如果在判断前有个预判,执行A或者B,可以预先做些操作,然后通过判断来确认判断的正确性,如果预判的准确率较高,那么效率提升地就高,而预判一般地基础是之前做地判断结果,所以排序后地判断,能保证这个预判地连续性和正确性,提升了效率。

 

具体来说,这其实是个CPU level的操作,一般的,指令流水线中的第一条指令已进入到译码阶段,而第二条指令已进入到提取阶段(准备进入译码器),如果发现第一条指令是分支指令(如跳转到某个地址),则指令预取队列中下一条及下下条等指令预取无效。这时(确切地说,等到第一条指令执行期间形成了分支的目标地址),需从目标地址中现取指令,并交付执行,同时应立即清除指令预取队列,再将目标地址后面的指令预取过来填到队列中。这表明,一遇到分支指令,整个指令流水线就被打乱一次,稍后才能恢复到正常。显然,这影响了机器的运行速度。为此,在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带来的效益就越高。

 

参考:http://blog.sina.com.cn/s/blog_6c673e570100zfmo.html

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值