Cache基本原理、基本概念

Cache工作原理

3.5Cache_全相联映射


3.5Cache_主存_02


局部性原理

3.5Cache_主存_03


空间局部性:在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上是邻近的 (数组元素、顺序执行的指令代码)

时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息 (循环结构的指令代码)基于局部性原理,不难想到,可以把CPU目前访问的地址“周围”的部分数据放到Cache中

程序B按“列优先”访问二维数组,空间局部性更差

性能分析

3.5Cache_全相联映射_04


3.5Cache_数据_05


3.5Cache_主存_06


3.5Cache_数据_07


如何区分Cache与主存的数据块对应关系?

Cache和主存的映射方式

Cache很小,主存很大。如果Cache满了怎么办?

替换算法

CPU修改了Cache中的数据副本,如何确保主存中数据母本的一致性?

Cache写策略

Cache和主存的映射方式

全相联映射

3.5Cache_数据_08


主存块可以放在Cache的任意位置

(b)直接映射

3.5Cache_全相联映射_09


每个主存块只能放到一个特定的位置

Cache块号=主存块号% Cache总块数

©组相联映射

3.5Cache_开发语言_10


Cache块分为若干组,每个主存块可放到特定分组中的任意一个位置

组号=主存块号%分组数

全相联映射(随意放)

假设某个计算机的主存地址空间大小为256MB,按字节编

址,其数据Cache有8个Cache行,行长为64B。

Cache行:即Cache块,与主存块的大小相等

3.5Cache_主存_11


3.5Cache_数据_12


实现映射

3.5Cache_开发语言_13

3.5Cache_开发语言_14

直接映射(只能放固定位置)

假设某个计算机的主存地址空间大小为256MB,按字节编

址,其数据Cache有8个Cache行,行长为64B。

直接映射,主存块在Cache中的位置=主存块号%Cache总块数

3.5Cache_主存_11


3.5Cache_开发语言_16


3.5Cache_主存_17


3.5Cache_全相联映射_18


3.5Cache_数据_19


3.5Cache_数据_20

组相联映射(可放到特定分组)

假设某个计算机的主存地址空间大小为256MB,按字节编

址,其数据Cache有8个Cache行,行长为64B。

3.5Cache_主存_11


组相联映射,所属分组=主存块号%分组数

3.5Cache_主存_22


3.5Cache_数据_23


3.5Cache_主存_24


3.5Cache_数据_25

3.5Cache_数据_26

Cache替换算法

随机算法(RAND)

随机算法(RAND,Random)――若Cache已满,则随机选择一块替换。

设总共有4个cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}

3.5Cache_开发语言_27

随机算法――实现简单,但完全没考虑局部性原理,命中率低,实际效果很不稳定

先进先出算法(FIFO)

先进先出算法(FIFO,First In First Out)—-若Cache已满,则替换最先被调入Cache的块

设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块 {1,2,3,4,1,2,5,1,2,3,4, 5}

3.5Cache_主存_28


先进先出算法――实现简单,最开始按#O#1#2#3放入Cache,之后轮流替换#O#1#2#3

FIFO依然没考虑局部性原理,最先被调入Cache的块也有可能是被频繁访问的

抖动现象:频繁的换入换出现象(刚被替换的块很快又被调入)

近期最少使用算法(LRU)

近期最少使用算法(LRU, Least RecentlyUsed )–为每一个Cache块设置一个“计数器”,用于记录每个Cache块已经有多久没被访问了。当Cache满后替换“计数器”最大的
设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}
①命中时,所命中的行的计数器清零,比其低的计数器加1,其余不变;
②未命中且还有空闲行时,新装入的行的计数器置0,其余非空闲行全加1;
③未命中且无空闲行时,计数值最大的行的信息块被淘汰,新装行的块的计数器置0,其余全加1。

3.5Cache_全相联映射_29


3.5Cache_开发语言_30


3.5Cache_开发语言_31


3.5Cache_数据_32


3.5Cache_数据_33


LRU算法――基于“局部性原理”,近期被访问过的主存块,在不久的将来也很有可能被再次访问,因此淘汰最久没被访问过的块是合理的。LRU算法的实际运行效果优秀,Cache命中率高。

若被频繁访问的主存块数量>Cache行的数量,则有可能发生“抖动”,如:1,2,3,4,5,1,2,3,4,5,1,…]

最不经常使用算法(LFU)

最不经常使用算法(LFU, Least Frequently Used )—-为每一个Cache块设置一个“计数器”,用于记录每个cache块被访问过几次。当Cache满后替换“计数器”最小的

设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}

新调入的块计数器=O,之后每被访问一次计数器+1。需要替换时,选择计数器最小的一行

3.5Cache_主存_34


3.5Cache_开发语言_35


3.5Cache_数据_36


LFU算法―一曾经被经常访问的主存块在未来不一定会用到(如:微信视频聊天相关的块),并没有很好地遵循局部性原理,因此实际运行效果不如LRU

Cache写策略

写命中

写回法(write-back)——当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存

减少了访存次数,但存在数据不一致的隐患。

3.5Cache_全相联映射_37

全写法(写直通法,write-through)——当CPU对Cache写命中时,必须把数据同时写入cache和主存,一般使用写缓冲(write buffer)

访存次数增加,速度变慢,但更能保证数据一致性

3.5Cache_全相联映射_38


使用写缓冲,CPU写的速度很快,若写操作不频繁,则效果很好。若写操作很频繁,可能会因为写缓冲饱和而发生阻塞

3.5Cache_全相联映射_39

写不命中

写分配法(write-allocate)——当CPU对Cache写不命中时,把主存中的块调入Cache,在Cache中修改。通常搭配写回法使用。

写回法(write-back)——当CPU对Cache写命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存

3.5Cache_主存_40

只有“读”未命中时才调入Cache

非写分配法(not-write-allocate)——当CPU对Cache写不命中时只写入主存,不调入Cache。搭配全写法使用。

全写法(写直通法,write-through)——当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓冲(write buffer)

3.5Cache_开发语言_41

多级Cache

3.5Cache_全相联映射_42

现代计算机常采用多级Cache

离CPU越近的速度越快,容量越小

离CPU越远的速度越慢,容量越大