计算机体系结构 第7章 存储系统(4)

第7章 存储系统

7.4 减少Cache不命中开销

7.4.1 采用两级Cache

在Cache和主存之间进行改进,不影响CPU。

思想:

  • 在原有Cache和存储器之间增加一级Cache,构成两级Cache。
  • 第一级Cache做的足够小,速度和CPU匹配
  • 第二级Cache做的足够大,捕获更多本来要对主存的访问,从而降低实际不命中开销

性能分析

  • 原有的平均访存时间公式变为以下形式:

平均访存时间 = 命中时间 L 1 + 不命中率 L 1 × 不命中开销 L 1 \text{平均访存时间}= \text{命中时间}_{L_{1}} + \text{不命中率}_{L_{1}} × \text{不命中开销}_{L_{1}} 平均访存时间命中时间L1不命中率L1×不命中开销L1

不命中开销 L 1 = 命中时间 L 2 + 不命中率 L 2 × 不命中开销 L 2 \text{不命中开销}_{L_{1}}= \text{命中时间}_{L_{2}}+\text{不命中率}_{L_{2}}× \text{不命中开销}_{L_{2}} 不命中开销L1命中时间L2不命中率L2×不命中开销L2

  • 合并可得:

平均访存时间 = 命中时间 L 1 + 不命中率 L 1 × ( 命中时间 L 2 + 不命中率 L 2 × 不命中开销 L 2 ) \text{平均访存时间}= \text{命中时间}_{L_{1}} + \text{不命中率}_{L_{1}} × (\text{命中时间}_{L_{2}}+\text{不命中率}_{L_{2}}× \text{不命中开销}_{L_{2}}) 平均访存时间命中时间L1不命中率L1×(命中时间L2不命中率L2×不命中开销L2)

  • 另一种形式的平均访存时间

T e f f = h 1 t 1 + ( 1 − h 1 ) h 2 t 2 + ( 1 − h 1 ) ( 1 − h 2 ) h 3 t 3 + ⋯ + ( 1 − h 1 ) ( 1 − h 2 ) ⋯ ( 1 − h n − 1 ) h n t n T_{eff} = h_{1}t_{1} + (1 - h_{1})h_{2}t_{2} + (1-h_{1})(1-h_{2})h_{3}t_{3} + \cdots + (1-h_{1})(1-h_{2})\cdots(1-h_{n-1})h_{n}t_{n} Teff=h1t1+(1h1)h2t2+(1h1)(1h2)h3t3++(1h1)(1h2)(1hn1)hntn

​ 其中: h i h_{i} hi是存储器层次结构中任意两个相邻层当在 M i M_{i} Mi找到某一信息项时的概率,称为命中率

局部不命中率与全局不命中率
局部不命中率 = 该级Cache的不命中次数  /  到达该级Cache的访问次数 \text{局部不命中率}= \text{该级Cache的不命中次数}\ /\ \text{到达该级Cache的访问次数} 局部不命中率该级Cache的不命中次数 / 到达该级Cache的访问次数

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

说明:

  • 全局不命中率是比局部不命中率更好的衡量指标,指出来在CPU发出的访存中,有多大比例是穿过各级Cache,最终到达存储器的

  • 评价第二级Cache时,应使用全局不命中率这个指标

全局不命中率 L 2 = 不命中率 L 1 × 不命中率 L 2 \text{全局不命中率}_{L_{2}}=\text{不命中率}_{L_{1}} × \text{不命中率}_{L_{2}} 全局不命中率L2不命中率L1×不命中率L2

每条指令的平均访存停顿时间
每条指令的平均访存停顿时间 = 每条指令的平均不命中次数 L 1 × 命中时间 L 2 + 每条指令的平均不命中次数 L 2 × 不命中开销 L 2 \text{每条指令的平均访存停顿时间} = \text{每条指令的平均不命中次数}_{L_{1}} × \text{命中时间}_{L_{2}}+\text{每条指令的平均不命中次数}_{L_{2}}×\text{不命中开销}_{L_{2}} 每条指令的平均访存停顿时间每条指令的平均不命中次数L1×命中时间L2每条指令的平均不命中次数L2×不命中开销L2

实例1:考虑某一两级Cache:第一级Cache为L1,第二级Cache为L2。

  1. 假设在1000次访存中,L1的不命中是40次,L2的不命中是20次。求各种局部不命中率和全局不命中率。

  2. 假设L2的命中时间是10个时钟周期,L2的不命中开销是100时钟周期,L1的命中时间是1个时钟周期,平均每条指令访存1.5次,不考虑写操作的影响。

