CSAPP – Chapter 6 内存与缓存 —— 内存层级与缓存机制

课程链接

Lecture 11 The Memory Hierarchy

Lecture 12 Cache Memories

存储器层次结构概览

层级越高,与 CPU 的距离越远。

Untitled

存储器系统

  1. 多个具有不同容量、成本和访问时间的存储设备构成了存储器层次结构,称为存储器系统。
  2. 执行指令时访问数据所需的周期数:

CPU 寄存器:0个周期

L1 ~ L3 高速缓存:4~75个周期

主存:上百个周期

磁盘:几千万个周期

6.1 存储器技术

几种基本的存储技术

  1. 随机访问存储器 (RAM, Random-Access Memory),分为两类:
    1. RAM,同时也是易失性存储器,也分为两类:
      • SRAM:静态随机访问存储器,速度快,价格高。多用来作为高速缓存存储器。
      • DRAM:动态随机访问存储器,速度慢,价格低。多用来作为主存和图形系统的帧缓冲器。
    2. ROM,同时也是非易失性存储器闪存属于 ROM,固态硬盘就是基于闪存开发而来。
  2. 机械硬盘
  3. 固态硬盘

6.1.1 随机访问存储器

1. SRAM

双稳态

只要有电,就永远地保持它的值。即使有干扰,当干扰消除,电路也会恢复到稳定值。

2. DRAM

每个 DRAM 单元由一个电容和一个访问晶体管组成。

DRAM 对干扰非常敏感。当电容的电压被扰乱后,就永远不会恢复了。

3. DRAM 读数据

DRAM 芯片被分为 d 个超单元,每个超单元包含 w 个 DRAM 单元,w 一般为 8。当从 DRAM 中读取数据时,一次可以读取一个超单元的数据(可以近似的将超单元理解为一个字节)。

DRAM 中的超单元按行列组织(原因:行地址和列地址共享相同的 DRAM 芯片地址引脚),DRAM 中还包含一个行缓冲区。

内存控制器依次将行地址和列地址发送给 DRAM,DRAM 将对应的超单元的内容发回给内存控制器以实现读取数据。

从 DRAM 中读取超单元的步骤:

  1. 内存控制器发来行地址 i,DRAM 将整个第 i 行复制到内部的行缓冲区
  2. 内存控制器发来列地址 j,DRAM 从行缓冲区中复制出超单元 (i, j) 并发送给内存控制器。

Untitled

4. 内存模块

内存单元都是通过小的内存芯片组合排列成的,许多 DRAM 芯片封装在内存模块中,插到主板的扩展槽上,如图。

内存上数据的存储:比如一个内存模块包含 8 个 DRAM 芯片,每个 DRAM 包含 8M 个超单元,每个超单元存储一个字节。使用 8 个 DRAM 芯片上相同地址处的超单元来表示一个 64 位字,DRAM 0 存储第一个字节,DRAM 1 存储第 2 个字节,依此类推。

访存:访存数据也是分片访问。要取出内存地址 A 处的一个字,内存控制器先将 A 转换为一个超单元地址 (i, j),然后内存模块将 i, j 广播到每个 DRAM。作为响应,每个 DRAM 输出它的 (i, j) 超单元的 8 位内容,合并成一个 64 位字,再返回给内存控制器。

Untitled

5. 非易失性存储器

DRAM 和 SRAM 会在断电后丢失信息,因此是易失性存储器。ROM 是非易失性存储器,在断电后仍保存着信息。

ROM 是只读存储器,但是实际上有些 ROM 既可以读也可以写。

Untitled

注:操作系统的视角 —— 将磁盘看成一个个的逻辑块,每个块就是一个数组

6.2 局部性

具有良好局部性的程序倾向于重复地访问相同的数据 (时间局部性),或倾向于访问邻近的数据 (空间局部性),因此运行更快。

局部性有两种形式:时间局部性空间局部性

6.2.3 局部性小结

评价局部性的简单原则:

  1. 重复引用相同变量的程序有好的时间局部性。
  2. 对于步长为 k 的引用模式的程序,k 越小,空间局部性越好。
  3. 对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。

 

6.3 存储器层次结构

计算机系统数据读取架构:

Untitled

缓存层级:

Untitled

存储器层次结构的核心思想:第 k 层作为第 k+1 层存储设备的缓存。

缓存的具体实现:第 k+1 层的存储器被划分为连续的块(block),每个块有唯一的地址或名字。第 k 层的存储器被划分为较少的块的集合,每个块的大小与 k+1 层的块大小一样。数据以块为传输单元在不同层之间复制。

