CPU存储器层次结构

3 存储器层次结构

3.1 内容概要

  • 简单的计算机系统模型为CPU执行指令,存储器系统为CPU存放指令和数据。在该简单的计算机系统模型中,存储器系统是一个线性的字节数组,而CPU能够在一个常数时间内访问每个存储器位置。
  • 存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构。CPU寄存器保存着最常用的数据。靠近CPU小的、快速的高速缓存存储器作为一部分存储在相对慢速的主存储器中数据和指令的缓冲区域。主存缓存存储在容量较大的、慢速磁盘上的数据,而这些磁盘常常又作为存储在通过网络连接的其他机器的磁盘或磁带上的数据缓冲区域。
  • 本章主要介绍存储器层次结构,各个层次的基本作用及其特性,最重要的是介绍CPU是如何从存储器的各个层次获得数据和指令,以及现代处理器为什么要设计此类多层次的存储器结构。

3.2 存储技术

3.2.1 随机访问存储器

  • 随机访问存储器(Random-Access Memory,RAM)分为两类:静态和动态。静态RAM(SRAM)比动态RAM(DRAM)更快,但贵很多。SRAM用为高速缓存存储器,既可以在CPU芯片上,也可在片下。而DRAM一般用作主存以及图像系统的帧缓存区。

3.2.2 静态RAM

  • SRAM将每个存储在一个双稳态的存储单元里,每个单元是用一个六晶体管电路来实现的,其属性是可以无限期的保持在两个不同的电压配置或状态之一。由于SRAM存储器单元的双稳态特性,只要有电,它就会永远的保持他的值。即使有干扰(如电子噪音)来扰乱电压,当干扰消除时,电路就会恢复到稳定值。

3.2.3 动态RAM

  • DRAM将每个存储为对一个电容充电,该电容非常小,通常只有30毫微法拉。DRAM存储器其工艺可以制造的非常密集——每个单元有一个电容和一个访问晶体管组成,因此其存储单元对干扰非常敏感。同时当电容的电压被扰乱后,就永远无法恢复,并且暴露在光线下会导致电容电压改变。
  • 导致DRAM的存储单元漏电的原因有很多,使得DRAM单元在10~100ms时间内失去电荷,而计算机运行的时钟周期是以纳秒来衡量的,因此这个保持时间相对较长。与SRAM不同之处就是,只要供电SRAM就会保持不变,而DRAM需要周期性的通过读出,并重新刷新内存每一位。另外有些系统会使用纠错码,其中计算机的字会被多编码几个位(如64位的字可能用72位来编码),则电路可以发现并纠正一个字中任何单个的错误位。另一个不同之处就是,SRAM的存取比DRAM块,同时SRAM对光和电噪声的干扰不敏感。因此SRAM单元比DRAM单元使用更多的晶体管,因而密集度低,而且贵,并功耗大。
    这里写图片描述

3.3 局部性

  • 良好的计算机程序应当具有良好的局部性。该程序倾向于引用邻近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。此类倾向性,被称为局部性原理,是一个持久的概念,对硬件和软件系统的设计和性能都有着极大的影响。
    局部性通常有两种不同的形式:时间局部性和空间局部性。在一个具有良好时间局部性的程序中,被引用过一次的内存位置很可能在不远的将来再被多次引用。在一个具有良好空间局部性的程序中,如果一个内存位置被引用了一次,那么程序很可能在不远的将来引用附近的一个存储位置。
  • 有良好的局部性程序比局部性差的程序运行的更快。而现代计算机系统的各个层次,从硬件到操作系统、再到应用程序,他们都利用了局部性。在硬件层,局部性原理允许计算机设计者通过引入高速缓存存储器的小而快速的存储器来保存最近被引用的指令和数据,从而提高对主存的访问速度。在操作系统,局部性原理允许系统使用主存作为虚拟地址空间最近被引用块的高速缓存。类似的,操作系统用主存来缓存磁盘文件系统中最近被使用的磁盘块。

3.3.1 对程序数据引用的局部性

这里写图片描述

  • a) 良好空间局部性的程序
    这里写图片描述
  • b) 空间局部性很差的程序

