查缺补漏----数据冒险与控制冒险

不清楚概念的话,先看王道书,或者看这篇:

计算机组成原理(11)----指令流水线_store指令的时空图-CSDN博客

结构冒险:

对于结构冒险,通常采用指令Cache和数据Cache分离的方法就能解决。

数据冒险:

在学习的指令中,Load指令和运算类指令会写寄存器,如果在没有写回寄存器之前,其他指令就尝试读这一指令,那么就会发生数据冒险。

控制冒险:

在学习的指令中,只有转移类指令可能会更改PC值,那么下一条要执行的指令就不是流水线中的下一条指令,则引起控制冒险。


判断是否存在数据冒险:

从第一条指令开始,结合注释,观察该指令“写”了某个寄存器,并观察后续相邻的3条指令是否“读”了同一个寄存器。若发现此类情况,则存在数据冒险。为什么只用看后面3条,看下面的图就懂了。

例题1:

I1写的是R1,观察后面3条指令,没有读R1,I1与其他3条指令不存在数据冒险;第二条指令写了R5,观察后续3条指令有没有读R5,I3读了R5,所以I2与I3存在数据冒险。

数据冒险的解决方法:

① 硬件阻塞        ② 转发(旁路)技术,转发旁路技术能解决大部分数据冒险,不能解决由 Load 指令写寄存器引起的 Load-use数据冒险(后面讲)

用硬件阻塞的方法解决如下:

由于阻塞期间I2一直占用IF段的硬件资源,所以只有I2段进入到了ID,下一段才能进入IF

例题2:

答案为C,自己分析一遍,以下为解决方法:


分析是否存在控制冒险:

只有转移类指令的执行才会引发控制冒险。因此只需观察指令序列中是否包含“转移类指令”即可。

解决方法:将转移类指令后一条指令的IF段硬件阻塞3个时钟。这样就能保证后一条指令取指的操作,在转移类指令的第4段(M)之后在开始,这样才能保证后一条指令取指,取的是修改完PC后正确地址的指令。

例题:

第1条指令写了R4,而后面的2,3条指令都读了R4,所以需要确保第2条和第3条指令的ID段在第1条指令的WB段之后:

第2条指令与第3条指令之间也会产生数据冒险:

其余同理分析,会由于数据相关而产生阻塞的是2,3,4,6

很显然,第6条指令是转移类指令,所以会产生控制冒险。

为什么第1条指令和第5条指令存在数据相关?不是只有与后面3条指令才可以产生数据相关吗?

这是因为第6条指令是一条转移类指令,如果执行I6指令后,跳转到I1继续执行,那么I5和I1就有可能产生数据相关。

I5指令需要写R2,而I1需要读R2,所以I1的ID段需要在I5的WB段之后:

由于题目给了,分支指令的执行均引起3个时钟周期的阻塞,也就是后一个指令的IF段会推后3个时钟。看到下图,I1段的ID已经在WB段后面很多了,所以即使有数据相关,但是因为有3个时钟周期的阻塞,所以I1和I5不会因为数据相关而阻塞。

其实,就算3个时钟周期的阻塞,I5和I1的执行也不会产生数据相关,看图,因为I6与I5也有数据相关,I6需要向后推迟3个时钟周期,这时I1的执行刚好在I5的WB后面。所以说出题老师的本意是让我们答"分支指令的执行均引起3个时钟周期的阻塞",但是这里答"I6与I5有数据相关,所以I6向后推迟3个时钟周期"也没错。

补充:

为什么“分支指令的执行均引起3个时钟周期的阻塞”,因为跳转指令PC值在M段更新,所以推迟3个时钟周期,使得IF(取数阶段)在M(更新PC值)后面。

总结:

关于数据冒险:后一条指令的ID段要在前一条指令的WB段之后

判断是否会产生数据冒险,则看该条指令的后3条指令有没有读 该条指令写的寄存器

关于控制冒险:后一条指令的IF段要在前一条指令的M段之后


转发技术处理数据冒险:

以 I1 举例,在通常的指令流水线中,执行(EX)阶段得到的结果,需要到WB阶段才能写回,而采用转发技术,可以直接将I1的EX的结果(放到EX/MEM流水段寄存器的结果)从流水段寄存器中取出,直接送到第2条指令的ALU输入端。

也就是说,即使I2的ID段取得数据是错误的,但是EX执行操作阶段,使用的数据是正确的,所以ID不需要进行阻塞3个时钟周期的操作。

为什么转发技术不能解决由 Load 指令写寄存器引起的 Load-use数据冒险

Load-use:Load指令将数据加载到寄存器中,下一条指令就需要使用寄存器中的值。例如下图的I2,I3指令:

Load指令会在M段结束后,才能在内存中获得最终的数据,然后在WB段才写回R[s3]

而下一条指令要在EX段就使用Load指令读出来的数据。

所以必须要让EX段阻塞一个时钟,阻塞一个时钟之后就可以使用转发技术将上一条指令M段的数据转发到下一条指令的EX段

由于I3指令阻塞了一个时钟,那么后一条指令I4,就必须阻塞4个时钟周期,使得后一条指令的IF段在前一条指令的M段之后:

完整解答:

总结:

① 对于控制冒险,如果采用硬件阻塞的方法,就要确保后一条指令的IF段在前一条指令的M段(修改PC值)之后。

② 对于数据冒险,可以使用硬件阻塞,也可以使用转发技术。如果采用转发技术,就不需要进行任何阻塞。但是转发技术不能解决由 Load 指令写寄存器引起的 Load-use数据冒险。对于Load-use指令,需要在EX段前进行一个时钟周期的阻塞。

### 数据冒险的概念 在计算机体系结构中,当两条或多条指令之间存在依赖关系,并且这些指令被安排得非常紧密以至于影响彼此的操作数访问顺序时,则会发生数据冒险[^3]。 具体而言,数据冒险主要分为三种类型: - **读写冲突(RAW, Read After Write)**:后续指令尝试在其前驱指令更新目标位置之前就读取该位置的数据- **写读后冲突(WAR, Write After Read)**:一条指令试图覆盖某个内存地址的内容,在此之后另一条指令会去读这个已经被改写的值;但实际上按照程序逻辑应该先完成读再做修改。 - **写写冲突(WAW, Write After Write)**:两个不同的源想要在同一时间点或者几乎相同的时间点往同一个目的地写入不同数值的情况。 为了应对这些问题,现代处理器采用了多种技术和策略来缓解或消除数据冒险带来的负面影响。这其中包括但不限于重新排序独立操作、利用旁路机制提前提供运算结果以及通过编译器优化减少潜在的风险区域等措施。 ```c++ // 示例代码展示如何可能引发数据冒险的情形 float a = b * c; // 指令1: 计算a=b*c d = e + f; // 指令2: d=e+f (假设这条指令上一句无关) g = h / i; // 指令3: g=h/i (同样假定其他两句无关联) // 如果上述三条指令被分配得太近,可能会因为资源竞争而导致数据冒险现象的发生 ``` #### 解决方法 针对不同类型的数据冒险问题,采取相应的解决方案如下: - 对于**读写冲突**,可以通过延迟分支执行直到所有必要的输入都准备好为止,也可以采用转发技术使得新产生的数据能够立即传递给等待它的下级单元而不必等到其正式存入寄存器文件后再取出使用; - 面对**写读后冲突**和**写写冲突**,通常的做法是在不影响最终输出的前提下调整指令序列,确保正确的先后次序得以维持,同时还可以借助额外的硬件支持如保留站来进行更灵活的任务调度管理。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值