【计算机体系结构-05】流水线冒险 (Pipeline Hazards)——控制冒险 (Control Hazards)

news2024/11/25 11:54:30

1. 流水线冒险 (Pipeline Hazards)

  在流水线处理器中会有这样的情况,当前级流水线的指令可能会阻止下一条连续指令在流水线中预期的时钟周期内执行,这样的情况被称为流水线冒险 (Pipeline Hazards)。当发生流水线冒险后将会降低流水化所带来的理想加速比。共有以下三类冒险。
[注]:流水化加速比 = 非流水化指令平均执行时间 / 流水化指令平均执行时间

(1) 结构冒险 (Structural Hazards),当处理器以流水线方式工作时,指令会重叠执行,如果硬件无法同时支持指令的所有组合方式,就会出现资源冲突,从而导致结构冒险。即当前指令所需的硬件正在为之前的指令工作;
(2) 数据冒险 (Data Hazards),当处理器以流水线方式工作时,指令会重叠执行,若前后指令存在依赖关系,就可能导致数据冒险;(如,当前进入流水线的指令需要用到上一条指令执行结束后的结果作计算,此时则发生数据冒险)
(3) 控制冒险 (Control Hazards),分支指令以及其它改变程序计数器的指令实现流水化时可能导致控制冒险,也就是需要根据之前指令的执行结果决定下一步的行为。

  本文先仔细研究一下控制冒险,其它冒险类型将在后续文章中研究,在此之前首先来回顾以下一些你熟悉的东西。

2. 分支、跳转指令 (Branches、Jumps)

  你应该已经发现了分支指令和跳转指令与其它常规指令或者算术逻辑指令有些不同。这两类指令的执行都会影响到程序计数器 (PC-Program Counter) 的值。

  分支指令改变 PC 是根据当前 PC 的值加上偏移得到目标值——相对寻址指令。

  跳转指令(无条件跳转)改变 PC 无需关心当前 PC 值,而直接改变 PC 寄存器——“绝对寻址指令”。需要注意的是这里加上了双引号,跳转指令本意为跳转到一个绝对地址,但事实上在指令长度固定且与地址长度相同的情况下,没有一条指令可以同时容下操作码和跳转的绝对地址,因此跳转指令也为当前 PC 值加上偏移量实现的。

  • 无条件跳转 (Jumps)
    指令需要关心的点:操作码 (Opcode),偏移量 (Offset),程序计数器 (PC)

  例如,MIPS 中的 J 指令跳转到的地址并不是直接指定 32 位的地址(所有 MIPS 指令都是 32 位长,不可能全部用于编址数据域,那样的指令是无效的,也许只有nop ):由于目的地址的最高 4 位无法在指令的编码中给出,32 位地址的最高 4 位取值当前 PC 的最高 4 位。对于一般的程序而言,28 位地址所支持的 256MB 跳转空间已经足够大了。

  再如 RISC-V 架构 (RV32) 中的 JAR 指令运用到 J 格式的立即数编码方式,符号位扩展之后 2 的整数倍的偏移量加上 PC 值作为跳转目标地址,因此可以控制指令跳转到当前位置前后 1 MiB 的范围内。JAL 指令将(PC + 4)存放在目的寄存器 rd 中。标准的软件中系统调用约定用寄存器 x1 作为返回地址寄存器。

JALrd = x0 的时候,即为简单的 Jump 指令(汇编程序中的伪指令 J)。
在这里插入图片描述
  OK,当计算机取指 (IF) 到一个 JUMP 指令,在 ID 阶段译码器通过该条指令的操作码 Opcode 确定当前指令是一条跳转指令,然后还需要确定指令中给的偏移量 Offset 和当前程序计数器 PC 值,然后需要为程序计数器加上该偏移量,这就需要在 ALU 或者是一个特殊的加法器中执行,最终改变 PC 值。

  • 寄存器跳转 (Jump Register)
    指令需要关心的点:操作码 (Opcode),寄存器值

  当计算机取指 (IF) 到一个寄存器跳转指令,在 ID 阶段译码器通过该条指令的操作码 Opcode 确定当前指令是一条寄存器跳转指令,但这时候并不知道要跳转的地址只知道保存跳转地址的寄存器,之后再从该寄存器中获取跳转地址。这里没有任何偏移,而是直接跳转到跳转寄存器保存的地址。

  • 条件分支跳转 (Conditional Branches)
    指令需要关心的点:操作码 (Opcode),程序计数器 (PC),寄存器值 (用于判断条件),偏移量 (Offset)

  这就变得有点复杂了,当计算机取指 (IF) 到一个条件跳转指令,在 ID 阶段译码器通过该条指令的操作码 Opcode 确定当前指令是一条条件跳转指令,然后需要获取 PC 值和查看对应的寄存器,通过寄存器的值得到条件结果(如,用寄存器的值与 0 比较,查看是否大于或小于),再通过指令给的偏移量加上程序计数器 PC 值得到跳转地址完成一个和 PC 相关的分支。