问:平均访存时间是多少?每条指令的平均停顿时间是多少个时钟周期?

第一问:

  • 第一级Cache的不命中率:

    • 全局、局部: 40 1000 = 4 % \frac{40}{1000} = 4 \% 100040=4%
  • 第二级Cache的不命中率:

    • 局部: 20 40 = 50 % \frac{20}{40} = 50\% 4020=50%
    • 全局: 20 1000 = 2 % \frac{20}{1000} = 2\% 100020=2%

第二问:

由以下公式可知:
平均访存时间 = 命中时间 L 1 + 不命中率 L 1 × ( 命中时间 L 2 + 不命中率 L 2 × 不命中开销 L 2 ) \text{平均访存时间}= \text{命中时间}_{L_{1}} + \text{不命中率}_{L_{1}} × (\text{命中时间}_{L_{2}}+ \text{不命中率}_{L_{2}}× \text{不命中开销}_{L_{2}}) 平均访存时间命中时间L1不命中率L1×(命中时间L2不命中率L2×不命中开销L2)

  • 命中时间 L 1 = 1 \text{命中时间}_{L_{1}} = 1 命中时间L1=1

  • 不命中率 L 1 = 4 % \text{不命中率}_{L_{1}} = 4\% 不命中率L1=4%

  • 命中时间 L 2 = 10 \text{命中时间}_{L_{2}} = 10 命中时间L2=10

  • 不命中率 L 2 = 50 % \text{不命中率}_{L_{2}} = 50\% 不命中率L2=50%

  • 不命中开销 L 2 = 100 \text{不命中开销}_{L_{2}} = 100 不命中开销L2=100

平均访存时间 = 1 + 4 % × ( 10 + 50 % × 100 ) = 3.4 时钟周期 \text{平均访存时间}= 1 + 4\% × (10 + 50\% × 100) = 3.4 \text{时钟周期} 平均访存时间1+4%×(10+50%×100)=3.4时钟周期

由于平均平均每条指令访存1.5次,每条指令的平均访存停顿时间为: 3.4 − 1 = 2.4 时钟周期 3.4 - 1 = 2.4 \text{时钟周期} 3.41=2.4时钟周期,所以:
每 条 指 令 的 平 均 停 顿 时 间 = 2.4 × 1.5 = 3.6 时钟周期 每条指令的平均停顿时间 = 2.4 × 1.5 = 3.6\text{时钟周期} =2.4×1.5=3.6时钟周期

第二级Cache的相关结论:

  • 在第二级Cache比第一级 Cache大得多的情况下,两级Cache的全局不命中率和容量与第二级Cache相同的单级Cache的不命中率非常接近。
  • 在评价第二级Cache时,应用全局不命中率这个指标。

第二级Cache不会影响CPU的时钟频率,因此其设计有更大的考虑空间。

第一级Cache和第二级Cache之间的首要区别

  • 第一级Cache的速度会影响CPU的时钟频率,而第二级Cache的速度只影响第一级Cache的不命中开销。
  • 因此,在设计第二级Cache时可以有更多的考虑空间,许多不适合于第一级Cache的方案对于第二级Cache可以使用

设计第二级Cache两个问题:

  • 它能否降低CPI中的平均访存时间部分?
  • 它的成本是多少?

第二级Cache的参数

  • 容量
    • 第二级Cache的容量一般比第一级的大许多。大容量意味着第二级Cache可能实际上没有容量
      不命中,只剩下一些强制性不命中和冲突不命中。
  • 相联度
    • 第二级Cache可采用较高的相联度或伪相联方法。

实例2:如果有一个二级Cache,请计算和分析如下问题:

给出有关第二级Cache的以下数据:

  1. 对于直接映象,命中时间 L 2 = 10 L_{2} = 10 L210个时钟周期
  2. 两路组相联使命中时间增加0.1个时钟周期,即为10.1个时钟周期。
  3. 对于直接映象,局部不命中率 L 2 = 25 % L_{2} = 25\% L225%
  4. 对于两路组相联,局部不命中率 L 2 = 20 % L_{2}= 20\% L220%
  5. 不命中开销 L 2 = 50 L_{2} = 50 L250个时钟周期

通过计算和分析说明第二级Cache的相联度对不命中开销的影响如何?

