处理器的乱序执行

前面介绍了乱序的概念及去相关,这里开始介绍处理器的乱序执行结构。

1. Buffer的作用去耦合

在顺序执行内核中,指令依次流经各个流水线单元,不需要进行缓存,而为了要能乱序执行,首先需要一个Buffer来缓存还没有执行的指令,然后在这个 Buffer中去调度指令的执行顺序。乱序执行内核的基本模型如下:

现代处理器中有大量的 Buffer,Buffer也广泛应用在其他技术领域及生活领域中,就拿电冰箱来说,电冰箱除了冷冻的功能外,它实际上也是个 Buffer,我们把买来的东西放进去,要吃时,再从里面拿。 Buffer有两大功能:

  1. 去耦合;
  2. 抗波动;

如果没有电冰箱,每次我们想吃东西时,都要去超市,用专业术语来讲,这就是耦合性太强了,如果超市关门了怎么办?如果超市太远了怎么办?有了电冰箱后,从超市买的食物就放在电冰箱中,我们就直接从电冰箱中取食物,而不需要关注超市的状况了。电冰箱去除了人和超市的耦合。 正常情况下,我们是每天买每天的食物,不过有时候,我们知道明天会有事情,没有时间买食物,因此今天就把今、明两天的食物都买了,这样明天就不会饿肚子了,这就是电冰箱的抗波动功能。

在上面的图中,粗线条表示东西多,细线条表示东西少,有时候买的多,有时候买的少,有时候吃的多,有时候吃的少,电冰箱的进和出都会存在一定的波动,电冰箱起到了抗波动功能,保证了我们在想吃时都有东西吃。

2.指令调度

在前面乱序设置陷阱的例子中,如果没有那个聪明的士兵,乱序也就无从谈起。同样,处理器的乱序执行内核也需要一个调度器,分析指令间的相关性,分析指令什么时候能开始执行。 指令什么时候能开始执行呢? 对于一条指令来说,它有操作码和操作数,操作码描述指令要做什么,处理器会安排个功能单元( function unit)去执行它。操作数描述指令要处理什么数据,经过寄存器重命名后,目的寄存器总是新的,因此只需要关注源操作数是否准备好即可。所以,指令能否开始执行,依赖于两个条件:

(1) 是否有空闲的功能单元去执行这条指令。

(2) 该指令的源操作数是否已经准备好。

只要满足这两条要求,指令就可以去执行,而不需要等待前面的指令完成。这样处理器就完成了乱序调度及并行调度。 以前面经过寄存器重命名的指令为例,

处理器会记录指令源操作数的准备状态,当指令1完成后,处理器会通知所有依赖F5的指令,F5已经准备好了,指令2需要的两个源操作数F5和F2都已准备好,它就可以被发送到指令的执行队列中去执行。同样,指令3也可以准备执行,如果处理器中有多个加法单元,指令2和指令3就可以同时执行。指令2完成后,F6也准备好了,指令4就可以去执行,指令4执行完后,F8就准备好了,F5早就准备好了,指令5就可以去执行。 在这个调度的例子中,5条指令4个 Cycle就可以完成,而使用顺序内核,则需要5个 Cycle。 处理器内部需要一个Buffer来缓存指令,以供乱序调度,这个Buffer就是保留站( Reservation station),完成寄存器重命名后的指令被放置在保留站中,等到操作数和功能单元都准备好时,保留站中的指令就能被分派出去执行。

3.指令的顺序提交

在指令的执行过程中,通常会有中断和异常产生,如在下面的这个例子中,

XOR指令执行完后,来了一个中断,中断处理一般都是将处理器的ISA寄存器压栈执行中断服务程序,然后再退回来执行中断后面的指令。精确中断( Precise Interrupt)要求中断前的指令都执行,中断后的指令都没有执行,而在乱序执行内核中,MOV、INC指令有可能提前到XOR前面执行,那么怎么来实现精确中断呢? 解决方法就是:在指令乱序执行之后,再加一个步骤:指令顺序提交(In- order commit)。乱序执行后,指令的结果虽然出来了,但是这个结果并没有立即提交到ISA寄存器中,而是先缓存起来,只有当前指令前面的指令提交后,这条指令才能提交。 指令的顺序提交也能解决投机执行出错的问题,如下图所示:

