701-存储层次结构概况
# 701-存储层次结构概况
如果 CPU 爱好哲学,它可能一直在问自己两个问题,我要运算的数据从哪里来?我算完的数据又将去向哪里?这在计算机世界当中确实是一个非常重要的问题。这也正是我们今天所要探讨的主题:存储器。
这是我们非常熟悉的冯·诺依曼计算机结构, 那这其中哪些部件和存储功能有关呢? 存储器自然会是一个,而外部记录介质也是带有存储功能的。 这两个都比较明显,另外还有一个也带有存储功能那就是运算器。 因为 CPU 当中的通用寄存器是包含在运算器当中的, 通用寄存器中也是用来存放临时的数据,也可以看作是一种存储器。
那这些就是我们要介绍的构成存储层次结构的主要部件。 那为了便于描述把这些部件都统称为存储器。
# 计算机对存储器的需求
那我们来看一看计算机当中对存储器有哪些需求。首先存储器当中应该保存了将要运行的程序和需要运算的数据,那这些内容在系统通电启动的时候就应该在存储器当中了, 而且在断电之后也不会丢失。那么具有这样特定的存储器我们称之为非易失性存储器。 而断电后存储的信息就会丢失的存储器则称为易失性存储器。那么在现在的计算机系统当中储存和 CPU 当中的通用寄存器都是易失性的存储器,断电之后其中的信息就丢失了。 而 bios 芯片和硬盘则是非易失性的存储器, 所以在系统通电之后 CPU 必须要从 bios 芯片开始执行程序,然后这段程序把硬盘等设备配置好之后再将更多的程序和数据从硬盘搬运到内存, 之后 CPU 才可以在内存里执行程序,因此在系统中必须要有非易失性的存储器。
第二这样的存储器肯定得是可读又可写的。 那在这个结构当中硬盘和主存都是可读可写的, 而 bios 芯片则是一个只读的芯片, 倒不是说它完全不支持写操作,而是对它的写需要借助特殊的设备或者特殊的操作过程,非常的麻烦, 无法支持经常性地写入数据。
第三存储器最好是能够支持随机访问。所谓随机访问是指对存储器当中任何一个数据的访问所花费的时间与这个数据所在的位置没有关系。 那一种典型的非随机访问的设备就是磁带,比如早期要听歌都是要使用磁带的, 假如现在磁带的开头你就可以马上听第一首歌,但是如果你想听第十首歌,你就得用快进的方式快速的卷过前九首歌才能够听第十首。 这样的访问就是和它的位置有关的,
而在计算机程序的运行过程中, 我们会访问到存储器的任意位置,如果不支持随机访问, 这就会对性能造成很大的影响。在这里对主存的读写和 Bios 芯片的读都是支持随机访问的。 而硬盘内部实际上是由多个盘片构成, 这些盘片处于高速旋转的状态,并由一个机械的读写头去寻找需要访问的数据的位置。 这就不是随机访问的模式,而且由于期中有机械部件的存在,速度就变得非常的慢。
而在计算机当中存储器的速度也就是访问的时间也是一个非常重要的因素。 CPU 的运行速度很快在它需要访问存储器的时候,最好能在一个时钟周期内就完成数据的访问,不然就会阻碍 CPU 后续的操作。 而储存的速度是明显高于硬盘的速度的。所以总体看来, 如果我们能找到一个存储器支持随机读写而且是非易失性的,访问时间也很短, 那么就可以考虑只用这样一个存储器和 CPU 连接,当然我们还要考虑到是否有足够大的容量以装下所以我们需要的程序和数据, 还有价格是否能够承受,以及功耗是否合适等等。
那既然现状我们是使用了这么多种不同的存储器,虽然是因为没有一个唯一而完美的解决方案, 那么就从性能和价格等方面对它们进行一个比较。
# CPU 和存储器的特性对比
这是 30 年来具有代表性的 CPU,我们每隔十年 选取一个代表,80 年的 8080,时钟频率大约为一兆赫兹,其时钟周期是一千纳秒。 90 年我们选取了 386 的一个版本,时钟周期是五十纳秒。 而 2000 年选择的是奔腾二,时钟周期大约为一点六纳秒。 2010 年选择的是 Core i7,时钟周期大约是 0.24 纳秒。 当然我们要注意因为这个时候已经是四核了, 如果每个核,每个时钟周期都需要对外传输数据, 那其实相当于每零点一纳秒就需要传输一个数据。 那么就以这个 CPU 的时钟周期为指标来看一看外部存储器的特性。
首先我们来看硬盘。 硬盘的访问时间在 80 年的时候大约是 87,我们注意这个单位是毫秒, 毫秒和纳秒差了一百万倍,所以虽然这 30 年来硬盘的访问速度也有所提升, 大概提升了 29 倍,但它和 CPU 的时钟周期完全没有可比性, 相差数百上千万倍。 所以仅从访问时间这一项来看硬盘从一开始就不具备直接和 CPU 进行交互的能力, 当然它的优势在于容量大而且便宜。 在 80 年的时候大约每兆字节需要五百美元, 那时典型的硬盘容量是一兆 bit, 而在这 30 年中硬盘单位容量的价格在迅速的下降,下降幅度超过 160 万倍, 而与此同时硬盘的容量也在迅速的增长,上升的幅度也有 150 万倍。 这样我们就可以存放更多的程序和数据。 这是硬盘技术进步带来的最大的好处。
当然另外还有一件很有意思的事情,我们发现 价格下降的幅度和容量上升的幅度基本相当, 也就是说现在和 30 年前相比虽然硬盘的容量和单个字节的价格 有了巨大的变化,但是整个硬盘的价格却基本保持着不变。
那硬盘作为一个非易失性的存储器自然有它自己的作用。 但是要想和 CPU 直接交互还得看其他的设备, 这就是 DRAM。现在的存储主要是采用 DRAM 实现。 它的访问时间在 1980 年大约是 375 纳秒, 我们注意到这个时候 DRAM 实际上比 CPU 的运行的速度还要快一些, 所以这时候并不用担心内存无法及时给 CPU 提供数据的事情。
而到了 90 年 DRAM 的速度已经比 CPU 的速度慢了,而且后来这个差距越来越大, 到 2010 年,即使只考虑单核 CPU 的需求,DRAM 的访问时间 也和 CPU 的时钟周期相差一百倍。那在这同样的这 30 年里 CPU 的 时钟频率提升了 2500,而 DRAM 的访问速度却只提升了 9 倍, 所以这个差距明显是在拉大的。 不过 DRAM 的进步也同样体现在其容量和价格上, 这 30 年来其容量足足提升了有 12 万倍之多, 而成本也几乎有同样比例的压缩,也就是说我们可以与 30 年前用同样的价格买到 12 万倍的容量的内存。
# 存储器性能的影响
容量扩大自然是一件好事,但是这个性能的差距到底会带来什么样的影响呢?我们通过一个例子来看一看。 假设 CPU 直接连接的 DRAM 构成的主存, 那在 CPU 当中执行一条指令所需要花的时钟周期大约是这样的, 我们就以奔腾 CPU 执行指令的五个步骤为例,首先是取指, 我们假设在 CPU 内部需要花一个周期产生访问存储器的地址, 那么接下来就因为要读存储器而进行等待, 所以这样 CPU 就会等待一百个时钟周期才能得到这条指令的编码, 然后再花一个周期在 CPU 内部进行译码,第三步在奔腾当中是生成地址, 第四步则是执行。
如果在执行当中需要去访问存储器读取操作数,那又需要再等待一百个周期, 然后才可以得到操作数,并在 CPU 内部再用一个周期完成相应的执行工作。 最后花一个周期写回到寄存器,但是如果目的操作数是存储器的话那还需要花一段时间完成写存储器的操作。 那么这里就可以看到实际上执行一条指令大约要花掉二百多个时钟周期, 而且绝大多数的时间都在等待存储器。
我们原先希望一个时钟周期就能完成一条指令,那如果 CPU 真是这么运行的, 那一个 1G 赫兹的 CPU 只相当于时钟主频只有 5 兆赫兹的 CPU 的性能了。 这样显然是无法接受的。所以我们必须要考虑如何提升 CPU 访问存储器的性能。
那既然 DRAM 的性能提升有限,那么就只能去寻找其它速度更快的存储器, 比如说 SRAM 就是一种选择。 那么就可以考虑在 CPU 和 DRAM 之间,加上一个速度更快的 SRAM, 那如果我们能让 CPU 所需要的程序和数据大部分时间都存放在这个 SRAM 当中, 那 CPU 就可以获得快得多的存储器访问时间。 这样一个 SRAM 的部件,就称为 cashe,也就是高速缓存。
那我们来对比一下 cache 对指令执行时间的影响。 SRAM 的访问时间大约可以认为是 3 个时钟周期,那上面这个指令执行的过程就会变成这个样子, 所有读存储器的 100 个时钟周期都会缩短为大约 3 个时钟周期, 这样大约只需要总共 10 个时钟周期就可以完成一条指令了。 相比于之前的性能,有了巨大的提升。
既然 SRAM 这么好,那么为什么不用 SRAM 作为主存呢? 要回答这个问题,我们还得来看这张表,我们再加上 SRAM 的相关参数。 在 1980 年,SRAM 的访问时间大约是 300 纳秒,比 DRAM 要快一些, 但是很有限,基本上属于相当的访问时间,但是 SRAM 的访问速度提升的很快, 三十年间提升了大约两百倍,而这段时间,DRAM 只提升了九倍。 在很长一段时间内,SRAM 的访问时间与 CPU 的时钟周期基本相当, 所以在之前学习处理器结构的过程中,我们一直认为 CPU 可以在一个时钟周期内从高速缓存当中获得数据, 即使在 2010 年的时候,SRAM 的访问时间也不过是 CPU 时钟周期的三到四倍, 那这个差距,也完全可以通过继续细化切问流水集来解决。 因此从速度上来说,SRAM 作为与 CPU 直接连接的存储器是合适的。
但是我们能不能直接把它作为主存呢?那我们就得来看看价格是否能够接受了。 我们注意到在 2010 年,同样容量的 SRAM,它的价格是 DRAM 的 一千倍。如果说我们现在花一千块钱就可以买到一个非常好的内存条, 那你是不是愿意花十万块钱买一个相同容量的 SRAM 作为内存呢?所以即使仅从价格因素来考虑,SRAM 也无法取代 DRAM 用来作为内存,而是只能用一个小容量的 SRAM 作为高速缓存,保存最常用的程序和数据,以达到性能和价格的平衡。
那是什么时候开始用 SRAM 作为 cache 加到 CPU 和主存之间的呢? 其实从这张表上我们也能够看出来, 在 80 年的时候,DRAM 还是比 CPU 的速度要快的, 所以这个时候没有使用高速缓存的需求,而到了 90 年,DRAM 的速度已经比 CPU 慢了, 所以在我们用作例子的这些英特尔系列的 CPU 中, 正是在 1980 年到 1990 年这个过程中,逐渐产生了高速缓存的需求。 那在这个时期,我们细致地来看, 早期的 8088CPU 访存实际上需要 840 纳秒, 而 DRAM 的延迟是 250 纳秒,那当然就不需要 cache。 286 的访存周期大约是 200 纳秒,DRAM 的延迟呢, 是 220 纳秒,也基本相当,这时候还是不需要 cache。 而 386 的访存周期大约是 80 纳秒,DRAM 的延迟虽然有所进步,但还是需要 190 纳秒,这时候已经明显慢于 CPU 了, 但是 386CPU 芯片内部并没有设计 cache 这个部件, 后来也发现这对性能有很大的影响,所以当时是采用在芯片外再增加一块 SRAM 芯片作为 cache 来解决这个问题。 那么到了 486 的时候,就已经把 cache 集成到了 CPU 芯片的内部, 从而缓解 CPU 和 DRAM 主存之间的性能差距,
# 存储层次
因此,现代的计算机当中都采用了这样层次化的存储结构。 在这个层次结构中,越往上的部件, 容量越小,但速度更快,而单位字节的成本更高, 越靠下的部件,容量更大,但速度更慢,而单位字节的成本更低。
现在,我们已经了解了计算机对存储器的基本需求, 也知道了存储器的基本特性和大致的分类, 那我们就要对其中的细节进行深入的探索, 以及建立完整的计算机存储体系。