3.3.2 取指令的局部性

  • 因为程序指令是存放在内存中的,CPU必须取出这些指令。如上图a)中的for循环里的指令是按连续的内存顺序执行的,因此其具有良好的空间局部性。又因为循环体会被执行多次,所以其也有很好的时间局部性。

3.3.3 局部性小结

量化评价局部性的简单原则:

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

3.4 存储器层次结构

  • 典型的存储器层次结构,如下所示。一般而言,从高层往底层走,存储设备变得更慢、更便宜和更大。在最高层(L0),是少量快速的CPU寄存器,CPU可以在一个时钟周期内访问它们。接下来是一个或多个小型到中兴的基于SRAM的高速缓存存储器,可以在几个CPU时钟周期内访问它们。然后是一个大的基于DRAM的主存,可以在几十到几百个时钟周期内访问它们。接下来是慢速但容量很大的本地磁盘。最后,有些系统甚至包括了一层附加的远程服务器上的磁盘,要通过网络来访问他们。
    这里写图片描述

3.4.1 存储器层次结构中的缓存

  • 存储器层次结构的中心思想是:层次结构中的每一层缓存来自于脚底一层的数据对象。
    这里写图片描述
  • 由上可知,数据总是以块大小为传送单元在第k层和第k+1层之间来回复制的。虽然层次结构中任何一对相邻的层次之间块大小是固定的,但其他的层次对之间可以有不同的块大小。一般而言,层次结构中较低层的设备的访问时间较长,因此为了补偿这些较长的访问时间,倾向于使用较大的块。
3.4.1.1 缓存命中
  • 当程序需要第k+1层的某个数据对象d时,他首先在当前存储在第k层的一个块中查找d。如果d刚好缓存在第k层中,那就是缓存命中。该程序直接从第k层读取数据d,比从第k+1层读取数据d更快。
3.4.1.2 缓存不命中
  • 如上所述,如果在第k层中没后缓存数据对象d,这就是所说的缓存不命中。此时第k层的缓存将从第k+1层缓存中取出包含d的数据块,若第k层的缓存已经满了,则会覆盖现存的一个块。
  • 覆盖一个现存的块的过程称为替换或驱逐这个块。被驱逐的这个块称为牺牲块,具体决定该替换哪个块是由缓存的替换策略来控制的。
3.4.1.3 缓存不命中的种类
  • 冷缓存:空的缓存。此类不命中称为强制性不命中或冷不命中。冷不命中,通常是短暂的事件,不会在反复访问存储器使得缓存暖身之后的稳定状态中出现。
  • 冲入不命中:是由于硬件缓存使用严格的放置策略导致的。如:该策略将第k+1层的某个块限制放置在第k层的一个小的子集中。此时缓存足够大,能够保存被引用的数据对象,但是因为这些对象会映射到同一个缓存块,缓存会移植不命中。
3.4.1.4 缓存管理
  • 存储器层次结构的本质是,每一层存储设备都是较低一层的缓存。在每一层上,某种形式的逻辑必须管理缓存。具体是指某个东西要将缓存划分成块,在不同层之间传送块,判定是命中还是不命中,并处理它们。管理缓存的逻辑可以是硬件、软件或者两者的结合。

3.4.2 存储器层次结构概念小结

  • 基于缓存的存储器层次结构性质有效,是因为较慢的存储设备比较快的存储设备更便宜,还因为程序倾向于展示局部性:
  • 利用时间局部性:由于时间局部性,同一数据对象可能会被多次使用。一旦一个数据对象在第一次不命中时被复制到缓存中,我们就会期望后面对该目标有一系列的访问命中。因为缓存比低一层的存储设备更快,对后面的命中服务会比较最开始的不命中快很多。
  • 利用空间局部性:块通常包括多个数据对象。由于空间局部性,我们会期望后面对该块中其他对象的访问能够补偿不命中后复制该块的花费。

现代系统中到处都是用了缓存,CPU芯片、操作系统、分布式文件系统和万维网等都是用了缓存,各种各样的硬件和软件组合构成和管理着缓存。
这里写图片描述