3. 控制冒险 (Control Hazards)

3.1. 跳转指令带来的流水线控制冒险

首先来了解下基本的控制冒险,最基本的控制冒险是如何保证下一条指令的正确执行,来看下面这个流水线图。

在这里插入图片描述
  在上面个流水线中有两个指令 I1I2,指令 1 是从 r0 寄存器中取值并加上立即数 10 再将结果保存到 r1 寄存器中,指令 2 是从 r2 寄存器中取值并加上立即数 17 再将结果保存到 r3 寄存器中去。这是两条很简单的指令,这两条指令之间没有数据的依赖性,因此着这种情况下不会产生数据冒险。这里重点关注控制冒险。

  指令 1 会按正常的五级流水线执行顺序执行,取指 IF、译码 ID、执行 EX、存储 MEM、写回 WB 。可能你发现了第二条指令这里的执行似乎有点不同,当第二条指令指令进入流水线中,第一条指令才刚刚完成取指阶段,这个时候就会产生一个问题:“第二条指令到底是否是我们需要执行的指令呢?”,产生这个问题的原因是第一条指令并没有被译码,因此这时并不清楚第一条指令到底是不是分支或跳转指令。所以这时候按顺序流进流水线的指令 2 不一定是程序需要执行的指令。直到第一个指令在 ID 阶段被译码器解码后,这时候我们了解到,“哦~ 上一条指令不是分支或跳转指令,或者的确是一条分支或跳转指令”。

  那么如果指令 1 是一条分支或跳转指令呢?那么在译码阶段就会确定指令 1 是这样的指令,因此在指令 1ID 阶段时钟周期将会改变程序计数器 PC 和改变指令寄存器中要被读取的指令地址。这样就会产生控制冒险,为了避免冒险我们会在 ID 这个阶段插入一个气泡 (Bubble),让下一条指令的取值阶段延迟一个周期,如果继续这样下去,就会变成下面这样。
[注]:为避免这类冒险,常常会使流水线插入一个空操作 nop。这样的空操作通常被称为流水线气泡或直接称为气泡 (Pipeline Bubble/Bubble)。

在这里插入图片描述

  每条指令流入流水线都会要考虑控制冒险,那么要避免冒险就要给每个 ID 阶段插入一个 Bubble,那么每条指令的取值都需要两个时钟周期,你会意识到这将会是非常低效的流水线。现在我们具体的分析这样的流水线,让我们换一种流水线画法(坐标改变)再来看看。

在这里插入图片描述

这样就会很清楚的看到,这条流水线执行的顺序是 I1nopI2nopI3nopI4 …按照这个流水线计算它的 CPI = 2 (1 + 1) ,理想 CPI = 1 ,按照这样设计的机器执行程序的性能严格减半。
[注]:
非流水化 CPI = 指令执行周期 / 执行指令个数;
流水化 CPI = 理想 CPI + 每条指令的流水线停顿时钟周期;(理想 CPI = 1)

3.2. 解决跳转指令带来的控制冒险(基本方法)

  现在已经清楚了在流水线中会因为存在跳转指令的原因,而为流水线带来控制冒险,那么如何解决这个问题呢?其实说来方法也简单,那就是猜测 (Speculate) 下一条指令不是跳转指令,因此直接将 PC 的值加 4 (若指令长度是 4 字节)。
在这里插入图片描述
  现在的流水线处理方法就是图中紫色线圈出的部分,猜测吓一跳指令不是跳转指令,而直接用一个加法器为 PC4,让其指向连续的下一条指令,按照正常的顺序这里应该会执行 96 地址的指令、100 地址、104 地址。

  但实际上来看这段指令代码,100 地址的指令是一条跳转指令,当 100 地址的指令被取值,到了 ID 译码阶段发现 100 地址的指令是一条跳转指令,但此时 104 地址的指令已经被取值(由于上次猜测该指令不是跳转指令因此会顺序取值)。而 100 地址的指令告诉我们应该去 304 地址取值执行,那么这时候就需要做两件事情,第一,要阻止已经被取值了的 104 地址指令继续在流水线中执行(即杀死现在的流水线);第二,改变 PC 值为要跳转到的地址。