根据公式: 不命中开销 L 1 = 命中时间 L 2 + 不命中率 L 2 × 不命中开销 L 2 \text{不命中开销}_{L_{1}}= \text{命中时间}_{L_{2}}+\text{不命中率}_{L_{2}}× \text{不命中开销}_{L_{2}} 不命中开销L1命中时间L2不命中率L2×不命中开销L2

  • 对一个直接映象的第二级Cache来说,第一级Cache的不命中开销为:

不命中开销 直接映象 , L 1 = 10 + 25 % × 50 = 22.5 个时钟周期 \text{不命中开销}_{\text{直接映象}, L_{1}}= 10 + 25 \% × 50 = 22.5 \text{个时钟周期} 不命中开销直接映象,L110+25%×50=22.5个时钟周期

  • 对于两路组相联第二级Cache来说,命中时间增加了10%*1个时钟周期,故第一级Cache的不命中开销为:

不命中开销 两路组相联 , L 1 = 10 ∗ 1.1 + 20 % × 50 = 20.1 个时钟周期 \text{不命中开销}_{\text{两路组相联}, L_{1}}= 10*1.1 + 20 \% × 50 = 20.1 \text{个时钟周期} 不命中开销两路组相联,L1101.1+20%×50=20.1个时钟周期

由于在实际机器中,第二级Cache几乎总是和第一级Cache以及CPU同步的。因此,第二级Cache的命中时间必须是时钟周期的整数倍。这里把该命中时间取整为11个时钟周期,即:
不命中开销 两路组相联 , L 1 = 21 个时钟周期 \text{不命中开销}_{\text{两路组相联}, L_{1}}= 21 \text{个时钟周期} 不命中开销两路组相联,L121个时钟周期
不难看出,两路组相联比直接映像的效果更好


降低第二级cache的不命中率

可以采用提高相联度伪相联方法来减少第二级Cache的不命中率,从而达到减少不命中开销的目的,因为:

  • 它们对第二级的命中时间影响很小,而且平均访存时间中很大一部分是由于第二级Cache的不命中而产生的。
  • 虽然较大容量的第二级Cache消除了一些冲突不命中(因块数增加了),但它同时也减少了容量不命中,所以在直接映像的第二级Cache中,冲突不命中所占的比例依然很大

对于第二级Cache来说,同样也可以采用增加块大小的方法来减少其不命中率。前面我们已经得出这样的结论:

  • Cache 块的大小增加到一定程度后,反而可能导致不命中率上升。
  • 但对于大容量的第二级Cache来说,这一点并不成为问题,因为它容量大,使其不命中率达到最低的块大小也比较大。64 字节、128字节甚至256字节的块大小都是第二级Cache经常采用的。

第二级Cache的多级包容性

多级包容性:第一级Cache中的数据总是同时存在于第二级Cache中

作用:多级包容性有利于实现I/O和Cache之间的内容一致性检测。

为了减少平均访存时间,可以让容量较小的第一级Cache采用较小的块,而让容量较大的第二级Cache采用较大的块。在这种情况下,仍可实现包容性,但在处理第二级Cache不命中时要做以下工作:

  • 替换第二级Cache中的块时,必须作废所有对应于该块的第一级Cache中的块。这样不但会使第一级Cache的不命中率有所增加,而且会造成不必要的作废操作。
  • 如果结合使用其他一些性能优化技术(如非阻塞的第二级Cache),包容性就会进一步增加复杂度。

总结

  • Cache设计的本质是在快速命中减少不命中次数这两个方面进行权衡。

  • 大部分优化措施都是在提高一方的同时损害另一方。对于第二级Cache而言:

    • 由于它的命中次数比第一级Cache少得多,所以重点就放在减少其不命中次数上。
    • 这就导致了更大容量、更高相联度和块更大的Cache的出现。

7.4.2 让读不命中优先于写

背景:在写直达Cache中,每次写访问都要对主存进行写入。为了提高性能,一般都是设置一个大小适中的写缓冲器,CPU将数据写入写缓冲器后即可继续执行后序指令。

存在的问题:写缓冲器导致存储器访问的复杂化

  • 在读不命中时,所读单元的最新值有可能还在写缓冲器中,尚未写入主存。

解决方法一:

  • 最简单的办法是推迟对读不命中的处理,直至写缓冲器清空。

  • 缺点:由于在发生读不命中时,写缓冲器中几乎总是有数据的,这就增加了处理读不命中的开销。

