乱序执行 (out-of-order execution)

乱序执行(out-of-order execution)是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理的技术。比方Core乱序执行引擎说程序某一段有7条指令,此时CPU将根据各单元电路的空闲状态和各指令能否提前执行的具体情况分析后,将能提前执行的指令立即发送给相应电路执行。

这好比请A、B、C三个名人为晚会题写横幅“春节联欢晚会”六个大字,每人各写两个字。如果这时在一张大纸上按顺序由A写好"春节"后再交给B写"联欢",然后再由C写"晚会",那么这样在A写的时候,B和C必须等待,而在B写的时候C仍然要等待而A已经没事了。但如果采用三个人分别用三张纸同时写的做法, 那么B和C都不必须等待就可以同时各写各的了,甚至C和B还可以比A先写好也没关系(就象乱序执行),但当他们都写完后就必须重新在横幅上(自然可以由别人做,就象CPU中乱序执行后的重新排列单元)按"春节联欢晚会"的顺序排好才能挂出去。【参考1】

从Intel 第六代 CPU(Pentuim Pro) 开始, 引入了乱序执行的功能。通过前面的介绍也可以看出来 CPU 需要确定后面要执行的指令并不依赖于前面的指令。比如:计算 a=1+2, b= a+1, 这种情况是无法先进行 b=a+1 运算的。这种依赖被称作依赖链。

首先,处理器将指令转为微指令(μop)。比如: ADD EAX,EBX 这样的只对应一个μop;但是像 ADD EAX,[MEM1] 会生成2个μop:一条指令是从内存读取数值到寄存器,另外一条是将保存内存值的寄存器和 EAX 相加;再例如 ADD [MEM1],EAX 会生成3个μop:第一个是从内存取值,一个是进行相加,最后一个是将结果传输到内存中。这样做的好处是,拆分之后的μop可以进行乱序执行:

例如:

mov eax,[mem1]
imul eax,5
add eax[mem2]
mov [mem3],eax

这里 ADD EAX,[MEM2] 拆分为2条μop。这样计算 imul eax, 5 的时候可以同时到内存中读取[MEM2]。如果Cache 中没有数据,那么处理器读取[MEM1]之后会马上进行读取[MEM2]的操作。

再比如堆栈操作指令拆分为μop之后运行会更有效率。例如:

push eax
call func

如果没有将 PUSH 拆分为2条μop的话,因为 CALL 操作需要依赖于 ESP ,所以 CALL 需要等待 PUSH EAX 之后才能执行。如果将 PUSH eax 指令拆分为2个μop: SUB ESP,4 和 MOV [ESP],EAX。 那么 SUB ESP,4 可以在 EAX 还没有赋值之前执行。这样就解除了CALL 指令的路径依赖。可见在μop的帮助下,堆栈的操作能够节省时间。【参考2】

参考:

1.https://baike.baidu.com/item/%E4%B9%B1%E5%BA%8F%E6%89%A7%E8%A1%8C/4944129?fr=aladdin

2.https://www.agner.org/optimize/microarchitecture.pdf

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注