在这里插入图片描述

  为了完成上述第一个问题我们在流水线中加入一个选择器 IRSrc,当上一条指令到译码阶段被解译为跳转指令时,该选择器便会切换到一条空指令 nop。并且在周期结束时利用一个额外的加法器将指令的一部分和现有的 PC 相加计算得到新的跳转地址交给 PC,从而完成第二点。

在这里插入图片描述
  将上面的流水线电路执行程序的过程用时间线的表方式描述就像上图这样,第二条指令到了 ID 阶段被译码出是跳转指令,虽然 I3 已经完成取指,但是此时选择器切换到 nop,那么 I3 指令在接下来流入流水线并不会执行实际的动作,同时在 I2 指令 ID 阶段时钟周期结束时完成对 PC 值的计算,到了 t3 这个时钟周期,IF 再取指,就成功的取到了 304 地址的指令完成指令的跳转。

3.3. 条件分支带来的流水线控制冒险

I1            096      ADD
I2            100      BEQZ   r1   +200
I3            104      ADD
              108      ...
I4            304      ADD

  这里有一段指令代码,100 地址的指令会判断 r1 寄存器的值是否等于 0 如果是则跳转到以 200 为偏移的地址。事实上你发现这里已经产生了一条流水线的分支,那么带来的问题就是

  • 1. 要怎么样知道是否采用这条分支;
  • 2. 以及采用这个分支后要如何去做。

3.4. 解决条件分支指令带来的流水线的控制冒险(基本方法)

  先来看第一个问题,如何知道是否采用这条分支,是否还能像跳转指令那样直接在译码阶段完成(即根据译码的指令类型判断),这样的方法用在条件分支指令似乎不合理,因为这时候只知道是条件分支指令,但并不清楚条件是否成立。因此这里需要用一个能够做比较的硬件逻辑单元,类似这样的减法运算或比较操作很适合用 ALU 完成,然后再引出一个零线 (wire),如下图。

在这里插入图片描述

  根据这样的做法,将会在译码阶段的下一个周期结束后才能确定是否选用分支(根据 zero wire 判断)。PC 的预测方案依然是猜测不跳转的方式,那么 IF 阶段会在 I2ID 阶段取指一次地址为 PC + 4 = 104,当计算 I2 分支这个时钟周期, IF 又会取指一次地址为 PC + 4 = 108,因此当能够确定是否选用分支时,我们已经在提取下下一条的指令了。

  你应该发现了,当我们能够确定是否选用分支的时候,已经提取了两条指令,在此之前并不清楚是否要 kill 掉(插入 nop)这两个进入流水线的指令,直到获取到 zero wire 的信号。

  那么到这里又会存在一个问题,考虑一下,我们可以使用 stall 信号停止寄存器移动(改变),然后可以利用选择器重定向流水线流入指令,通过这两个方法实现消除先前的流水线业务。那么这两个动作的优先级应该怎样选择?是随意还是必须有先后顺序?

在这里插入图片描述

  ok,现在假设 stall 信号优先级更高一些,上图中红色的 stall 信号线会阻止寄存器改变,
