什么是“CPU乱序执行”
我们知道现在CPU在执行指令是并不是按照指令顺序执行的(除非使用了特殊如原子操作指令等),以提高执行效率。我们将其称之为乱序执行(Out-of-orderExecution)。下面我们来聊一聊这是怎么回事。
实际上早在1964年,CDC6600就使用乱序执行来解决计分板冲突问题。1967年在IBM工作的计算机科学家托马苏洛(RobertTomasulo)发明了托马苏洛算法用来改善处理器乱序指令级并行效率。第一个采用乱序执行的CPU是IBM的POWER1.随后Intel在x86体系中的PentiumPro中也采用了乱序执行的技术。从此以后,乱序执行就成了CPU提升效率的基础技术之一。
为什么要采用乱序执行呢?顺序执行不好吗?我们知道,CPU为了提升效率都采用了pipe-line流水线技术。将一个执行过程分为如:取指(IF),译码(ID),执行(EX),访存(MEM),写回(WB)等。如下图所示是一个标准的5级流水(实际CPU流水远不止5级)的示意图。
指令流水
上图中展示的指令流水的每个阶段都是完美的,然而实际情况往往并非如此。尤其是在遇到条件分支,跳转等指令时,上图中的流水可能会被打断,而导致该指令之前的流水被清空,而浪费CPU时钟周期从而影响了效率。尽管CPU采用了分支预测技术,但仍然无法彻底解决该问题。看下面的例子:
ldr1,0(r2)//从r2代表的内存中加载数据到r1寄存器
addr2,r1,r3//计算r2=r1+r3
addr4,r3,r5//计算r4=r3+r5
我们假设r3和r5的值已经在寄存器文件当中准备好了,另外假设执行第一条加载指令时CPU在L1缓存中未命中数据,而不得花大约20个时钟周期不到L2缓存中读取。在这段时间CPU的数据加载单元一直在忙碌,但是指令流水线却停止了,因为第二条指令需要依赖r1的值。但是注意第三条指令,前面我们说r3和r5的值是准备好的,因此它完全可以执行,但是无奈的是流水线已经停止了。第三条指令不得不等待加载指令的完成。
而乱序执行(Out-of-order)或者动态调度(dynamicscheduling)就是一种来解决上文描述的CPU带宽浪费的技术。在乱序执行时,处理器按照指令顺序发射(Issue)每一条指令到一个新的被称作”读操作”的流水线阶段,不管这些指令在程序中的顺序是怎么的,每一个操作都会被移入执行(execution)阶段。下面我们具体对比一下顺序执行(In-Order)和乱序执行(Out-of-Order)的执行流程有何不同:
顺序执行(In-Order):
指令顺序指令
处理器从内存中取出指令
如果输入的指令操作可以被执行,那么指令就被送往执行单元
如何输入操作当前不可以被执行,处理器会等待,直到满足可以被执行的条件(比如等待从内存中取出待操作数据),然后指令被送往执行单元
指令在相应的执行单元被执行。
指令执行后,它被写回寄存器。
乱序执行(Out-of-Order):
乱序执行流
处理器从内存中读取指令
译码后指令将被发送到指令缓存区也叫保留站
在指令缓存区的可被执行的指令(所有条件具备的指令),会被发送到相应执行单元执行。(上图中使用了不同的形状来表示不同的执行单元)
执行的结果会被发到结果重排区进行重排,以使其保持原有指令顺序。
如果所有之前执行的结果已经被写回,那么将当前执行结果写回寄存器文件。
乱序执行避免了因各种因素导致的指令流水线停滞,而提升效率。本文简单地介绍了乱序执行的概念和执行流程。抛砖引玉,供大家参考。