3.5 高速缓存存储器

3.5.1 高速缓存存储器的基本内容

这里写图片描述
随着CPU和主存之间的性能差距的增大,系统设计者在CPU寄存器和主存之间插入高速缓存,如下所述:

  • L1高速缓存:在CPU寄存器文件和L2高速缓存之间插入的SRAM高速缓存存储器,其访问速度几乎与寄存器一样快,典型的是大约4个时钟周期;
  • L2高速缓存:在L1高速缓存和主存之间插入一个更大的高度缓存,大约10个时钟周期内访问到它。
  • L3高速缓存:位于L2高速缓存和主存之间,大约50个周期内访问到它。

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

  • 不命中率。在一个程序执行或程序的一部分执行期间,内存引用不命中的比率。计算公式:不命中数量/引用数量。
  • 命中率。命中内存引用的比率。命中率=1-不命中率。
    命中时间。从高速缓存传送一个字到CPU所需的时间,包括组选择、行确认和字选择的时间。对于L1高速缓存来说,命中时间的数量级是几个时钟周期。
  • 不命中处罚。由于不命中所需要的额外的时间。L1不命中需要从L2得到服务的处罚,通常是数十个周期;从L3得到服务的触发,50个周期;从主存得到的服务的处罚,200个周期。
  • 1)高速缓存大小的影响
    一方面,较大的高速缓存可能会提高命中率;另一方面,使大存储器运行得更快总是难一些。较大的高速缓存可能会增加命中时间,这就解释了为什么越高级的高速缓存会低级的要越小。
  • 2)块大小的影响
    大的块有利有弊。一方面,较大的块能利用程序中可能存在的空间局部性,帮助提高命中率。对于给定的高速缓存大小,块越大就意味着高速缓存行数越少,这就损害时间局部性比空间局部性更好的程序中的命中率。较大的块对不命中处罚也有负面影响,因为快越大,传送时间就越长。
  • 3)相联度的影响
    较高的相联度的优点是降低了高速缓存由于冲突不命中出现抖动的可能性,但其会造成较高的成本。相联度的选择最终变成了命中时间和不命中处罚之间的折中。
  • 4)写策略的影响
    直写高速缓存比较容易实现,而且能使用独立于高速缓存的写缓存区,用于更新内存。而读不命中开销没这么大,因为它们不会处罚内存写。另外,写会高速缓存引起的传送比较少,它允许更多的内存的带宽用于执行DMA的I/O设备。此外,越往层次下面走,传送时间增加,减少传送的数量就变得更加重要。一般而言,高速缓存越往下层,越可能使用写回而不是直写。

备注:高速缓存行、组和块的区别

  •  块:固定大小的信息包,在高速缓存和主存之间来回传送;
  •  行:高速缓存中的一个容器,存储块以及其他信息;
  •  组:一个或多个行的集合。直接映射高速缓存中的组是由一行组成。组相联和全相联高速缓存中的组是由多个航组成的。
    在直接映射高速缓存中,组和行实际上是等价的。不过,在相联高速缓存中,组和行是不一样的,两者不能相互使用。

3.6 编写高速缓存友好的代码

编写高速缓存友好代码的基本方法:

  • 1)让最常见的情况运行得块。程序通常把大部分时间都花在少量的核心函数上,而这些函数通常把大部分时间都花在少量循环上。即要把注意力集中在核心函数里的循环上,而忽略其他部分。
  • 2)尽量减小每个循环内部的缓存不命中数量。在其他条件相同的情况下,不命中率较低的循环运行得更快。
1   int sumvec(int v[N])
2   {
3       int i, sum = 0;
4    
5       for (i=0; i<N; i++)
6       {
7           sum += v[i];
8       }
9
10      return sum;
11   }

通过sumvec示例可说明两个关于编写高速缓存友好的代码的重要问题:

  •  对局部变量的反复引用是好的,因为编译器能够将他们缓存在寄存器文件中(时间局部性)。
  •  步长为1的引用模式时好的,因为存储器层次结构中所有层次上的缓存都是将数据存储为连续的块(空间局部性)。
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值