加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

5.3 硬件预读

(2011-10-02 23:18:51)
标签:

杂谈

分类: 浅谈CacheMemory

采用硬件预读的优点是不需要软件进行干预,不会扩大代码的尺寸,不需要浪费一条预读指令来进行预读,而且可以利用任务实际运行时的信息(Run Time Information)进行预测,这些是硬件预读的优点。

硬件预读的缺点是预读结果有时并不准确,有时预读的数据并不是程序执行所需要的,比较容易出现Cache Pollution的问题。更重要的是,采用硬件预读机制需要使用较多的系统资源。在很多情况下,耗费的这些资源与取得的效果并不成比例。

硬件预读机制的历史比软件预读更为久远,在IBM 370/168处理器系统中就已经支持硬件预读机制。大多数硬件预读仅支持存储器到Cache的预读,并在程序执行过程中,利用数据的局部性原理进行硬件预读。

最为简单的硬件预读机制是OBL(One Block Lookahead)机制,这种方式虽然简单,但是在许多情况下效率并不低于许多复杂的实现,也是许多处理器采用的方式。OBL机制有许多具体的实现方式,如Always prefetchPrefetch-on-missTagged prefetch[23]

在使用Always Prefetch OBL实现方式时,当一段程序访问数据块b时,只要数据块b+1没有在CacheHit,就对数据块b+1进行预读。这种方式的缺点是可能程序访问数据块b之后,将很长时间不使用数据块b+1,从而带来较为严重的Cache Pollution。使用这种方式时的Access Ratio2

在使用Prefetch-on-Miss OBL实现方式时,当程序对数据块b进行读取出现Cache Miss时,首先将数据块b从存储器更新到Cache中,同时预读数据块b+1Cache中;如果数据块b+1已经在Cache中,将不进行预读。使用这种方式时的Access Ratio1+Miss Ratio

Always PrefetchPrefetch-on-Miss OBL方式没有利用之前的历史信息,在某些应用中,容易造成Cache PollutionTagged PrefetchPrefetch-on-Miss实现方式的一种改进,其实现相对较为复杂,也使用了额外的硬件资源。

在使用Tagged Prefetch OBL实现方式时,需要为每一个Cache Block设置一个Tag位,该位在复位或者当前Cache Block被替换时设置为0。如果当前Cache Block是因为Prefetch的原因从其下的存储器子系统中获得时,该位依然保持为0

当前Cache Block在预读后第一次使用,或者是Demand-Fetched时,Tag位将从0转换为1,此时如果其后的数据块不在Cache Block时将进行预读[23]。这种方式与Prefetch-on-Miss的最大区别在于访问已经PrefetchCache中数据的处理。

当程序访问已经预读到CacheBlock时,在使用Prefetch-on-Miss方式时,不会继续预读下一个Cache Block,而使用Tagged Prefetch方式时,会继续预读下一个Cache Block,从而减少了Demand-Fetched的概率,其实现示意如54

5.3 <wbr>硬件预读

从上图可以发现,对于一个顺序访问的Access Patern,使用Prefetch-on-Miss方式,每次访问过一个Prefetched Cache Block后,都会出现一次Cache Miss;而是用Tagged Prefetch时仅会出现一次Cache Miss

但是仅用这一种访问模型,并不能证明Tagged Prefetch一定由于Prefetch-on-Miss方式。Alan J. Smith [23]根据Miss RatioAccess RatioTransfer Ratio三个参数对以上实现方式进行了较为细致的对比。从Access Ratio参数的上看,Always prefetch实现方式大于后两种方式。

Prefetch-on-miss方式相比,Tagged prefetch实现方式在Access RatioTransfer Ratio没有明显提高的前提下,降低了50%~90%Miss Ratio [23]。但是我们依然不能得出Tagged prefetch一定优于Prefetch-on-miss方式的结论。与其他方式相比,Tagged Prefetch方式每一个Cache Block多使用了一个Tag位,依然是某种程度的Trade-off

Tagged Prefetch实现有许多衍生机制,比如可以将数据块b+1b+2b+k预读到Cache中。其中kPrefetch的深度,当k1时,即为标准的Tagged Prefetch。更有甚者提出了一种Adaptive Sequential Prefetching实现方式,此时k可以根据任务执行的Run Time信息进行调整,可以为正,也可以为负。

