我们对系统的研究,目前依赖于一个简单的计算机系统模型,CPU执行指令,而存储器(memory)系统为CPU存放指令和数据。在我们简单的模型中,存储器系统是一个线性的字节数组,CPU能够在一个常数时间内访问每个存储器位置。但是这个模型并没有反映现代系统的实际工作方式。
实际上存储器系统(memory system)是一个具有不同容量、成本和访问时间的存储(storage)设备的层次结构:
- CPU寄存器保存着最常用的数据
- 靠近CPU的小的、快速的高速缓存存储器(cache memory)作为存储在相对慢速的主存储器(main memory,主存)中数据和指令子集的缓冲区域。
- 主存暂时存放存储较大的慢速磁盘上的数据。而这些磁盘常常又作为存储在通过网络连接的其他机器的磁盘或磁带上的数据的缓冲区域。
存储器的层次结构的好处是能够在成本尽可能小的情况下提升尽可能高的存储速度。一个编写良好的程序倾向于更频繁地访问某一个层次上的存储设备。所以,该层次下一层的、更低层次的存储设备可以更慢速一点,也因此可以令其更大,每个bit更便宜。整体效果是一个大的存储器池,其成本与层次结构底层最便宜的存储相当,但是却以接近于层次结构顶部存储设备的高速率向程序提供数据。
存储器层次结构对应用程序行呢能有着重大的影响。在寄存器中的数据0个周期内就能访问到;高速缓存中的数据1-10个周期内可以访问到;主存中的数据50-100周期;磁盘上需要大概20000000个周期!如果你理解了系统如何将数据在存储器层次结构中上上下下移动的,你就可以编写你的应用程序,使得它们的数据项存储在层次结构中较高的地方,在那里 CPU 能更快地访问到它们。
这个思想围绕着计算机程序的一个称为局部性(locality)的基本属性。具有良好局部性的程序倾向于一次又一次地访问相同的数据项集合,或是倾向于访问邻近的数据项集合。具有良好局部性的程序比局部性差的程序更多地倾向于从存储器层次结构中较高层次处访问数据项,因此运行得更快。例如,在 Core i7 系统,不同的矩阵乘法核心程序执行相同
数量的算术操作,但是有不同程度的局部性,它们的运行时间可以相差 40 倍!
在本章中,我们会看看基本的存储技术—— SRAM 存储器、DRAM 存储器、ROM 存储器以及旋转的和固态的硬盘——并描述它们是如何被组织成层次结构的。特别地,我们将注意力集中在高速缓存存储器上,它是作为 CPU 和主存之间的缓存区域,因为它们对
应用程序性能的影响最大。我们向你展示如何分析 C 程序的局部性,并且介绍改进你的程序中局部性的技术。你还会学到一种描绘某台机器上存储器层次结构的性能的有趣方法,称为“存储器山(memory mountain)” 它展示出读访问时间是局部性的一"函数。
存储技术
随机访问存储器
随机访问存储器(Random-Access Memory, RAM)分为两类:静态的和动态的。**静态RAM(SRAM)比动态 RAM(DRAM)**更快,但也贵得多。SRAM 用来作为高速缓存存储器,既可以在 CPU 芯片上,也可以在片下。DRAM 用来作为主存以及图形系统的帧缓冲区。典型地,一个桌面系统的 SRAM 不会超过几兆字节,但是 DRAM 却有几百或几千兆字节。
静态RAM
SRAM 将每个位存储在一个双稳态的(bistable)存储器单元里。每个单元是用一个六晶体管电路来实现的。这个电路有这样一个属性,它可以无限期地保持在两个不同的电压配置(configuration)或状态(state)之一。其他任何状态都是不稳定的——从不稳定状态开始,电路会迅速地转移到两个稳定状态中的一个。
由于 SRAM 存储器单元的双稳态特性,只要有电,它就会永远地保持它的值。即使有干扰(例如电子噪音)来扰乱电压,当干扰消除时,电路就会恢复到稳定值。
动态RAM
DRAM 将每个位存储为对一个电容的充电。这个电容非常小,通常只有大约 30 毫微微法拉(femtofarad)—— 30X10-15法拉。不过,回想一下法拉是一个非常大的计量单位。DRAM 存储器可以制造得非常密集——每个单元由一个电容和一个访问晶体管组成。但是,与 SRAM 不同,DRAM 存储器单元对干扰非常敏感。当电容的电压被扰乱之后,它就永远不会恢复了。暴露在光线下会导致电容电压改变。实际上,数码照相机和摄像机中的传感器本质上就是 DRAM 单元的阵列。
很多原因会导致漏电,使得 DRAM 单元在 10~100 毫秒时间内失去电荷。幸运的是,计算机运行的时钟周期是以纳秒来衡量的,所以相对而言这个保持时间是比较长的。内存系统必须周期性地通过读出,然后重写来刷新内存每一位。有些系统也使用纠错码,其中计算机的字会被多编码几个位(例如 64 位的字可能用 72 位来编码), 这样一来,电路可以发现并纠正一个字中任何单个的错误位。
只要有供电,SRAM 就会保持不变。与 DRAM 不同,它不需要刷新。SRAM 的存取比 DRAM 快。SRAM 对诸如光和电噪声这样的干扰不敏感。代价是 SRAM 单元比 DRAM 单元使用更多的晶体管,因而密集度低,而且更贵,功耗更大。
传统的DRAM
DRAM芯片中的单元(位)被分为d个超单元(supercell),每个超单元都由 w 个 DRAM单元组成。一个dw的 DRAM 总共存储了dw位信息。超单元被组织成一个r行 c 列的长方形阵列,这里rc=d 。每个超单元有形如(i, j)的地址,这里 i 表示行,而 j 表示列。
例如,下图展示的是一个 16X8 的 DRAM 芯片的组织,有 d=16 个超单元,每个超单元有 W=8 位,r=4 行,c=4 列。==带阴影的方框表示地址(2, 1)处的超单元。就下图而言,1个超单元有1个字节——也就是w=8bits的DRAM单元。然后d=16个超单元组成一个r=4c=4的阵列。在这个阵列中,每个超单元可以用(i,j)的坐标进行标识。信息通过称为引脚(pin)的外部连接器流入和流出芯片。每个引脚携带一个 1 位的信号。图 6-3 给出了两组引脚:8 个 data引脚,它们能传送一个字节到芯片或从芯片传出一个字节(将一个字节的信息传入或者传出一个超单元),以及 2 个 addr引脚,它们携带 2 位的行和列超单元地址(锁定阵列中的i和j)==。其他携带控制信息的引脚没有显示出来。
每个 DRAM 芯片被连接到某个称为内存控制器(memory controller)的电路,这个电路可以一次传送w位到每个 DRAM 芯片或一次从每个 DRAM 芯片传出 w 位。为了读出超单元(i; j)的内容,内存控制器将行地址i发送到 DRAM,然后是列地址j。 DRAM 把超单元(i,j)的内容发回给控制器作为响应。行地址 i称为 RAS(Row Access Strobe, 行访问选通脉冲)请求。列地址j称为 CAS(Cÿlumn Access Strobe, 列访问选通脉冲)请求。注意,RAS 和 CAS 请求共享相同的 DRAM 地址引脚。