改进Cache的性能

Cache性能分析

虽然平均访存时间(平均访存时间 = 命中时间+不命中率×不命中开销)是一个比命中率更好的指标,但仍然是衡量性能的一个间接指标。执行一个程序所需的CPU时间能更好的反映存储系统的性能

最终方案:计算程序执行的CPU时间

假设所有的访存停顿都是由Cache不命中引起的,这是因为和IO设备使用存储器引起的竞争从而引发停顿相比,不命中引起的停顿占大多数

注意:IC = 指令数,不命中开销的单位是时钟周期数

上图中用红色中括号括起来的部分可看作考虑了cache不命中后的CPI

改进Cache的性能

因为平均访存时间=命中时间+不命中率×不命中开销

所以可以从三个方面改进Cache的性能

  • 降低不命中率(介绍8种)
  • 减少不命中开销(介绍5种)
  • 减少Cache命中时间(介绍4种)

三种类型(3C)的不命中-降低不命中率

强制性不命中(Compulsory miss)

当第一次访问一个块时,该块不在Cache中,需从下一级存储器中调入Cache,这就是强制性不命中。(冷启动不命中,首次访问不命中)

容量不命中(Capacity miss)

如果程序执行时所需的块不能全部调入Cache中,则当某些块被替换后,若又重新被访问,就会发生不命中。这种不命中称为容量不命中。

冲突不命中(Conflict miss)

在组相联或直接映像Cache中,若太多的块映像到同一组(块)中,则会出现该组中某个块被别的块替换(即使别的组或块有空闲位置),然后又被重新访问的情况。这就是发生了冲突不命中。 (颠簸、碰撞不命中,干扰不命中)


解决强制性不命中:增加块大小,预取

解决容量不命中:除了增加cache行(扩容)别无他法,提高相联度对容量不命中无效

解决冲突不命中:可以增加cache行,提高相联度

许多降低不命中率的方法会增加命中时间或不命中开销

1.增加cache块大小-降低不命中率

  • 对于给定的Cache容量,当块大小增加时,不命中率开始是下降,太大就会上升
  • 减少了强制性不命中,cache容量一定时,由于增加块大小会减少Cache中块的数目,所以有可能会增加冲突不命中
  • 增加块大小会增加不命中开销 ,因为不命中时,从主存搬的数据就多,平均访存时间就多了

2.增加cache容量-降低不命中率

  • 这是最直接的方法,只会增加成本,这种方法在片外Cache中用得很多

3.提高相联度-降低不命中率

  • 采用相联度超过8的方案的实际意义不大
  • 2:1Cache经验规则 :容量为N的直接映像Cache的不命中率和容量为N/2的两路组相联Cache的不命中率差不多相同
  • 提高相联度是以增加命中时间(hit time)为代价。为了减少命中时间,就要求实现更高的处理器时钟频率,需要设计结构简单的cache。但时钟频率越高,不命中开销越大(所需时钟周期数越多)。为减少不命中开销,又要求提高相联度(增加命中率)

4.伪相联cache-降低不命中率

而伪相联可以同时拥有两个优点:命中时间小 、不命中率低

缺点是伪相联cache具有一快一慢两种命中时间,优化方式是当出现伪命中时交换两个块的内容,把最近刚访问过的块放到第一位置上,以减少未命中次数(局部性原理)

5.硬件预取-降低不命中率

  • 指令和数据都可以预取
  • 预取内容既可放入Cache,也可放在外缓冲器中
  • 指令预取通常由Cache之外的硬件完成
  • 预取应利用存储器的空闲带宽,不能影响对正常不命中的处理,否则可能会降低性能
  • 流缓冲器:既能预取指令又能预取数据 。对于两个64KB四路组相联Cache来说,8个流缓冲器能捕获50%~70%的不命中

6.编译器控制的预取-降低不命中率

  • 没有额外硬件,就是cache本身自带的预取功能
  • 在编译时加入预取指令,在数据被用到之前发 出预取请求,取到寄存器或cache中
  • 在预取数据的同时,处理器应能继续执行。 只有这样,预取才有意义。这种灵活的cache叫做非阻塞Cache(预取与提供指令并行,处理不命中与提供后续命中指令并行)
  • 每次预取需要花费一条指令的开销 ,要保证这种开销不超过预取所带来的收益