小注:(文章未完,近期完善中…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/401399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA中自动书写setter插件

一般我们创建一个对象后,想要设置属性,是不是我们经常需要一个一个写,当属性很多的时候会非常麻烦,这个插件就可以解决这个问题:它可以一键生成该对象所有的setter方法 下载插件 选择需要设置属性的类名,a…

【Matlab】如何设置多个y轴

MTALAB提供了创建具有两个y轴的图,通过help yyaxis就能看到详细的使用方式。 但是如果要实现3个及以上y轴的图,就没有现成的公式使用了,如下图所示。 具体代码 % 数据准备 x10:0.01:10; y1sin(x1); x20:0.01:10; y2cos(x2); x30:0.01:10;…

C++:详解C++11 线程(一):MingGW 各版本区别及安装说明

MingGW 各版本区别一:MinGW、MinGW-w64 简介二:MinGW 各版本参数说明三:下载解压一:MinGW、MinGW-w64 简介 MinGW(全称为 Minimalist GNU for Windows),它实际上是将经典的开源 C 语言编译器 G…

Serviceaccount

K8S鉴权 目录 K8S鉴权 什么是RBAC K8S中的RBAC 角色 角色绑定 主体(subject) 角色(Role和ClusterRole) 集群内置权限 cluster-admin admin edit view system开头的y用户 演示 参考 k8s集群相关所有的交互都通过apiserve…

Go 内置运算符 if for switch

算数运算符fmt.Println("103", 103) //103 13 fmt.Println("10-3", 10-3) //10-3 7 fmt.Println("10*3", 10*3) //10*3 30 //除法注意:如果运算的数都是整数,那么除后,去掉小数部分,保留整数部分 f…

redis Big key (俗称大key)

一、什么是Big Key? 大key,其实不是说比较大的主键,而是值比较大的key。key往往是程序可以自行设置的,value往往不受程序控制,因此可能导致value很大。 redis中这些Big Key对应的value值很大,在序列化/反序列化过程中…

SAP MM学习笔记5-SAP中的移动类型实例,对应收货入库以及退货之后的各种情况

对应现实的情况,SAP中有各种各样的收货模式。在SAP中使用移动Type来对应这些情况。 最常用的就是 移动Type 101 收货。没有意外情况,就是正常的收货。 以下是我调查及验证的结果,如果有错误,请指正,谢谢。 移动Type…

腾讯云企业网盘2.5版本全新发布啦!!!

腾讯云企业网盘又又又更新啦!本期重点打磨管理协同、企业安全守护能力,同时也不断强化自身产品体验,助力企业高效办公~那么,此次更新具体有什么安全可靠的新功能呢?今天就带大家一起解锁~01协同管理,提升工…

【网络】http协议

🥁作者: 华丞臧. 📕​​​​专栏:【网络】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站 文章…

C/C++ 操作ini文件(SinpleIni 跨平台库)

最近在学习时,发现自己还不会操作ini文件,想着以前工作时接触到的项目或多或少都要用到ini文件去保存初始化程序的数据;所以赶紧去网上搜索以下C/C操作ini文件都有些什么库可以玩玩;搜索到有: 1. inih:这是…

Dubbo原理简介

Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。 作为RPC:支持各种传输协议,如dubbo,hession,json,fastjson,底层采用mina,netty长连接…

SAP 分析云 2023.03 版新功能抢先看

本文介绍了 SAP 分析云2023.03版本的新功能。对于 SAP 分析云季度发布周期 (QRC) 客户,此版本及其功能将作为 QRC 2023 年第2季度版本的一部分提供。本版本主要在仪表盘和故事设计、数据集成、企业计划方面进行了功能更新,来和阿拓一起看看吧&#xff01…

Hive---窗口函数

Hive窗口函数 其他函数: Hive—Hive函数 文章目录Hive窗口函数开窗数据准备建表导入数据聚合函数window子句LAG(col,n,default_val) 往前第 n 行数据LEAD(col,n, default_val) 往后第 n 行数据ROW_NUMBER() 会根据顺序计算RANK() 排序相同时会重复,总数不会变DENSE…

C#要点技术(一) - List 底层源码剖析

1。 ## 常用组件底层代码解析List 底层代码剖析List是一个C#中最常见的可伸缩数组组件,我们常常用它来替代数组,因为它是可伸缩的,所以我们在写的时候不用手动去分配数组的大小。甚至有时我们也会拿它当链表使用。那么到底它的底层是怎么编写…

将Quazip编译成基于32位release版的库时报错的解决方案

开发环境:Win10 Qt5.9.9 注意:阅读本篇文章前,首先阅读Quazip的编译及使用,保姆级教程。 之前写了如何编译Quazip的库,当时是使用MSV2015-64-release来编译的, 具体编译流程可参考之前的文章Quazip的编译及…

3句代码,实现自动备份与版本管理

前言:服务器开发程序、测试版本等越来越多,需要及时做好数据的版本管理和备份,作为21世界的青年,希望这些事情都是可以自动完成,不止做了数据备份,更重要的是做好了版本管理,让我们可以追溯我们…

用Go快速搭建IM即时通讯系统

WebSocket的目标是在一个单独的持久连接上提供全双工、双向通信。在Javascript创建了Web Socket之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会将HTTP升级从HTTP协议交换为WebSocket协议。由于WebSocket使用自定义的协议…

深度学习部署笔记(十): CUDA RunTime API-2.2流的学习

1. 流的定义 流(Stream)是一个基于上下文(Context)的任务管道抽象,是一组由GPU依次执行的CUDA操作序列,其中每个操作可能会使用或产生数据。在一个上下文中可以创建多个流,每个流都拥有自己的任…

Kettle体系结构及源码解析

介绍 ETL是数据抽取(Extract)、转换(Transform)、装载(Load)的过程。Kettle是一款国外开源的ETL工具,有两种脚本文件transformation和job,transformation完成针对数据的基础转换&…

全网最详细的(CentOS7)MySQL安装

一、环境介绍 操作系统:CentOS 7 MySQL:5.7 二、MySQL卸载 查看软件 rpm -qa|grep mysql 卸载MySQL yum remove -y mysql mysql-libs mysql-common rm -rf /var/lib/mysql rm /etc/my.cnf 查看是否还有 MySQL 软件,有的话继续删除。 软件卸…