5.2.3 存储器
存储器存储程序和数据,又称主存储器或内存,一般用动态随机访问存储器(Dynamic Random Access Memory,简称DRAM)实现。CPU可以直接访问它,IO设备也频繁地与它交换数据。存储器的存取速度往往满足不了CPU的快速要求,容量也满足不了应用的需要,为此将存储系统分为高速缓存(Cache)、主存储器和辅助存储器三个层次。Cache存放当前CPU最频繁访问的部分主存储器内容,可以采用比DRAM速度快但容量小的静态随机访问存储器(Static Random Access Memory,简称SRAM)实现。数据和指令在Cache和主存储器之间的调动由硬件自动完成。为扩大存储器容量,使用磁盘、磁带、光盘等能存储大量数据的存储器作为辅助存储器。计算机运行时所需的应用程序、系统软件和数据等都先存放在辅助存储器中,在运行过程中分批调入主存储器。数据和指令在主存储器和辅助存储器之间的调动由操作系统完成。CPU访问存储器时,面对的是一个高速(接近于Cache的速度)、大容量(接近于辅助存储器的容量)的存储器。现代计算机中还有少量只读存储器(Read Only Memory,简称ROM)用来存放引导程序和基本输入输出系统(Basic Input Output System,简称BIOS)等。现代计算机访问内存时采用虚拟地址,操作系统负责维护虚拟地址和物理地址转换的页表,集成在CPU中的存储管理部件(Memory Management Unit,简称MMU)负责把虚拟地址转换为物理地址。
存储器的主要评价指标为存储容量和访问速度。存储容量越大,可以存放的程序和数据越多。访问速度越快,处理器访问的时间越短。对相同容量的存储器,速度越快的存储介质成本越高,而成本越低的存储介质则速度越低。目前人们发明的用于计算机系统的存储介质主要包括以下几类:
1)磁性存储介质。如硬盘、磁带等,特点是存储密度高、成本低、具有非易失性(断电后数据可长期保存),缺点是访问速度慢。磁带的访问速度在秒级,磁盘的访问速度一般在毫秒级,这样的访问速度显然不能满足现代处理器纳秒级周期的速度要求。
2)闪存(Flash Memory)。同样是非易失性的存储介质,与磁盘相比,它们的访问速度快,成本高,容量小。随着闪存工艺技术的进步,闪存芯片的集成度不断提高,成本持续降低,闪存正在逐步取代磁盘作为计算机尤其是终端的辅助存储器。
3)动态随机访问存储器(DRAM)。属于易失性存储器(断电后数据丢失)。特点是存储密度较高(存储一位数据只需一个晶体管),需要周期性刷新,访问速度较快。其访问速度一般在几十纳秒级。
4)静态随机访问存储器(SRAM)。属于易失性存储器(断电后数据丢失)。存储密度不如DRAM高(SRAM存储一位数据需要4-8个晶体管),不用周期性刷新,但访问速度比DRAM快,可以达到纳秒级,小容量时能够和处理器核工作在相同的时钟频率。
现代计算机中把上述不同的存储介质组成存储层次,以在成本合适的情况下降低存储访问延迟,如图5.2中所示,越往上的层级,速度越快,但成本越高,容量越小;越往下的层级,速度越慢,但成本越低,容量越大。图5.2所示存储层次中的寄存器和主存储器直接由指令访问,Cache缓存主存储器的部分内容;而非易失存储器既是辅助存储器,又是输入输出设备,非易失存储器的内容由操作系统负责调入调出主存储器。
存储层次的有效性,依赖于程序的访存局部性原理,包含两个方面:一是时间局部性,指的是如果一个数据被访问,那么在短时间内很有可能被再次访问;二是空间局部性,指的是如果一个数据被访问,那么它的邻近数据也很有可能被访问。利用局部性原理,可以把程序近期可能用到的数据存放在靠上的层次,把近期内不会用到的数据存放在靠下的层次。通过恰当地控制数据在层次间的移动,使处理器需要访问的数据尽可能地出现在靠近处理器的存储层次,可以大大提高处理器获得数据的速度,从而近似达到用最快的存储器构建一个容量很大的单级存储的效果。现代计算机一般使用多端口寄存器堆实现寄存器,使用SRAM来构建片上的高速缓存(Cache),使用DRAM来构建程序的主存储器(也称为主存、内存),使用磁盘或闪存来构建大容量的存储器。
1.高速缓存
随着工艺技术的发展,处理器的运算速度和内存容量按摩尔定律的预测指数增加,但内存速度提高非常缓慢,与处理器速度的提高形成了“剪刀差”。工艺技术的上述特点使得访存延迟成为以存储器为中心的冯·诺依曼结构的主要瓶颈。Cache技术利用程序访问内存的时间局部性(一个单元如果当前被访问,则近期很有可能被访问)和空间局部性(一个单元被访问后,与之相邻的单元也很有可能被访问),使用速度较快、容量较小的Cache临时保存处理器常用的数据,使得处理器的多数访存操作可以在Cache上快速进行,只有少量访问Cache不命中的访存操作才访问内存。
Cache是内存的映像,其内容是内存内容的子集,处理器访问Cache和访问内存使用相同的地址。从20世纪80年代开始,RISC处理器就开始在处理器芯片内集成KB级的小容量Cache。现代处理器则普遍在片内集成多级Cache,典型的多核处理器的每个处理器核中一级指令Cache和数据Cache各几十KB,二级Cache为几百KB,而多核共享的三级Cache为几MB到几十MB。现代处理器访问寄存器时一拍可以同时读写多个数据,访问一级Cache延迟为1-4拍,访问二级Cache延迟为10-20拍,访问三级Cache延迟为40-60拍,访问内存延迟为100-200拍。
CPU执行一个程序的时间可以描述为:程序运行的总动态指令数 * CPI * 时钟周期。其中CPI(Cycle Per Instruction)表示平均每条指令执行花费的时钟周期数。CPI可以进一步细分为每种类型指令的CPI与这类指令占总指令数比例乘积之和,如运算指令CPI * 运算指令比例 + 访存指令CPI * 访存指令比例 + 其他指令CPI * 其他指令比例。访存指令CPI也称为平均访问延迟AMAT(Average Memory Access Latency)。在具有高速缓存的计算机中,
\[AMAT = HitTime + MissRate * MissPenalty\]
其中HitTime表示高速缓存命中时的访问延迟,MissRate表示高速缓存失效率,MissPenalty表示高速缓存失效时额外的访问延迟。例如,在某计算机系统中HitTime=1, MissRate=5%, MissPenalty=100,则AMAT=1+5=6。
2.内存
主存储器又称为内存。内存的读写速度对计算机的整体性能影响重大。为了提升处理器的访存性能,现代通用处理器都将内存控制器与CPU集成在同一芯片内,以减小平均访存延迟。
现代计算机的内存一般都采用同步动态随机存储器(SDRAM)实现。DRAM的一个单元由MOS管T和电容C(存储单元)组成,如图5.3所示。电容C存储的电位决定存储单元的逻辑值。单元中的字线根据读写地址译码得到,连接同一字的若干位;单元中的位线把若干字的同一位链接在一起。进行读操作时,先把位线预充到Vref=VCC/2,然后字线打开T管,C引起差分位线微小的电位差,感应放大器读出,读出后C中的电位被破坏,需要把读出值重新写入C。进行写操作时,先把位线预充成要写的值,然后打开字线,把位线的值写入C。C中的电容可能会漏掉,因此DRAM需要周期刷新,刷新可以通过读操作进行,一般每行几十微秒刷新一次。 "
SDRAM芯片一般采用行列地址线复用技术,对SDRAM进行读写时,需要先发送行地址打开一行,再发送列地址读写需要访问的存储单元。为了提高访问的并发度,SDRAM芯片一般包含多个Bank(存储块),这些Bank可以并行操作。图5.4显示了一个DDR2 SDRAM x8芯片的内部结构图。可以看到,该SDRAM内部包含了8个Bank,每个Bank对应一个存储阵列和一组感应放大器,所有的Bank共用读锁存(Read Latch)和写FIFO。
对SDRAM进行写操作后,由于必须等到写数据从IO引脚传送到对应Bank的感应放大器后,才能进行后续的预充电操作(针对相同Bank)或者读操作(针对所有Bank),因此写操作会给后续的其他操作带来较大的延迟,但连续的写操作却可以流水执行。为了降低写操作带来的开销,内存控制器往往将多个写操作聚集在一起连续发送,以分摊单个写操作的开销。
影响SDRAM芯片读写速度的因素有两个:行缓冲局部性(Row Buffer Locality,简称RBL)和Bank级并行度(Bank Level Parallelism,简称BLP)。
1)行缓冲局部性。如图5.4所示,SDRAM芯片的一行数据在从存储体中读出后,存储体中的值被破坏,保存在对应的一组感应放大器中,这组感应放大器也被称为行缓冲。如果下一个访存请求访问同一行的数据(称为命中行缓冲),可以直接从该感应放大器中读出,而不需要重新访问存储体内部,可以大大降低SDRAM的访问延迟。当然,在行缓冲不命中的时候,就需要首先将行缓冲中的数据写回存储体,再将下一行读出到行缓冲中进行访问。由此,对DRAM可以采用关行(Close Page)和开行(Open Page)两种策略。使用关行策略时,每次读写完后先把行缓冲的内容写入存储体,才能进行下一次读写,每次读写的延迟是确定的。使用开行策略时,每次读写完后不把行缓冲的内容写入存储体,如果下一次读写时所读写的数据在行缓冲中(称为行命中),可以直接对行缓冲进行读写即可,延迟最短;如果下一次读写时所读写的数据不在行缓冲中,则需要先将行缓冲中的数据写回对应的行,再将新地址的数据读入行缓冲,再进行读写,延迟最长。因此,如果内存访问的局部性好,可以采用开行策略;如果内存访问的局部性不好,则可以采用关行策略。内存控制器可以通过对多个访存请求进行调度,尽量把对同一行的访问组合在一起,以增加内存访问的局部性。
2)Bank级并行度。SDRAM芯片包含的多个Bank是相互独立的,它们可以同时执行不同的操作,比如,对Bank 0激活的同时,可以对Bank 1发出预充电操作,因此,访问不同Bank的多个操作可以并行执行。Bank级并行度可以降低冲突命令的等待时间,容忍单个Bank访问的延迟。
利用内存的这两个特性,可以在内存控制器上对并发访问进行调度,尽可能降低读写访问的平均延迟,提高内存的有效带宽。内存控制器可以对十几甚至几十个访存请求进行调度,有效并发的访存请求数越多,可用于调度的空间就越大,可能得到的访存性能就更优。
5.2.4 输入/输出设备
输入/输出设备(简称IO设备)实现计算机与外部世界的信息交换。传统的IO设备有键盘、鼠标、打印机和显示器等;新型的IO设备能进行语音、图像、影视的输入、输出和手写体文字输入,并支持计算机之间通过网络进行通信。磁盘等辅助存储器在计算机中也当作IO设备来管理。
处理器通过读写IO设备控制器中的寄存器来访问及控制IO设备。高速IO设备可以在处理器安排下直接与主存储器成批交换数据,称为直接存储器访问(Directly Memory Access,简称DMA)。处理器可以通过查询设备控制器状态与IO设备进行同步,也可以通过中断与IO设备进行同步。
下面以GPU、硬盘和闪存为例介绍典型的IO设备。
1.GPU
GPU(Graphics Processing Unit,图形处理单元)是与CPU联系最紧密的外设之一,主要用来处理2D和3D的图形、图像和视频,以支持基于视窗的操作系统、图形用户界面、视频游戏、可视化图像应用和视频播放等。
当我们在电脑上打开播放器观看电影时,GPU负责将压缩后的视频信息解码为原始数据,并通过显示控制器显示到屏幕上;当我们拖动鼠标移动一个程序窗口时,GPU负责计算移动过程中和移动后的图像内容;当我们玩游戏时,GPU负责计算并生成游戏画面。
GPU驱动提供OpenGL、DirectX等应用程序编程接口以方便图形编程。其中,OpenGL是一个用于3D图形编程的开放标准;DirectX是微软公司推出的一系列多媒体编程接口,包括用于3D图形的Direct3D。通过这些应用程序接口,软件人员可以很方便地实现功能强大的图形处理软件,而不必关心底层的硬件细节。
GPU最早是作为一个独立的板卡出现的,所以称为显卡。我们常说的独立显卡和集成显卡是指GPU是作为一个独立的芯片出现还是被集成在芯片组或处理器中。现代GPU内部包含了大量的计算单元,可编程性越来越强,除了用于图形图像处理外,也越来越多地用作高性能计算的加速部件,称为加速卡。
GPU与CPU之间存在大量的数据传输。CPU将需要显示的原始数据放在内存中,让GPU通过DMA的方式读取数据,经过解析和运算,将结果写至显存中,再由显示控制器读取显存中的数据并输出显示。将GPU与CPU集成至同一个处理器芯片时,CPU与GPU内存一致性维护的开销和数据传递的延迟都会大幅降低。此时系统内存需要承担显存的任务,访存压力也会大幅增加,因为图形应用具有天生的并行性,GPU可以轻松地耗尽有限的内存带宽。
GPU的作用是对图形API定义的流水线实现硬件加速,主要包括以下几个阶段:
- 顶点读入(Vertex Fetch):从内存或显存中取出顶点信息,包括位置、颜色、纹理坐标、法向量等属性
- 顶点渲染(Vertex Shader):对每一个顶点进行坐标和各种属性的计算
- 图元装配(Primitive Assembly):将顶点组合成图元,如点、线段、三角形等
- 光栅化(Rasterization):将矢量图形点阵化,得到被图元覆盖的像素点,并计算属性插值系数以及深度信息
- 像素渲染(Fragment Shader):进行属性插值,计算每个像素的颜色
- 逐像素操作(Per-Fragment Operation):进行模板测试、深度测试、颜色混合和逻辑操作等,并最终修改渲染缓冲区
在GPU中,集成了专用的硬件电路来实现特定功能,同时也集成了大量可编程的计算处理核心用于一些较为通用的功能实现。设计者根据每个功能使用的频率、方法以及性能要求,选择不同的实现方式。大部分GPU中,顶点读入、图元装配、光栅化及逐像素操作使用专用硬件电路实现,而顶点渲染和像素渲染采用可编程的计算处理核心实现。由于现代GPU中集成了大量可编程的计算处理核心,这种大规模并行的计算模式非常适合于科学计算应用,所以在高性能计算机领域,GPU常被用作计算加速单元配合CPU使用。
2.硬盘
计算机除了需要内存存放程序的中间数据外,还需要具有永久记忆功能的存储体来存放需要较长时间保存的信息。比如操作系统的内核代码、文件系统、应用程序和用户的文件数据等。该存储器除了容量必须足够大之外,价格还要足够便宜,同时速度还不能太慢。在计算机的发展历史上,磁性存储材料正好满足了以上要求。磁性材料具有断电记忆功能,可以长时间保存数据;磁性材料的存储密度高,可以搭建大容量存储系统;同时,磁性材料的成本很低。
人们目前使用的硬盘就是一种磁性存储介质。硬盘的构造原理为:将磁性材料覆盖在圆形碟片(或者说盘片)上,通过一个读写头(磁头)悬浮在碟片表面来感知存储的数据。通过碟片的旋转和磁头的径向移动来读写碟片上任意位置的数据。碟片被划分为多个环形的轨道(称为磁道,Track)来保存数据,每个磁道又被分为多个等密度(等密度数据)的弧形扇区(Sector)作为存储的基本单元。磁盘的内部构造如图5.5所示。硬盘在工作时,盘片是一直旋转的,当想要读取某个扇区的数据时,首先要将读写头移动到该扇区所在的磁道上,当想要读写的扇区旋转到读写头下时,读写头开始读写数据。
衡量磁盘性能的指标包括响应时间和吞吐量,也就是延迟和带宽。磁头移动到目标磁道的时间称为寻道时间。当磁头移动到目标磁道后,需要等待目标扇区旋转到磁头下面,这段时间称为旋转时间。旋转时间与盘片的旋转速度有关,磁盘的旋转速度用RPM(Rotation Per Minute,转/分)来表示,我们常说的5400转、7200转,就是指磁盘的旋转速度。扇区旋转到目标位置后,传输这个扇区的数据同样需要时间,称为传输时间。传输时间是扇区大小、旋转速度和磁道记录密度的函数。
磁盘是由磁盘控制器控制的。磁盘控制器控制磁头的移动、接触和分离以及磁盘和内存之间的数据传输。另外,通过IO操作访问磁盘控制器又会引入新的时间。现在的磁盘内部一般都会包含一个数据缓冲,读写磁盘时,如果访问的数据正好在缓冲中命中,则不需要访问磁盘扇区。还有,当有多个命令读写磁盘时,还需要考虑排队延迟。因此,磁盘的访问速度计算起来相当复杂。一般来说,磁盘的平均存取时间在几个毫秒的量级。
磁盘的密度一直在持续增加,对于用户来说,磁盘的容量一直在不断增大。磁盘的尺寸也经历了一个不断缩小的过程,从最大的14英寸(1英寸=0.0254米)到最小的1.8英寸。目前市场上常见的磁盘尺寸包括应用于台式机的3.5英寸和应用于笔记本电脑的2.5英寸。
3.闪存
闪存(Flash Storage)是一种半导体存储器,它和磁盘一样是非易失性的存储器,但是它的访问延迟却只有磁盘的千分之一到百分之一,而且它尺寸小、功耗低,抗震性更好。常见的闪存有SD卡、U盘和SSD固态磁盘等。与磁盘相比,闪存的每GB价格较高,因此容量一般相对较小。目前闪存主要应用于移动设备中,如移动电话、数码相机、MP3播放器,主要原因在于它的体积较小。闪存在移动市场具有很强的应用需求,工业界投入了大量财力推动闪存技术的发展。随着技术的发展,闪存的价格在快速下降,容量在快速增加,因此SSD固态硬盘技术获得了快速发展。SSD固态硬盘是使用闪存构建的大容量存储设备,它模拟硬盘接口,可以直接通过硬盘的SATA总线与计算机相连。
最早出现的闪存被称为NOR型闪存,因为它的存储单元与一个标准的或非门很像。NAND型闪存采用另一种技术,它的存储密度更高,每GB的成本更低,因此NAND型闪存适合构建大容量的存储设备。前面所列的SD卡、U盘和SSD固态硬盘一般都是用NAND型闪存构建的。
使用闪存技术构建的永久存储器存在一个问题,即闪存的存储单元随着擦写次数的增多存在损坏的风险。为了解决这个问题,大多数NAND型闪存产品内部的控制器采用地址块重映射的方式来分布写操作,目的是将写次数多的地址转移到写次数少的块中。该技术被称为磨损均衡(Wear Leveling)。闪存的平均擦写次数在10万次左右。这样,通过磨损均衡技术,移动电话、数码相机、MP3播放器等消费类产品在使用周期内就不太可能达到闪存的写次数限制。闪存产品内部的控制器还能屏蔽制造过程中损坏的块,从而提高产品的良率。