分支预测单元预测到JNZ跳转到XOR处执行,乱序执行让XOR指令在ADD前面执行,不过天有不测风云,处理器执行到JNZ时,发现分支预测单元预测错了,实际上应该执行的是MOV这个分支,使用顺序提交策略,JNz后面指令的结果都没有提交,可以直接抛弃,重新开始执行MOV这条路径即可。 为了实现指令的顺序提交,处理器内部使用了一个Buffer,叫做重排序缓冲区(ROB Re-order Buffer),多数的学术文章都叫这个名字,龙芯把这个 buffer叫做 Reorder Queue,简称ROQ(总要有所区别嘛)。

每条完成寄存器重命名的指令都要送到ROB中,ROB中的指令按照初始顺序存放,指令经乱序执行后,只是修改了处理器内部的物理寄存器,并没有修改处理器的ISA寄存器(汇编指令能看到的寄存器),指令在提交时,按照ROB中的顺序,顺序地修改处理器的ISA寄存器。

4. 乱序执行总结

简单来说,指令在乱序执行内核中的处理过程可分为3个步骤:

下图为乱序执行内核的基本结构图:

取指、译码、分支预测和顺序执行内核一样,译码后,指令经过寄存器重命名,去除伪相关,然后进入指令分派模块,指令分派模块决定什么时候将指令分派到什么执行单元去执行。指令同时会进入指令提交单元,它记录了指令的原始顺序,用于指令的顺序提交,同时它会将分支指令的实际执行信息更新到分支预测单元。 乱序执行比顺序执行需要耗费更多的处理器资源,通常只有髙端处理器才会使用。最近, ARM Cortex-A9也引入了高端处理器常用的乱序执行( Out-of-Order Execution)和投机执行( Speculative Execution)。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏挖掘大数据

Apache NiFi 简介及Processor实战应用

Apache NiFi是什么?NiFi官网给出如下解释:“一个易用、强大、可靠的数据处理与分发系统”。通俗的来说,即Apache NiFi 是一个易于使用、功能...

2.1K100
来自专栏张善友的专栏

使用Hystrix提高系统可用性

今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来。 ? (图片来源:htt...

22350
来自专栏SpringBoot 核心技术

SpringCloud组件:Eureka服务注册中心的失效剔除与自我保护机制

Eureka作为一个成熟的服务注册中心当然也有合理的内部维护服务节点的机制,比如我们本章将要讲解到的服务下线、失效剔除、自我保护,也正是因为内部有这种维护机制才...

2.9K20
来自专栏自由而无用的灵魂的碎碎念

解决因为卸载vmware后键盘不能使用的问题

我之前安装的是vmware workstation 7.1,虽然添加与删除程序里有卸载选项,不过不管用,无奈用windows 优化大师将其卸载了。然后手动删除一...

12730
来自专栏全华班

小而优美的快速开发平台

kylin-frame是一个小而优美的快速开发平台,采用流行的框架springBoot+mybatis+shiro+redis开发,实现了权限管理(菜单...

26420
来自专栏菩提树下的杨过

spring cloud 学习(7) - 生产环境如何不停机热发布?

业务繁忙的系统,原则上是不允许停机的,那么问题来了,如果真有严重的bug要修复,不得不发布,怎么做到不停机发布,对业务无感知呢? eureka 提供了一系列re...

55090
来自专栏即时通讯技术

新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

3.2K30
来自专栏云计算

Go 微服务,第11部分:Hystrix和Resilience

在Go微服务博客系列的这一部分,我们将探讨如何使用Netflix Hystrix的Go实现和go-resilience重试包,使用断路器模式使我们的服务间通信更...

1.2K30
来自专栏Kirito的技术分享

浅析Spring中的事件驱动机制

今天来简单地聊聊事件驱动,其实写这篇文章挺令我挺苦恼的,因为事件驱动这个名词,我没有找到很好的定性解释,担心自己的表述有误,而说到事件驱动可能立刻联想到如此众多...

74290
来自专栏JackieZheng

探秘Tomcat(一)——Myeclipse中导入Tomcat源码

前言:有的时候自己不知道自己是井底之蛙,这并没有什么可怕的,因为你只要蜷缩在方寸之间的井里,无数次的生活轨迹无非最终归结还是一个圆形;但是可怕的是有一天你不得...

22280

扫码关注云+社区

领取腾讯云代金券