层次结构中更低的层,因为访问时间更长,为了补偿访问时间,使用的块更大

数据访问

数据总是以块大小为传送单元在第 k 层和第 k+1 层之间来回复制的;层次结构中任何一对相邻的层次之间块大小是固定的, 但是其他层次对之间可以有不同的块大小;访问数据时,先去 cache 中查

  • 缓存命中
  • 缓存不命中
    • 如果第 k 层缓存已经满了,需要根据替换策略选择一个块进行覆盖 (替换),未满的话需要根据放置策略来选择一个块放置。

注:

  • 希望程序遵循局部性;
  • 寄存器是 cache 的缓存;
  • cache 的内容是内存的子集;
  • 内存可以看成是磁盘的缓存;

缓存管理

寄存器文件的缓存由编译器管理,L1, L2, L3 的缓存由内置在缓存中的硬件逻辑管理,DRAM 主存作为缓存由操作系统和 CPU 上的地址翻译硬件共同管理。

6.4 高速缓存存储器

L1 高速缓存的访问速度约为 4 个时钟周期,L2 约 10 个周期,L3 约 50 个周期。

当 CPU 执行一条读内存字 w 的指令,它首先向 L1 高速缓存请求这个字,如果 L1 没有就向 L2,依此而下。

6.4.1 通用的高速缓存存储器组织结构

假设一个计算机系统中的存储器地址有 m 位 (即表示 CPU 用来寻找内存数据的地址的位数),形成 M =2^m 个不同的地址。m 个地址为划分为 t 个标记位,s 个组索引位,b 个块偏移位。

高速缓存被组织成 S = 2^s 个高速缓存组,每个组包含 E 个高速缓存行 (cache line),每个行为一个数据块,包含一个有效位,t = m-(b+s) 个标记位,和 B = 2^b 字节的数据块。高速缓存的容量 = S * E * B。

关于数据块的理解:数据块大小是 B 字节,取数据时用块偏移表示要读的数据,最多用 b 个位表示(全为 1,B = 2^b ,此时每个数据大小是 1 字节),因此 m 位中这 b 个块偏移位的取值不一定会 0 ~ 2^b – 1 全部取;

Untitled

CPU 读内存数据过程

CPU → 内存的物理地址 → 地址分为三部分Tag、Set index、Block offset → 数据返回给 CPU

当 CPU 要从地址 A (由m个地址位组成) 处读一个字时,三步:

  1. A 中的 s 个组索引位告诉我们在哪个组中
  2. A 中的 t 个标记位告诉我们在这个组中的哪一行:当且仅当这一行设置了有效位并且标记位与 A 中的标记位匹配时,才说明这一行包含这个字。

有效位无效时,将相应的 Block 的数据全部读入这个缓存行;

  1. A 中的 b 个块偏移位告诉我们在 B 个字节的数据块中的字偏移。

Untitled

🌟 示例

Untitled

  • valid 位是 0 时,表示 cache 中没有数据,先把连续 Block 大小(B) 的数据读进来(所以本身内存里的数据就被分为了一个个的 Block) ——— 局部性
  • 不匹配时,做 cache 替换

🌟 Block 的设计意义:将连续的地址的数据一起读进来

🌟 Block offset:一个数据块(Block)是 B 个字节,偏移量的含义是需要的数据在 Block 中偏移相应的字节数(可以取的值当然受数据本身的大小影响

cache 的抖动:数据恰好映射到了同一个组里,造成 cache 被频繁的换入换出

🌟 解决方法:增加某一部分的地址,让冲突的映射交叉开

总结

1.为什么高位做标记位?

使用高位做标记位,可以避免连续的块被映射到同一高速缓存组中。

2.通过高速缓存从内存读字

CPU -> 逐级 Lx 高速缓存 -> 主存

  • 缓存命中
  • 缓存不命中
    • 高速缓存会向主存请求包含目标数据的,保存在自己的 cache line 中,然后从中抽取目标数据,并返回给 CPU

3.CPU 从内存地址读数据三步

1). 组选择

2). 行匹配

3). 字抽取

4.高速缓存有以下几类:

1). 直接映射高速缓存:每个组只有一行,即 E = 1。

2). 组相联高速缓存:每个组有多行,1 < E < C / B。

3). 全相联高速缓存:只有一个组,E = C / B。

