首页 > 代码库 > 微处理器之Trace Cache浅析

微处理器之Trace Cache浅析

问题背景是这样的:随着处理器内流水线越来越长,主频越来越高,分支问题带来的性能损失就越来越明显了。根据统计,分支指令占指令总数的10%(静态),15%(动态)。也就是说平均每处理6~7条指令就出现一条条件转移指令。比如流水线的深度为25,当出现条件转移时,整个流水线都需要被刷新,这个性能损失是难以容忍的。尽管可以采用分支预测等手段来减缓条件转移带来的开销,但并不能彻底解决问题。

我们首先来研究一下分支指令的执行速度:

ExecTime = PredictTime + FailRate * FailPenalty

其中,ExecTime是执行分支指令的速度,PredictTime是预测成功情况下,指令的执行速度。FailRate是预测失败的概率,FailPenalty是分支预测失败时恢复流水线所耗费的时间。FailRate的降低主要依靠提升分支预测的准确率,可以通过在程序里添加一些信息告知编译器那个分支的概率更高点,但是想进一步提高就很困难了。Trace Cache的出现可以降低PredictTime和FailPenalty.

对于X86指令集,译码的时间是非常长的。流水线的大部分工作都是在执行译码,如果能把这部分时间去除或者大幅降低将大幅提高指令的执行速度。从这个角度出发,我们再接着考察实际的程序。事实上,处理器在执行程序的时候总是会处理循环的。这是因为现代处理器可以在1秒内轻易处理10GB以上条指令,如果没有循环,那么这一秒内的程序文件将达到10GB以上,而实际上可执行程序的大小通常是10KB~20MB,也就是说程序中的平均每条指令都需要执行1000次~1000,000次。根据这个观察的结果,如果我们能将1次的译码时间分摊在1000条甚至1000,000条指令上将大幅提升指令的执行速度。

Trace Cache正是基于这个理念实现的,如果把一个窗口内的指令集译码完毕后保存到一个缓冲区中,如果下次再需要执行时,直接从这个缓冲区中读取,不再进行译码将有效降低分支指令预测失败带来的开销。这有两个原因:第一个是可以降低FailPenalty。我们可以宏观的将处理器流水线分为两部分:取指译码部分和执行部分。如果分支预测失败,也只需要将执行部分的流水线清空,而不需要将取指译码部分的流水线清空。第二个原因是降低了PredictTime。这是因为如果分支预测成功了,可以直接从Trace Cache中加载译码之后产生的微操作(uOp),相当于消除了条件指令在译码流水线上耗费的时间。考虑到条件指令占总指令数量的15%左右,这个提升还是非常可观的。

Trace Cache还能带来其他的好处:

  • 消除指令预取要求的字节对齐。为了充分利用16字节对齐的指令预取要求,函数和循环的入口地址通常需要按照16字节对齐。而Trace Cache中直接加载微操作,这个要求就不需要了。
  • 可以消除译码配对问题。处理器通常将简单指令和复杂指令在不同的部件上执行,为了在执行微操作时充分实现部件之间的全并行,编译器在优化时需要按照一定的模式对译码后的微操作进行配对。而Trace Cache中直接加载的就是微操作,不需要再进行配对。
Trace Cache虽然有很多优点,但是其最大的缺点就是缓冲区耗费的空间比较大。占用较多的芯片面积,随着集成技术的进步,这个问题将会慢慢有所改观。
参考:http://memcache.drivehq.com/memparam/Bench/Other/TraceCache.htm