关于Cache的一点点小结

为什么引入Cache?

因为IO设备向主存请求的级别高于cpu,会出现cpu等待IO访问cpu的情况,进而导致cpu使用效率的降低。解决主存和cpu速度不匹配的问题。

Cache依赖的原理?

时间局部性:近期要访问的数据很可能是现在要访问的数据,因为有循环。
空间局部性:近期要访问数据的所在地址,很可能就是现在访问数据地址的附近。

Cache和主存的映射方式

cache里面的数据实际上就是主存数据的一份复制。那么主存的数据该怎么放进cache中,引出映射的不同方式。而为存入cache里面的块为了与主存的块保持对应,还需要加上标记。还需要添加有效位来保存当前cache块的状态。

标记:用于指出在cache里面的是主存的哪一块的副本。
例如:cache 中有 0 1 2 3 ,此时cpu要访问主存的第4块和第8块数据,主存里第四块数据如果根据组相连映射法,4将映射到cache的第(4mod4=0)组,8将映射到cache的第(8mod4=0)组.这时候如果不加上一个标识,那都分不清楚4和8在cache里第0组里面谁是谁了,因为他们都是0。

有效位:为1:该块已经放了。为0:没放。

1、直接映射

主存里面的每一块只可以放在cache里固定的位置,不能放别人那。后来的、产生冲突的块,直接把原来的踢走。

j:Cache块号
i:主存块号
c:Cache总块数

直接映射的关系: j = i mod c

地址结构

标记Cache行号块内地址

cache命中:
1、首先找到地址结构中的cache行号对应的在cache里内容。
2、根据该cache块的标记位与主存的标记位来进行比较。
3、如果相等并且有效位=1,则说明cache命中。

cache未命中:
1、从cpu内读取所需要数据在主存中的位置。
2、找到以后读出信息,同时送去对应的cache行,还要把信息送至cpu

优点:实现简单。
缺点:空闲块利用率较低,块冲突的概率高。不够灵活。

2、全相联映射

主存的每一块可以放进cache中空闲的任意一个位置。cpu访存时需要和所有的cache行的标记进行比较,因为它的放置与主存的位置之间没有规律可循。

地址结构:

标记块内地址

优点:冲突概率低,提高了空闲块的利用率,命中率较高。
缺点:标记的比较速度比较慢,实现成本高,通常要用昂贵的相联存储器来进行地址映射。

3、组相联映射

结合全相联映射和直接映射的方式,将cache进行分组,主存里的每一块固定对应cache的某一组,不能去别的组。而组内是使用了全相联映射的方式,组内随机存放。

二路组相联--------将cache分成2块为一组

(主存地址块号)mod(cache的分组数)= 该块在cache当中的所在组号。

地址结构

标记组号块内地址

路数越多则冲突概率越低,但是路数越多也就以为着电路的设计更加的复杂。成本接近直接映射,性能接近全相联映射。

Cache主存块的替换算法

当cache已经存满了的时候,该如何选择被换出的cache块?

1、随机算法

随机从cache里面挑选一名幸运的人被换出去,可惜没依据程序访问的局部性原理,因为随机挑一个有可能是工作人员,他要一直被使唤干活的(即该块使用率较高)。命中率比较低。

2、先进先出算法(堆栈类算法)

从cache里面选最开始就来了的人,谁先到谁先滚蛋。也不是很好,因为如果是工作人员,那他最早来的cache被换走了就很麻烦。因为他比较忙,可能经常是要使唤去干活的。因此也没有依据程序访问的局部性原理

3、最近最少使用算法(堆栈类算法)

选cache里面近期没有被使唤的工作人员换出,稍微合理了些,依据了局部性原理。那么系统是怎么知道cache里面谁被使唤的时间最少呢?
对cache每个工作人员设置一个计数器,每当一个工作人员被使唤一次则计数器归0,比他低的+1。
抖动:集中访问的存储区超过cache组的大小时,命中率可能变得非常低。

4、最不经常使用算法

将一段时间内访问次数最少的块进行换出操作,设置计数器,使用一次便++,最后计数器值最小的就是最不经常使用的。

Cache写策略

在通过cache进行访问数据的时候,难免会有数据出现修改要写回主存的情况,那么对于写回主存又有以下几种策略。

cache命中:

1、全写法:当cpu对cache写命中时,必须把数据同时写入内存

但是由于写回cpu写回主存的速度和写回cache的速度不匹配(写回主存更加慢),所以添加一个写缓冲(FIFO队列),cpu把要修改的数据给了cache和缓冲池以后就去干别的事情,由缓冲自己慢慢写回主存。但是如果频繁写入的话容易造成写缓冲溢出。

优点:随时保持数据的正确性
缺点:增加了访存的次数,降低了cache的效率

2、写回法:cpu命中后修改cache里面的数据,并不会立即写回主存,只有在这一块被换出去的时候才会去看这块是否修改了,才决定要不要写回主存。

那么怎么确定该块是否被修改了?
设置脏位,脏位=1,修改了,反之没有被修改。

cache不命中

1、写分配法

加载主存的块到cache里面,更新这个cache块。缺点是每一次不命中都要去主存里面读取一块。通常配合写回发使用,因为调块去了cache里面就意味着将会被命中,则也是设置脏位

2、非写分配法

只写入主存,不进行调块


版权声明:本文为yliyp原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。