学习目标
- SRAM和DRAM的构成与区别
- 磁盘存储的结构以及磁盘容量,扇区读取时间的计算
- 认识局部性原理
- 认识存储器结构层次发挥的巨大作用
- 深入理解高速缓存存储器的读取和写入
随机访问存储器
随机存取存储器(RAM,Random-Access Memory)有两种类型:SRAM和DRAM,SRAM非常快,不需要定期刷新,通常用在处理器作缓存,但是比较贵;DRAM需要刷新,通常用作主存。无论是SRAM还是DRAM,一旦不通电,所有的信息都会消失。
静态RAM
SRAM将每个位存储在一个双稳态(bistable)的存储器单元里。
每个单元是用一个六晶体管电路来实现的。它可以无限期地保持在两个不同的电压配置(configuration)或状态(state)之一。
动态RAM
DRAM将每个位存储为对一个电容的充电。
分类 | 每位晶体管数 | 相对访问时间 | 持续的? | 敏感的? | 相对花费 | 应用 |
---|---|---|---|---|---|---|
SRAM | 6 | 1X | 是 | 否 | 100X | 高速缓存存储器 |
DRAM | 1 | 10X | 否 | 是 | 1X | 主存,帧缓存区 |
磁盘存储
磁盘以扇区大小的块来读写数据。对扇区的访问时间主要有三个部分:
- 寻道时间 seek time
- 旋转时间 rotational time
- 传送时间 transfer time
磁盘的访问时间是SRAM的40000倍,是DRAM的2500倍。
设备可以自己执行读或者写总线事务,而不需要CPU干涉的过程,这个过程称为直接存储器访问(Direct Memory Access,DMA)
固态硬盘 Solid State Disk
固态硬盘是一种基于闪存
的存储技术。一个SSD由一个或多个闪存芯片和闪存翻译层(flash translation layer)组成,闪存芯片替代传统磁盘中的机械驱动器,而闪存翻译层是一个硬件/固件设备,扮演与磁盘控制器相同的角色,将对逻辑块的请求翻译成对底层物理设备的访问。
局部性
局部性原理(principle of locality):计算机程序倾向于引用邻近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。这种倾向性,就叫做局部性原理。
- 时间局部性(Temporal Locality):如果一个信息正在被访问,那么近期它很可能还会被再次访问。程序循环、堆栈等是产生时间局部性的原因。
- 空间局部性(Spatial Locality):在最近的将来用到的信息很可能与现在正在使用的信息在空间地址上是临近的。
- 循序局部性(Order Locality):在典型程序中,处转移指令外,大部分指令是顺序执行的。指令的顺序执行、数组的连续存放等是产生顺序局部性的原因。
举个简单的例子:
int sumvec(int v[N]){
int i,sum = 0;
for(int i=0; i < N; i++)
sum += v[i];
return sum;
}
sum 在每次循环迭代中都被引用一次,对 sum 来说就具有良好的时间局部性。数组 v 的访问是连续的,具有良好的空间局部性。
局部性小结:
* 重复引用一个变量的程序有良好的时间局部性
* 对于步长为k的引用模式的程序,步长越小,空间局部性越好
* 对于取指令来说,循环有良好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好
存储器结构层次
一种介质的速度越快就会越贵,同时也消耗更多的电量,所以一般容量比较小。而CPU与内存之间的差距越来越大,好的程序都会尽可能利用局部性。而根据这些特性,引申出了安排存储的方式,称为金字塔式存储体系(Memory Hierarch)。
存储器的中心思想:对于每个k,位于k层的更快更小的存储设备作为位于k+1层的更大更慢的存储设备的缓存。利用局部性原理,程序会倾向于访问第k层的数据,而非第k+1层,这样就减少了访问时间。
缓存类型 | 缓存内容 | 缓存位置 | 延时(时钟周期) | 管理者 |
---|---|---|---|---|
寄存器 | 4-8字节的字 | CPU内核 | 0 | 编译器 |
TLB | 地址翻译 | 芯片TLB | 0 | 内存管理单元 |
L1缓存 | 64字节的块 | 芯片L1缓存 | 4 | 硬件 |
L2缓存 | 64字节的块 | 芯片L2缓存 | 10 | 硬件 |
虚拟内存 | 4KB的页 | 主存 | 100 | 硬件+操作系统 |
缓冲区缓存 | 文件的部分内容 | 主存 | 100 | 操作系统 |
磁盘缓存 | 磁盘扇区 | 磁盘控制器 | 100,000 | 磁盘固件 |
网络缓冲区缓存 | 文件的部分内容 | 本地磁盘 | 10,000,000 | NFS客户端 |
浏览器缓存 | 网页 | 本地磁盘 | 10,000,000 | 网络浏览器 |
Web缓存 | 网页 | 远程服务器磁盘 | 1,000,000,000 | Web代理服务器 |
缓存未命中的类型:
- 强制性失效(Cold/compulsory Miss):CPU第一次访问响应缓存块,缓存中肯定没有数据,这是不可避免的
- 冲突失效(Conflict Miss):在直接相联或组相联的缓存中,不同的缓存由于索引相同相互替换,引起的失效叫做冲突失效
- 假设这里有 32KB 直接相关联的缓存
- 如果有两个 8KB 的数据需要来回访问,但是这两个数组都映射到相同的地址,缓存的大小足够存储全部的数据,但是因为相同地址发生冲突需要来回替换,发生的失效全是冲突失效(第一次访问失效依旧是强制性失效),这时缓存并没有存满。
- 容量失效(Capacity Miss):有限的缓存容量导致缓存放不小而被替换,被替换出去的缓存块再被访问,引起的失效叫容量失效。
深入理解高速缓存存储器 Cache Memory
高速缓存存储器是由硬件自动管理的SRAM内存,CPU会先从这里找数据,其所处的位置如蓝色部分所示:
高速缓存存储器由三个关键部分组成:
- S表示集合(set)数量
- E表示数据行(line)的数量
- B表示每个缓存块(block)保存的字节数目
如图所示:
所以缓存中存放数据的空间大小为B×E×S
实际上可以理解为三种层级对应关系,对应不同的索引,这样分层的好处是:通过层级关系简化搜索需要的时间,并且和字节的排布也是一一对应的(之后介绍缓存的时候就体现的更加明显)。
当处理器需要访问一个地址时,会先在高速缓冲存储器中进行查找,查找的过程我们首先在概念上把这个地址划分成三个部分:
读取
具体在从缓存中读取一个地址时,首先我们通过set index确定要在那个set中寻找,确定后利用tag和同一个set中的每个line进行对比,找到tag相同的那个line,最后再根据block offset确定要从line的那个位置读起。
当E = 1时,也就是每个set只有一个line的时候,称之为直接映射高速缓存(Direct Mapped Cache),如下图所示:
直接映射高速缓存的过程分为三步:组选择、行匹配、字抽取。
如果缓存不命中,那么它需要从存储器层次结构的下一层取出被请求的块,然后将新的块存储在组索引位指示的组中的一个高速缓存行中。
写入
整个存储层级中,不同的层级可能会存放同一个数据的不同拷贝(如L1,L2,L3,主内存,硬盘)。如果发生写入命中的时候(也就是要写入的地址在缓存中有),有两种策略:
- Write-through:命中后更新缓存,同时写入到内存中
- Write-back:直到这个缓存需要被置换出去,才写入到内存中(需要额外的 dirty bit 来表示缓存中的数据是否和内存中相同,因为可能在其他的时候内存中对应地址的数据已经更新,那么重复写入就会导致原有数据丢失)
在写入 miss 的时候,同样有两种方式:
- Write-allocate:载入到缓存中,并更新缓存
- No-write-allocate:直接写入内存中,不能载入到缓存
这四种策略通常的搭配是:
- Write-through + No-write-allocate
- Write-back + Write-allocate
其中第一种可以保证绝对的数据一致性,第二种效率会比较高(通常情况下)。