关于机器指令和微指令

最近在看《深入理解计算机系统》,真的很不错,让我对CPU又有了更深的了解。


我们都知道,实际上我们用高级语言编写的程序,被编译成可执行程序,存放可执行程序的文件实际就是一些机器码,可以被硬件执行。在这一步,我们称其为机器指令(Machine Instruction),而到了这一步,往往也就以为自己到达了所谓的“底层”。


前一段时间,我还在论坛提过一个疑问,就是Intel编译器编译出的代码是针对Intel处理器优化的,在AMD处理器上执行效率一般,为什么会出现这个情况?因为机器指令序列都是一样的,每个机器指令按照硬件厂商给的参数,周期数(clock cycle)应该也差别不大啊。


现在我想,我可以尝试来解答这个问题了。在我们看来,每一步机器指令都是一个原子操作,但是硬件为了追求更高的吞吐率(through output),将这些指令又细分成一个个独立的阶段,称之为微指令(micro-operation,μ-op),这些微指令可以在一个流水线(pipeline)的不同阶段中顺序执行执行,当流水线头部空了,就可以执行下一个机器指令的微指令。这样“同时”执行的机器指令就很多,从而增加了吞吐率。


当然一味增加流水线的阶段也是不行的,因为从一个阶段到另一阶段有时间延迟(latency),并且这些阶段公用时钟信号,所以要用执行时间最长的阶段所需时间作为公共时钟,并且很多操作无法切割成太多的微指令。下图是奔4处理器的流水线示意图:




所以,我之前的概念,mov reg reg这样的操作只需要耗费1个clock,这是错误的,正确的说法是这个操作的均摊时间是1个clock,它必须走完流水线所有的步骤,而流水线的每个步骤至少是1个clock的。一条机器指令的执行,包括取值、译码、计算、访存、更新PC等很多步骤,而微指令可以看成是译码以后的结果,它还可以缓存在buffer上,从而下次遇到相同的指令,减少译码时间。


还有一个问题就是相邻的机器指令之间如果有依赖,上一个指令还没在流水线出来,下一个就进去了,这样下一个可能用了错误的值,这个问题可以用转发(bypass)上个流水线的中间值给下个流水线,或暂停(stall)来解决,但是stall是不合理的,因为这样使得流水线的一部分处于停滞状态,而还有一个方法,就是乱序执行(out of order),将后面没有依赖关系的指令提到前面来,尽量使流水线填充满。


所以,可以想象,Intel和AMD的微指令层面,流水线肯定是非常不一样的。那么如何安排机器指令顺序(当然执行时CPU会判断能否乱序,但是这时已经是后期,如果编译器能更多的去除依赖当然就更好了),以及如何利用寄存器(有时同样的功能也可以用不同的机器码来实现)等等。所以Intel的编译器能够针对自家的CPU给出更高效的编译结果。


例如:AMD文档给编译器开发者的一条建议是,当跳转后面紧跟ret指令时,最好插入一个rep,从而在不引入错误的前提下,提高CPU效率。

......
je  .L33
rep
ret


扩展阅读:

CPU流水线的探秘之旅 (这是翻译后的版本,英文原版地址:A Journey Through the CPU Pipeline



参考文档

《深入理解计算机系统》

http://en.wikipedia.org/wiki/Pipeline_(computing)

http://en.wikipedia.org/wiki/Micro-operation




  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值