6.4.2 直接映射高速缓存

特征:每个组只有一行,即 E=1

关于标记位、组索引与块偏移意义的理解: 标记位索引位连接起来标识了整个内存中的所有块,而高速缓存中的高速缓存组(块)是少于内存中的块数的。因此位于不同标记位,相同组索引位的块会映射到高速缓存中的同一个高速缓存组。

在一个高速缓存组中存储了哪个块,可以由标记位唯一地标识。

理解:对于主存中的整个地址空间,根据标记位不同将其分为了若干个部分,每个部分可以单独且完整地映射到高速缓存中,且刚好占满整个直接映射高速缓存。

6.4.3 组相联高速缓存

特征:每个组有多行,1 < E < C/B

cache 不命中时,几种替换策略

  1. 随机替换策略:随机选择要替换的行
  2. 最不常使用策略:替换在过去某个时间窗口内引用次数最少的一行。
  3. 最近最少使用策略:替换最后一次访问时间最久远的那一行。

因为存储器层次结构中越靠下,不命中开销越大,好的替换策略越重要。

6.4.4 全相联高速缓存

特征:只有一个组,E = C/B

Untitled

全相联高速缓存中只有一个组,地址中没有组索引位,只有标记位和块偏移位。

🌟 适用于 cache 容量比较小时

6.4.5 写 cache

向内存中写数据

分数据在 cache 中存不存在

Untitled

6.4.6 Intel Core i7 高速缓存层次结构

高速缓存既保 存数据,也保存指令,可分为三种:

  1. i-cache:只保存指令的高速缓存。i-cache 通常是只读的,因此比较简单。
  2. d-cache:只保存程序数据的高速缓存。
  3. 统一的高速缓存:既保存指令又保存程序数据。

现代处理器一般包括独立的 i-cache 和 d-cache,其中两个原因如下:

  1. 使用两个独立的高速缓存,CPU 可以同时读一个指令字和一个数据字。
  2. 可以确保数据访问不会与指令访问形成冲突不命中(不过可能会使容量不命中增加)。

Core i7 的高速缓存层次结构及其特性

Untitled

  • 三级 cache 都在 CPU 中;
  • 关注 cache 与内核的位置关系、相互的交互关系;
  • L1: 分为数据和指令 cache,是分开的;
  • L3: 是所有核共享的

Untitled

6.4.7 高速缓存参数的性能影响

衡量高速缓存的性能指标

  1. 命中率:命中的内存引用比率。
  2. 命中时间:从高速缓存传送一个字到 CPU 的时间,包括组选择、行确认和字抽取的时间。对于 L1 高速缓存来说,命中时间的数量级是几个时钟周期。
  3. 不命中处罚:不命中产生的额外时间消耗。L1 不命中需要从 L2 得到服务的处罚,通常是数10 个周期;从 L3 得到服务的处罚,50 个周期; ,从主存得到的服务的处罚,200 个周期。

几个影响因素

  1. 高速缓存大小:较大的高速缓存可以提高命中率,但是会运行得更慢,即增加命中时间。
  2. 块大小:较大的块更能利用空间局部性以提高命中率。但是对于给定的总容量,块越大高速缓存行就越少,不利于利用时间局部性较大的块因为传送时间更长,所以也会增加不命中处罚。现代处理系统的高速缓存块一般为 64 字节。
  3. 相联度:每个组中高速缓存行数 E 选择的影响。较高的相联度(也就是 E 的值较大)的优点是降低了高速缓存由于冲突不命中出现抖动的可能性;但是,缺点:
    • 资源占用增加:每 一行需要更多的标记位,每一行需要额外的 LRU 状态位和额外的控制逻辑,很难使之速度变快。
    • 增加命中时间:因为复杂性增加了
    • 增加不命中处罚:因为选择牺牲行的复杂性也增加了

相联度的选择是命中时间与不命中处罚之间的折中。

🌟 Core i7 的三级高速缓存中相联度的设计考虑点

L1 、L2级 高速缓存不命中处罚较小,因此可以选择较低的相联度(8路),减少命中时间;到 L3 级高速缓存,考虑 L2 级从它这得到的不命中处罚与它从主存得到的服务的处罚,选择比较小的相联度(16路),降低 L2 级从它这得到的不命中处罚与提升 L3 级的命中率。

关于缓存 – 总结

缓存指标

影响因素

参考链接

《深入理解计算机系统(CSAPP)》全书学习笔记(详细) – 神明佑我

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