高速缓存
最后更新于:2022-04-02 04:04:37
[TOC]
## 高速缓存的工作原理
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/be/90/be90a786f8c14c8c060d308156dd8499_1158x296.png)
1. CPU需要的数据在缓存里
2. CPU需要的数据不在缓存里
3. 不在缓存的数据需要去主存拿
## 主存原理
- **字**:是指存放在一个存储单元中的二进制代码组合
- **字块**:存储在连续的存储单元中而被看作是一个单元的一组字
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/48/df/48df7bb77032ba75d3556d3cad06c36a_1646x864.png)
**字的地址**
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/62/db/62db2466644216bbd3ba7ba89a847d29_1530x888.png)
### 思考题
例子:假设主存用户空间容量为4G,字块大小为4M,字长为32位,则对于字地址中的块地址m和块内地址b的位数,至少应该是多少?
```
4G=4096M
求一共的字块数M: 4096/4=1024
字块地址m: 2^m=M -> log2 1024=10 //至少需要10位为才能标识 1024 大小
块内字数 B : 4M / 32 bit = 4*1024*1024*8/32 bit = 1048576 bit
块内地址b: 2^b=B -> log2 1048576=20
m>=10 b>=20
```
## 缓存原理
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/c4/f2/c4f29b30b3352c6df6e911d315447fde_1916x862.png)
缓存原理与主存类似:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/40/50/405046786614632008678ffd182dcb9b_1530x846.png)
### 命中率
- 命中率是衡量缓存的重要性能指标
- 理论上CPU每次都能从高速缓存取数据的时候,命中率为1
### 计算命中率 h
访问主存次数 `$ N_{m} $`:
访问缓存次数 `$ N_{c} $`:
`$ h=\frac{N_{c}}{N_{c}+N_{m}} $`
### 计算访问效率 e
访问主存时间: `$ {t_{m}} $`
访问缓存时间: `$ {t_{c}} $`
访问缓存-主存系统的平均时间:`$ {t_{a}} = h{t_{c}}+(1-h){t_{m}} $`
访问效率 :`$ e=\frac{t_{c}}{t_{a}}=\frac{t_{c}}{h{t_{c}}+(1-h){t_{m}}} $`
### 思考题
例子:假设CPU在执行某段程序时,共访问了 Cache命中2000次,访问主存50次,已知 Cache的存取时间为50ns,主存的存取时间为200ns,求 Cache主存系统的命中率、访问效率和平均访问时间。
命中率:`$ h=\frac{N_{c}}{N_{c}+N_{m}}=\frac{2000}{2000+50}=0.97 $`
访问效率 :`$ e=\frac{t_{c}}{t_{a}}=\frac{t_{c}}{h{t_{c}}+(1-h){t_{m}}}=\frac{50}{0.97*50+(1-0.97)200}=0.917=91.7% $`
平均访问时间`$ 0.97*50+(1-0.97)200=54.5ns $`
## 高速缓存的替换策略
### 随机算法
### 先进先出算法(FFO)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/7c/fc/7cfc8002af65b15e36c6256194a87b9a_1832x742.png)
### 最不经常使用算法(LFU)
- 优先淘汰最不经常使用的字块
- 需要额外的空间记录字块的使用频率
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/5c/77/5c7774ed23bc90c102b39e4f86d93f50_936x608.jpeg)
### 最近最少使用算法(LRU)
- 优先淘汰一段时间内没有使用的字块
- 有多种实现方法,一般使用双向链表
- 把当前访问节点置于链表前面(保证链表头部节点是最近使用的)
```
// 假设缓存4个字块, () 表示使用的字块,[]表示淘汰的字块
(1)
(2),1
(4),2,1
(7),4,2,1
(5),7,4,2->[1]
(4),5,7,2
(6),4,5,7->[2]
(1),6,4,5->[7]
(6),1,4,5
(7),6,1,4->[5]
(4),7,6,1->[4]
(1),4,7,6
```
';