以上这些硬件预读算法都有其局限性,特别是在处理Strided Array相关的计算时,为此也产生了一系列可以利用Stride信息的硬件预读实现,如Lookahead Data Prefetching实现[102]。该实现的组成结构如55所示。

5.3 <wbr>硬件预读

假设在一个3-Nested Loop Iterations中,某条存储器访问指令mi需要陆续访问a1, a2a3。当(a2- a1) = Δ ≠ 0时,需要对mi进行预读,Δ参数即为预读的Stride。第一次预读地址A3 = a2 +Δ,其中A3为预测值,如果预测与实际的a3相同,则继续预测,直到An ≠ an。采用这种实现方法,需要使用历史地址信息和最后一次检测成功的Δ参数,为此在硬件上需要设置一个RPT(Reference Prediction Table)RPT的组成结构与Cache类似,如56所示。

5.3 <wbr>硬件预读

RPT由微架构的PC进行索引。当指令mi第一次执行时,将从RPT中分配一个空闲Entry,填写相应的Instruction TagPrevious Address,并将state设置为initial状态。当指令mi第二次执行时,并在RPT中命中时,将根据当前的EAPrevious Address计算Atride参数后填入当前Entry,并将State设置为Transient状态。

此时如果地址(Effective Adderss+Stride)所指向的数据没有在Cache中命中,进行Tantative Prefetch操作。当指令mi第三次执行时,在RPT中命中,而且A3与实际的a3相同时,表示发生了一次Correct stride Prediction,此时继续进行下一个地址的预读,同时将State改写为Steady。在RPT中,State的状态迁移如57所示。

5.3 <wbr>硬件预读

根据57的状态迁移关系,我们考察以下实例,如58所示。其中左图为一个3-Nested Loop Iterations,并对数据a进行赋值操作,其中数组abc使用的Stride参数并不相同。但是在一下程序中,数据abc使用的Stride参数依然具有强烈的规律性,在RPT中分别保存着这些规律,从而在一定程度上提高了预读的准确性。

5.3 <wbr>硬件预读

假设数组a, bc的基地址分别以10,000, 20,00030,000对界。在第一次进行运算时,通过计算可以在RPT表中记录相应的Previoud Address,数组abcStride参数为初始值0,而State为初始状态Initial

在第一次Iteration之后,RPT表中的数组bcStride分别为4400(Current AddressPrevious Address之差)State改变为Transient,并开始预读之后的Cache Block,而通过计算数组aStride0,与之前的值相同,State改变为Steady,即不进行预读;在第二次Iteration之后,RPT中的数组b, ca发现Stride没有再次发生变化时,State改变为Steady,开始稳定地进行预读。

在第一重循环k执行完毕后,由于k的变化,将使RPT的数组c进入Initial状态,重新进入准备阶段;第二重循环j执行完毕后,由于j的变化,将使RPT的数组ac进入Initial状态,重新进入准备阶段;第三重循环i执行完毕后,由于i的变化,将使RPT的数组ab进入Initial状态,重新进入准备阶段。

周而复始,直到三重循环完全执行完毕。

采用这种硬件预读方法,可以有效解决在Loop Iterations中数据的Stride问题。在进一步考虑了Prefetch Distance,即δ参数的基础上,Lookahead data prefetching算法可以在此基础上继续优化,可以设置一个LA-PC(Lookahead Program Count)。此时预读的地址Prefetch Address等于Effective Addess + (Stride × δ)LA-PCPC的差值即为δ

在某些情况下,基于RPT的预读机制并不能理想地处理Triangle-Shaped Loop,这种Loop访问Stride值的计算不但与自身有关,而且与相邻的Loop直接相关。采用Correlated Reference Prediction预读机制[103]可以有效解决这一问题。

该机制的实现要点是除了关注在一个Loop内的数据访问轨迹之外,还关心相邻的Loop,以实现对Triangle-Shaped Loop的预读。为此在56中需要加入另外一组Prev AddressStride参数,对此有兴趣的读者可参阅[103]以获得更详细的信息。

无论是软件还是硬件Prefetch的实现方式,都不可避免地出现Prefetch得来的数据并没有被及时使用,从而会在一定程度上一定程度上的重复,这种重复会进一步提高系统功耗,对于有些功耗敏感的应用,需要慎重使用Prefetch机制。Prefetch机制除了对系统有较大影响之外,还会引发一定程度的Cache Pollution。这使得Stream buffer[20]机制因此引入。

0

阅读 收藏 喜欢 打印举报/Report
前一篇:5.2 软件预读
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有