唤醒阶段的推测唤醒(1)

        前文讲述的唤醒方法都是建立在一个前提下,即指令在 FU 中执行的周期数是可以预知的,这样才可以为这条指令分配一个确定的DELAY值,但是在实际的处理器中,很多指令需要的执行周期数是没有办法提前知道的。

  • load指令。
    • FU中执行的周期数,取决于D-cache是否命中,而且DRAM有可能读取数据不是一个固定的值;                           
  • 在某些处理器中,定义了一些特殊的情况;
    • 乘法的位数比较小时,乘法的结果可以提前得到,early out;

解决方式:当该指令执行完成时,再进行唤醒;

  • 小的改进:在设计Dcache时,是否命中可以提前于数据得到;
    • 通过这种改进措施,当L1 Cache命中时,指令A和指令B之间的执行相差了3个周期,相比于前一种设计已经有了改进,但是仍旧不完美。
    • 其实对于load指令,还需要考虑更多的事情:
      • A发生了miss, 此时B指令也不能stall而等待操作数, 这回导致FU无法接受新的指令;
      • 需要将inst B重新放回issue queue, inst A会重新对issue queue中的指令进行唤醒;
  • 预测唤醒(speculative wake-up)
    • 对于执行周期数是一个确定值的指令,可以使用延迟唤醒的方法,而对于本节介绍的load类型的指令,它的执行周期是不确定的,而load指令多处于相关性的顶端,如果等到它的结果被计算出来的时候才进行唤醒操作,会损失一些潜在的并行执行的机会,从而降低处理器的性能;
    • 因此需要使用预测的方法预测指令执行的周期数,在指令得到结果之前,就对相关的指令进行唤醒操作,这种方法就称为推测唤醒(speculative wake-up),或称为预测唤醒。
    • 对于load来讲:
      • 在流水线的发射阶段假设所有load指令的D-Cache都是命中的,这样当load指令被仲裁电路选中时,就可以按照最短的执行周期数,对相关的指令进行唤醒操作
      • 当load指令真正访问D-Cache时,如果此时发现了缺失,那么就说明之前的预测是错误的,需要进行状态恢复
        • 那些被load指令唤醒的所有寄存器都应该重新被置为非准备好(not ready)的状态,
        • 如果一些指令已经离开了发射队列,那么还需要将其从流水线中抹掉重新放回到发射队列中,这就完成了状态恢复的过程
        • 这些指令会等待load指令重新将它们唤醒。此时load指令可以继续预测L2 Cache是命中的,并按照这个周期数对相关指令进行唤醒,当然,如果发现这个预测也是不正确的,那么就继续按照这种方法进行状态恢复。
      • 采用VIPT/PIPT的D-CACHE,在推测唤醒的过程上是不同的;
        • 主要是判断hit/miss的时间点不一样;差别在于需要进行VA/PA转换;
      • independent window 与 speculative window;
        • load 指令被仲裁电路选中之后,需要等待两个周期才可以将相关的指令进行唤醒,在这两个周期内,仲裁电路可以选择那些和load指令不存在相关性的指令,称这两个周期为Independent Window(简称IW)。
        • 而从load指令开始将相关的指令进行唤醒,直到它发现自身是否会D-Cache命中/缺失,中间也间隔了两个周期,称这两个周期为Speculative Window(简称SW),示意图如图 8.47 所示。
      • IW/SW可能是互相重合的;
        • SW 窗口中的指令不一定就和 load 指令存在相关性,例如那些被 load指令唤醒的指令并没有马上被仲裁电路选中,就会使SW窗口中的指令其实并没有使用load 指令的结果
        • IW 窗口中的指令也并不一定就和 load指令无关,因为它可能和其他load 指令的 SW窗口是重合的;
        • 由于发现 D-Cache缺失时,那些和 load 指令存在相关性的指令都需要重新被放回发射队列中并等待被唤醒,这就需要这些指令重新在发射队列中变为not ready的状态,并重新向仲裁电路发出申请,这个过程称为replay。
        • replay有两种方式:issue queue based replay, replay queue based replay;
  •  issue queue based replay
    • 指令被仲裁电路选中之后,不会马上离开发射队列(Issue Queue),只有当这条指令被确认已经正确执行之后,才会允许这条指令离开发射队列。
    • 此种方式需要增加一个bit, issued, 指示已经被选中,但是还没有离开issue queue;
      • 当这个标志位为1时,这条指令就不会再向仲裁电路发出请求信号了;
      • 当这条指令需要replay时,会将issued标志位清零,这样它就可以继续向仲裁电路发出请求信号;
    • 可能会发生replay的场景可能有:
      • 采用交叠(interleaving)结构的D-Cache中的bank冲突
      • store/load指令的违例(即按照程序中规定的顺序,load指令比拥有相同地址的 store 指令先执行了),
      • 甚至是 load/load 指令的违例(即按照程序中规定的顺序,load指令比拥有相同地址的load指令先执行了,在某些多核应用环境中要求保持这种顺序)
      • 等等,都需要进行replay;
    • 解决方式:
      • 让所有的指令在被仲裁电路选中的时候,都不要马上离开发射队列,只有当这条指令确认自己可以正确执行的时候,才会离开发射队列;
    • 怎么知道一条指令的执行是正确的
      • out-of-order处理器中,load/store乱序,即使load已经命中,或者执行完了,但是只要store/load的顺序不对而导致load指令的结果是错误的,此时需要将load及其相关的指令,都进行replay;
      • 这种处理器中,只有该指令retire的时候,才能保证是正确执行的,此时才能离开发射队列;
    • 这种基于issue queue replay的方式,有部分指令因为d-cache hit的概率很高,发生store/load的概率也不高,所以其实大部分指令,在被仲裁电路选中之后,已经不会replay了,但是这部分指令,仍然占据着发射队列的空间;
    • --> 降低了实际可以使用的容量
    • 采用折中的方式:
      • 只对load指令采取issue queue based replay的方式, 一旦load指令在其执行阶段得到了D-cache hit的结果,则将发射队列中的相关指令进行释放
        • 这种方式,如果发生了store/load违例,或者load/load违例,此时可能该load指令已经离开IQ, 此时已经没有办法,因为IQ已经满了的原因,该指令无法重新放回IQ,可能会产生死锁:
          • 在发射队列中的指令等待被它前面的指令唤醒,而前面的指令由于发射队列中没有空间而无法进行replay,也就无法将其他指令进行唤醒,这就产生了死锁。
          • 因此,对于store/load指令违例,或者load/load指令违例的这些情况,是没有办法依靠发射队列进行replay的,这时候需要将那些需要replay的指令从流水线中抹掉,从1Cache中重新将这些指令取出来放到流水线中,当然这样会损失一些性能,这就是一种折中了;
      • 对于load指令,仍然使用issue queue进行replay;
        • 一种简单的方式:将所有在load指令之后,被selcet的指令,都放回发射队列;(注意,并不是真的将指令放回到发射队列中,因为这些指令还都没有离开发射队列(因为还没有commit),只需要更改对应的状态位就可以了)
        • 这种方法当然不会产生错误,但是,考虑到IW窗口的存在,甚至是在一条load指令的SW窗口中,未必所有的指令都是和load指令相关的,所以这种方法将很多本来可以不需要replay的指令也进行了replay,在一定程度上损失了一些性能,但是实现起来相对是比较简单的,这种方法被称为Non-SelectiveReplay;
        • (此处描述的依赖关系,而不是IW/SW的关系)
        • 进一步改进:
          • 处于IW窗口中的指令,是肯定和对应的load指令不存在相关性的。
          • 在图 8.50 中,当load指令在流水线的Data阶段发现 D-Cache miss时,处于 Cal Addr 和 TLB/Tag 这两个流水段的指令,是不需要进行 replay 的,
          • 因此只需要将RF和Select这两个流水段的指令从流水线中抹掉,重新在发射队列中等待被唤醒就可以了,这样可以在一定程度上减少性能的损失,可以称为是改良版的NonSelective Replay 的方法。
      • 上面的load replay的时候,需要判断,哪些指令和load指令存在相关性,哪些不存在相关性:
        • 不存在相关性的指令,issued被清除之后,仍然处于ready状态,可以直接向select logic发出申请;
        • 存在相关性的指令,需要等待被load重新唤醒;
        • 所以我们需要知道,哪些寄存器是和load指令存在相关性的;
    • 相关性的计算方式:
      • 每条load指令,使用5bit的值,表示该load指令处于流水线哪个位置: Select、RF、Cal Addr、TLB/Tag 和 Data;
      • 该5 bits的值,称之为Load Position Vector(LPV);
        • select logic 选中时,LPV=10000;
          • 此阶段会将load的目的寄存器,与发射队列中的所有源寄存器进行比较,相等的源寄存器,会得到该load指令的LPV值;
          • 后续每个周期,得到LPV的源寄存器,都会右移一位,用来跟踪load指令处于流水线的阶段;
        • 间接相关性的实现;
          • 每条指令在被仲裁电路选中后,需要对其他指令进行唤醒,此时将当前指令的LPV也给到唤醒的指令,这样就能识别出,哪些指令与load存在间接相关性了;
        • load指令的LPV值,也是每个cycle 右移一位;
      • 使用时,当load指令的LPV值变为00001时,如果当前是miss的,则只要去看看哪些源寄存器的LPV值,最低bit也是1,则说明这些源寄存器和load指令存在直接或者间接的相关性,需要变成not ready状态;
      • 如果一个周期可以选出多条load指令,则增加LPV的个数即可;

