想找可以在家做的手工活去什么网站,网站开发 ip6,吉林网站制作选择乐云seo,iis网站wordpress登陆课程链接#xff1a; 计算机组成_北京大学_中国大学MOOC(慕课) 7 - 5 - 705-高速缓存的工作原理#xff08;16-00--#xff09;_哔哩哔哩_bilibili 在【计算机组成 课程笔记】7.1 存储层次结构概况_Elaine_Bao的博客-CSDN博客中提到#xff0c;因为CPU和内存的速度差距越来… 课程链接 计算机组成_北京大学_中国大学MOOC(慕课) 7 - 5 - 705-高速缓存的工作原理16-00--_哔哩哔哩_bilibili 在【计算机组成 课程笔记】7.1 存储层次结构概况_Elaine_Bao的博客-CSDN博客中提到因为CPU和内存的速度差距越来越大使得计算机的性能受到了影响而高速缓存的出现则挽救了这一局面。这一节我们就来看一下高速缓存是如何工作的。
这是CPU的存储层次结构高速缓存也就是Cache位于CPU和DRAM主存之间相比于主存它的容量要小得多但速度要快得多。
但是为什么在CPU和主存之间增加这么一个速度更快但是容量很小的存储部件就能提升整个计算机系统的性能呢这就要得益于计算机中运行程序的一个特点这个特点被称为程序的局部性原理。
程序的局部性原理
这是一个常见的程序有两层循环对一个二维数组进行累加。如果sum这个变量是保存在内存中的那么这个存储单元就会被不断访问这就称为时间局部性。类似地这些对循环变量进行判断条件的指令和对循环变量递增的指令也会被反复执行。
另一点叫做空间局部性。指的是正在被访问的存储单元附近单元也很快会被访问。例如a[0][0]附近的a[0][1],a[0][2]也会很快被访问。 Cache的基本原理
Cache就是利用了程序的局部性原理设计出来的。
首先我们来看Cache对空间局部性的利用。当CPU要访问主存时实际上是把地址发给了Cache最开始Cache里是没有数据的所以它会再把地址发给主存再从主存中取得对应的数据。但Cache并不会只取回当前需要的数据而是会把与这个数据相邻的主存单元的数据一并取回来这些数据就被称为一个数据块block。Cache取回数据块以后存在自己内部再选出CPU需要的那个数据传给CPU。那过一会CPU很可能就需要刚刚那个数据附近的其他数据这时候Cache里面已经有了就可以很快地返回从而提升访存效率。
再来看一下Cache对时间局部性的利用。因为刚才这个数据块暂时会保存在Cache当中那CPU如果要再次用到刚才用过的那个存储单元Cache也可以很快地提供。 这就是Cache对程序局部性的利用。我们要注意这些操作都是由硬件完成的对于软件编程人员来说他编写的程序代码当中只是访问了主存当中的某个地址而并不知道这个地址对应的存储单元到底是放在主存当中还是Cache当中。
Cache的访问过程
现在CPU放松读请求都是直接发给CacheCache这个硬件部件会检查数据是否存在Cache当中根据是否命中hit/miss来决定是否需要向主存发送读请求——这个过程是由Cache发起的CPU是不知情的它仍然在等待Cache返回数据。 Cache组织结构示例
Cache的主要组成部件是SRAMSRAM的组织结构很像这个表格会分为很多行每行当中有一个bit是有效位还有若干bit是标签其他bit用于存储从主存取回的数据块这个例子中数据块是16字节。 Cache的读操作
我们来看一个具体的读操作过程示例。假设一开始Cache全是空的有效位为0代表对应行没有数据。现在我们要来执行这4条指令。 MOV AL, [2011H]
第一步我们要访问2011H这个地址并取出对应的字节放在AL寄存器中。CPU把2011H这个地址发给Cache而现在因为Cache全是空的所以显然没有命中那么Cache就会向内存发起一次读操作的请求。但我们要注意因为Cache一次要从内存中读取一个数据块而现在这个Cache的结构一个数据块是16字节所以它发出的地址都是16个字节对齐的所以它向主存发出的地址是2010H。读回数据块后分配的Cache Line是第一行表项1这时候表项1中的字节0存的是2010H的数据字节1存的是2011H的数据所以把字节1的A1H返回给CPU。
那么这里为什么分配的Cache Line是第一行呢Cache从CPU收到的地址是2011H而由于Cache是以块为单位进行存储的所以2011H中的最后一位正好用来表示在这一行中的索引。剩下的倒数第二位则正好可以用于选取Cache Line在这个例子中这个数是1所以Cache决定放在表项1中。剩下的还有两位地址20H则作为标签存储起来。 MOV BL, [4011H]
Cache收到4011这个地址后首先查看表项1是否有数据。有效位是1说明是有数据的但是标签对应的是20H和当前需要的40H不同所以还是未命中Cache还是向主存发出访存请求发出的访存地址是4010H。读回数据以后替换表项1并将4011H对应的数据B1H返回给CPU这条指令就完成了。 MOV CL, [3732H]
这条指令会去查看Cache中的表项3是否有数据发现没有数据。接下来的过程和第1条指令类似。 MOV DL, [401FH]
Cache首先找到对应的表项1有效位为1说明有数据。下一步是比较标签也是40H说明是所需要的Cache Line确认Cache hit。最后再根据最低位F找到对应数据BFH返回给CPU。 现在我们就了解了Cache读操作的几种典型情况
1. 没有命中且对应表项是空的情况。
2. 没有命中但是对应表项已经被占用的情况。
3. 命中了的情况。
那看完了读我们再来看一下Cache的写操作。
Cache的写策略
当CPU要写一个数据的时候也会先送到Cache这时也会有命中和失效两种情况。
当Cache命中时可以采取的一种写策略是写穿透即同时写入Cache和主存中这样能保证数据的一致性但因为访问主存速度较慢所以这种写策略效率较低。
所以还可以采用另一种写策略叫做写返回即数据只写入Cache只在该数据块被替换时才将数据写入主存。这样的性能显然会好些因为有可能对同一个单元进行连续多次的写这样只需要将最后一次写的结果在替换时写回主存就可以了大大减少了访问主存的次数。但要完成这样的功能Cache这个部件就会变得复杂得多。
同样的在Cache失效时也有两种写策略。一种叫做写不分配因为Cache失效要写的那个存储单元不在Cache当中所以直接写入主存。
另一种策略叫做写分配就是先将这个数据块读入Cache然后将数据写入Cache中。写不分配的策略实现简单但是性能不太好而写分配的策略虽然第一次操作时复杂一些要把数据先读到Cache里但是根据局部性原理这个数据块后面很可能还会被用到所以会让后续的访存性能大大提升。 所以在现在Cache的设计中写穿透和写不分配往往是配套使用的用于那些对性能要求不高但设计简单的系统对性能要求较高的通常使用写返回和写分配这一套组合的策略。 Cache的设计要点
高速缓存是一个非常精细的部件如果要达到很好的性能需要在设计时进行仔细的权衡。想要设计出一个优秀的高速缓存我们需要从几个基本概念入手。
平均访存时间
以下是Cache的访问过程其中有几个性能指标命中率命中时间失效率和失效代价。 要评价访存的性能经常会用到平均访存时间这个指标。其计算公式如下 那么要减少平均访存时间就有三个途径
1. 降低Hit Time要求Cache的容量小一点Cache的结构简单一点
2. 减少Miss Penalty提升主存的性能或者再增加一层cache
3. 降低Miss Rate增大Cache的容量
可以看出以上三个途径并不是完全独立的我们先来看一下提高命中率即降低失效率这个方面。根据上述假设命中率提升2%可以带来访存效率提升一倍。所以对于Cache来说能够提升一点点命中率都能带来很大的性能提升。
Cache失效原因
那么哪些因素会影响命中率呢或者Cache失效会有哪些原因
一种原因是义务失效这个无法避免。第二种是容量失效可以通过增加Cache容量来缓解但这一方面增加成本另一方面也会影响到命中时间所以也需要综合的考虑。第三种是冲突失效也就是在Cache并没有满的情况下由于将多个存储器的位置映射到了同一Cache Line导致位置上的冲突而带来的失效我们重点来看看如何解决这个问题。 Cache的映射策略
直接映射
例如如果有一个8表项的cache直接映射的情形如图就相当于将内存中的数据块每8个分为一组每一组当中的第0个数据块都会被放在Cache的表项0第1个数据块都会被放在Cache的表项1。 直接映射的优点在于硬件结构简单只要根据地址就能知道对应的数据块应该放在哪个表项。缺点是如果交替的访问两个数据a,b而这两个数据对应的数据块恰好被映射到了同一个表项中那就会一直cache miss这样的访存性能还不如没有Cache而这时候其实Cache中的其他表项都是空闲的。
N路组相联
为了解决直接映射的问题我们可以做一些改进在不增加cache总的容量的情况下我们可以将这8个Cache行分为两组这就是二路组相联的Cache。这样刚才那种交替访问a,b的情况a可以被放在第一行第一个位置然后b被放在第一行第二个之后在访问a,b时都能cache hit。
当然如果CPU在交替访问a,b,c的话二路组相联就不行了又会出现连续不命中的情况所以我们还可以对它进一步切分如四路组相联。
那我们是不是可以无限切分下去呢可以是可以比如对于上述Cache的大小全部展开可以得到八路组相联也就是说内存当中任一个数据块都可以放到这个Cache当中的任何一个行中 而不用通过地址的特征来约定固定放在哪一个行那这样结构的Cache就叫做全相联的Cache。这样的设计灵活性显然是最高的但它的控制逻辑也会变得非常复杂比如假设CPU发来一个地址Cache要判断这个地址是否在自己内部对于直接映射的Cache只需要比较一行的标签就可以了那在全相联的情况下它就需要比较所有Cache行的标签。这样的比较需要使用大量的硬件电路既增加了延迟又增加了功耗。所以如果划分的路数太多虽然降低了失效率但是增加了命中时间这样就得不偿失了。而且话又说回来增加了路数还不一定能够降低失效率还跟替换策略有关。
Cache替换算法
现在常见的Cache替换算法有这几种。在实际使用中LRU的性能表现比较好但其硬件设计也相当的复杂所以映射策略和替换算法都需要在性能和代价之间进行权衡。 Cache设计实例