7.编译优化-降低不命中率

  • 无需对硬件做任何改动,通过编译器对程序代码和数据的重组来降低不命中率
  • 把基本块对齐,使得程序的入口点与Cache块的起始位置对齐,就可以减少顺序代码执行时所发生的Cache不命中的可能性
  • 如果编译器知道一个分支指令很可能会成功转移,那么它就可以通过以下两步来改善空间局部性: ①将转移目标处的基本块和紧跟着该分支指令后的基本块进行对调; ②把该分支指令换为操作语义相反的分支指令

编译优化技术包括

  • 数组合并(将本来相互独立的多个数组合并成为一个复合数组,以提高它们的空间局部性)
  • 内外循环交换(列优先访问变为行优先访问,使程序按数据在存储器中存储的顺序进行访问,提高的是空间局部性)
  • 循环融合(将若干个独立的循环融合为单个的循环。这些循环访问同样的数组,对相同的数据作不同的运算。这样能使得读入Cache的数据在被替换出去之前,能得到反复的使用,提高的时间局部性)
  • 分块(把对数组的整行或整列访问改为按块进行,使一个cache块在被替换之前最大限度的利用它,提高的是时间局部性)

8.牺牲Cache-降低不命中率

  • 一种能减少冲突不命中次数而又不影响时钟频率的方法
  • 在Cache和它从下一级存储器调数据的通路之间设置一个全相联的小Cache,称为牺牲Cache(Victim Cache)。用于存放被替换出去的块(称为牺牲者),以备重用
  • 对于减小冲突不命中很有效,特别是对于小容量的直接映像数据Cache,作用尤其明显
  • 这里把牺牲cache归类为减少不命中的方法是因为把牺牲cache看作cache的拓展,即把被替换后的在牺牲cache中找到的数据也算是命中

1.多级cache-减少不命中开销

局部不命中率 = 该级Cache的不命中次数 / 到达该级Cache的访问次数

全局不命中率 = 该级Cache的不命中次数 / CPU发 出的访存的总次数

对于第二级Cache,有以下结论

  • 在第二级Cache比第一级 Cache大得多的情况下,两级Cache的全局不命中率和容量与第二级Cache相同的单级Cache的不命中率非常接近。
  • 局部不命中率不是衡量第二级Cache的一个好指标,因此,在评价第二级Cache时,应用全局不命中率这个指标
  • 第二级Cache的容量一般比第一级的大许多。 大容量意味着第二级Cache可能实际上没有容量 不命中,只剩下一些强制性不命中和冲突不命中
  • 第二级Cache可采用较高的相联度或伪相联方法,减少冲突不命中
  • 第二级Cache可采用较大的块,以减小强制性不命中
  • 第二级cache命中率比第一级小得多,所以重点放在减少不命中次数上

2.让读不命中优先于写-减少不命中开销

  • Cache中的写缓冲器导致的问题:在读不命中时,所读单元的最新值有可能还在写缓冲器中,尚未写入主存
  • 解决问题的方法(读不命中的处理) :①推迟对读不命中的处理直至写缓冲器清空 (缺点:读不命中的开销增加)② 检查写缓冲器中的内容,如果没有再访存,如果有就读写缓冲器的内容
  • 实际几乎是采用第二种方法,即让读不命中优先于写

3.写缓冲合并-减少不命中开销

  • 如果写缓冲器为空,就把数据和相应地址写入该缓冲器
  • 如果写缓冲器中已经有了待写入的数据,就要把这次的写入地址与写缓冲器中已有的所有地址进行比较,看是否有匹配的项。如果有地址匹配(连续地址,非相同地址)而对应的位置又是空闲的,就把这次要写入的数据与该项合并。这就叫写缓冲合并
  • 如果写缓冲器满且又没有能进行写合并的项,就必须等待
  • 提高了写缓冲器的空间利用率,而且还能减少因写缓冲 器满而要进行的等待时间