总结: 

  • 上面所述的内容即是Non-Selective Replay的方法,这种方法的过程可以简单地描述为:
    • 在load指令的执行阶段发现D-Cache缺失时,将它的SW窗口中的所有指令都从流水线中抹掉,这些指令会重新被“放回”到发射队列中
    • 同时将发射队列中和这条load指令直接或间接相关的所有源寄存器都置为 not ready 的状态,等待重新被唤醒。
    • 这样在发射队列中,那些和load指令无关的指令由于仍然是处于准备好的状态,它们很快会再次被仲裁电路选中,当然这样的重复执行会浪费一些性能,而那些和load指令存在相关性的指令需要等待被唤醒之后才可以参与仲裁的过程。
  • Selective Replay的方式
    • 如果发现 load 指令发生 D-Cache 缺失时,只将它的 SW 窗口中,和 load 指令存在相关性的指令抹掉,其他不相关的指令可以继续执行,则可以提高处理器执行的效率;
  • 不管是Non-Selective Replay还是Selective Replay,它们都是基于发射队列进行replay 的方法,很多指令在被仲裁电路选中之后不能马上离开发射队列,因此这种方法最大的缺点就是降低了发射队列实际可用的容量,造成处理器无法最大限度地寻找程序的并行性。
  • 44
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值