解决方法二:

  • 在读不命中时检查写缓冲器的内容,如果没有冲突(即没有地址相同)而且存储器可访问,就可继续处理读不命中。即让读不命中优先于写

在写回法Cache的应用

在写回法Cache中,也可以利用写缓冲器来提高性能,假定读不命中将替换一个修改过的存储块:

  • 不先把该块写回存储器,然后再从读存储器调块。

  • 而是把被替换的块临时复制到一个缓冲器中,然后从存储器调块,最后再把缓冲器中的内容写入存储器。

  • 这样CPU的读访问就能更快地完成了。

和上面的情况类似,发生读不命中时,处理器可以采用:

  • 等待缓冲区清空的方法
  • 采用检查与缓冲器中各字的地址是否有冲突的方法

7.4.3 写缓冲合并

背景:

  • 为了减少写访问所花的时间,写直达Cache一般都采用一个写缓冲器。如果该缓冲器不满,就可以把数据和相应地址写人该缓冲器。

  • 从CPU的角度来看,这个写操作就算是完成了,CPU可以继续执行后面的指令,而写缓冲器则负责将其写入存储器。

写缓冲合并

  • 在写缓冲器不为空的情况下,则需要把这次的写入地址与写缓冲器中已有的所有地址进行比较,看是否有匹配的项。
  • 如果有地址匹配而对应的位置又是空闲的,就把这次要写入的数据与该项合并。
  • 如果写缓冲器满且没有能进行写合并的项,则等待。

优点:

  • 提高了写缓冲器的空间利用率
  • 减少因写缓冲器满而等待的时间。

下图给出了采用和不采用写合并的例子。假设写缓冲器有4项,每项能够存放4个64位的字。图中V代表有效位。

  • 当不采用写合并时,写入4个连续存放的数据,就会使写缓冲器满了,3/4的空间被浪费。
  • 采用写合并时,则只需占用一个项。

写缓冲合并

7.4.4 请求字处理技术

与前面减少不命中开销的方法不同,请求字处理技术不用增加硬件

请求字

  • 从下一级存储器调入Cache的块中,只有一个字是立即需要的。这个字称为请求字

当CPU所请求的字到达后,不等整个块都调入Cache,就可把该字发送给CPU并重启CPU继续执行

有两种具体的方案:

  1. 尽早重启动:在请求字没有到达时,CPU处于等待状态。一旦请求字到达,就立即发送给CPU,让CPU尽早重启动,继续执行。
  2. 请求字优先:调块时,让存储器首先提供CPU所要的请求字,请求字一旦到达,就立即送给CPU,让CPU继续执行。同时从存储器调入该块的其余部分。

说明:

  • 一般来说,仅当Cache块很大时才有效。
  • 因为当Cache块较小时,是否使用这些技术,不命中开销差别不大。
  • 此外,在采用请求字优先时,若下一条指令正好访问Cache块的另一部分(以请求字为界,该Cache块被分为两部分),则只能节省一个时钟周期,因为只有得到请求字的指令在流水线中可以继续前进,下一条指令还是必须停下来等待所需的数据。

7.4.5 非阻塞Cache技术

非阻塞Cache:Cache不命中时仍允许CPU进行其它的命中访问。即允许“不命中下命中”。

进一步提高性能(理论上):

  • 让 Cache允许多个不命中重叠
  • 支持“多重不命中下的命中"和“不命中下的不命中",则可进一步减少实际不命中开销。

⚠️说明:

  • 可以同时处理的不命中次数越多,所能带来的性能上的提高就越大。但这并不意味着不命中次数越多越好。
  • 非阻塞Cache大大增加了Cache控制器的复杂度,特别是多重叠的非阻塞Cache,因此,在设计时要做全面综合考虑。

7.4.6 降低Cache不命中开销技术总结

为了描述方便,引入以下记号:

  • “+”号:表示改进了相应指标。
  • “-”号:表示它使该指标变差。
  • 空格栏:表示它对该指标无影响。
  • 复杂性:0表示最容易,3表示最
Cache优化技术总结2——减少不命中开销的方法
优化技术不命中率不命中开销命中时间硬件复杂度说明
使得读不命中优先于写+-1在单处理机上实现容易,被广泛采用
写缓冲合并+1与写直达合用,广泛应用,例如21164,UltraSPARC Ⅲ
两级Cache+2硬件代价大;两级Cache的块大小不同时实现困难;被广泛采用
请求字处理技术+2被广泛采用
非阻塞Cache+3在支持乱序执行的CPU中使用
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值