4.请求字优先-减少不命中开销

  • 请求字 :从下一级存储器调入Cache的块中,只有一个字 是立即需要的。这个字称为请求字
  • 尽早重启动:调块时,从块的起始位置开始读起,CPU处于等待状态,一旦请求字到达,就立即发送给CPU,让CPU继续执行
  • 请求字优先(requested word first):调块时,从请求字所在的位置读起。这样,第一个读出的字便是请求字。将之立即发送给CPU
  • 一般来说,这种技术只有在cache块很大时才有效,因为当cache块较小时,用不用这个技术不命中开销差别不大

5.非阻塞cache-减少不命中开销

  • 允许指令乱序执行时,CPU无需在cache不命中时停顿,它可以在等cache给出数据的同时执行后面的指令
  • 非阻塞cache就是能在不命中时仍允许cpu进行其他命中的访问
  • 简 单的“一次不命中下命中”就能充分的减少不命中开销了

1.容量小结构简单的cache-减少命中时间

  • 硬件越简单,速度就越快; 应使一级Cache足够小,以便可以与CPU一起放在同一块芯片上
  • 某些设计采用了一种折中方案:把Cache的标识放在片内,而把Cache的数据存储器放在片外。这样既能实现快速标识检测,又能利用独立存储芯片提供更大的容量
  • 采用直接映像cache也能减少命中时间,因为可以让标识检测和数据传送并行

2.虚拟cache-减少命中时间

  • 可以直接用虚拟地址进行访问的Cache。标识存储器中存放的是虚拟地址,进行地址检测用的也是虚拟地址
  • 在命中时不需要地址转换,省去了地址转换的时间。即使不命中,地址转换和访问Cache也是并行进行的,其速度比物理Cache快很多

  • 然而也有问题:每当进程切换时需要清空cache,因为新进程的某些访存虚拟地址可能与原进程相同,但它们指向的物理空间却是不同的
  • 解决上述问题的办法:在cache的tag字段中增加PID字段 ,由PID指出cache中的各块属于哪个程序
  • 虚拟cache没有流行起来的另一个原因是,操作系统和用户程序对于同一个物理地址可能采用两种以上不同形式的虚拟地址来访问,这些地址称为同义或别名,它们会导致同一个数据在虚拟cache中存在两个副本,而这是不允许的,否则会发生错误
  • 用软件的办法解决别名问题很容易,只要要求别名的某些地址位相同。例如:SUN公司的UNIX要求所有别名的地址的最后18位都相同。这种限制被称为页着色(page coloring)。这一限制使得容量不超过2^18B(256KB)的直接映像cache不可能出现一个cache块有重复物理地址的情况。所有别名被映像到同一cache块位置
  • 对于虚拟地址,还应考虑IO,IO通常使用物理地址,所以为了与虚拟cache打交道,需要把物理地址反映射为虚拟地址
  • 实际用的更多的是虚拟索引+物理标识这个方案,兼得虚拟Cache和物理Cache的好处,如下图
  • 直接用虚地址中的页内位移(页内位移在虚实地址转换中保持不变)作为访问cache的索引(index),但标识(tag)却是物理地址。CPU发出访存请求后,进行虚实地址转换的同时,可并行进行标识(tag)的读取,在完成地址转换后,再把得到的物理地址与标识(tag)进行比较
  • 这种方法的局限性是cache容量不能超过页面大小(直接映射的情况)
  • 为了实现大容量的cache,可以使每个索引对应的cache Line增加,即提高相联度

3.cache访问流水化-减少命中时间

  • 对第一级Cache的访问按流水方式组织 ,访问Cache需要多个时钟周期才可以完成
  • 这样处理的好处是可以提高时钟频率
  • 实际上它并不能真正减少cache命中时间,但可以提高访问cache的带宽

4.踪迹cache-减少命中时间

  • 开发指令级并行性所遇到的一个挑战是:当要每个时钟周期流出超过4条指令时,要提供足够多条彼此互不相关的指令是很困难的
  • 一个解决方法:采用踪迹Cache存放CPU所执行过的动态指令序列,包含了由分支预测展开的指令,该分支预测是否正确需要在取到该指令时进行确认
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值