Linux系统学习笔记:存储器

来源:互联网 发布:kali linux攻击服务器 编辑:程序博客网 时间:2024/06/03 22:24

存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构,较高层存储设备作为较低层存储设备的缓存。存储器层次结构对程序的性能有巨大的影响。可以利用局部性使程序运行得更快。本篇总结存储器系统。

Contents

  • 局部性
  • 存储设备
    • RAM
    • ROM
    • 磁盘
  • 存储器层次结构
    • 高速缓存存储器
    • 高速缓存和程序性能

局部性

良好的程序倾向于引用的数据项邻近于其他最近引用过的数据项或最近自我引用过的数据项,这称为局部性原理。局部性有时间局部性和空间局部性两种形式。引用过的存储器位置在最近将再被多次引用称为时间局部性,程序在最近将引用引用过的存储器位置附近的存储器位置称为空间局部性。

有良好局部性的程序比局部性差的程序运行得更快。

int sumvector(int v[N]){    int i, sum = 0;    for (i = 0; i < N; i++)     /* 步长为1的引用模式 */        sum += v[i];    return sum;}

v 有很好的空间局部性,时间局部性很差。 sum 为重复引用,有很好的时间局部性,没有空间局部性。

int summatrix1(int m[M][N]){    int i, j, sum = 0;    for (i = 0; i < M; i++)        for (j = 0; j < N; j++)            sum += m[i][j];    return sum;}int summatrix2(int m[M][N]){    int i, j, sum = 0;    for (j = 0; j < N; j++)        for (i = 0; i < M; i++)            sum += m[i][j];    return sum;}

summatrix1 和 summatrix2 的空间局部性一个很好,一个很差,因为后者使用了步长为 N 的引用模式。程序的引用模式的步长越小,空间局部性越好。

对于取指令,循环有良好的时间局部性和空间局部性,循环体越小,迭代次数越多,局部性越好。

存储设备

现有多种不同的存储技术,包括SRAM、DRAM、磁盘等。不同的存储技术有不同的价格和性能的折中,它们以不同的速率变化着。但DRAM和磁盘访问时间要滞后于CPU时钟周期时间,因此现在都使用基于SRAM的高速缓存来弥补CPU和存储器之间的速度差距。这种方法利用了程序的局部性。

RAM

随机访问存储器(RAM)分为静态的(SRAM)和动态的(DRAM)。SRAM更快也更贵,一般作为高速缓存存储器。DRAM一般作为主存。SRAM将位存储在双稳态的存储单元里,每个单元用六晶体管电路来实现,它可以无限期保存电压状态。DRAM将位存储为对电容的充电,每个单元由一个电容和一个晶体管组成,它会在一定时间后失去电荷,因此必须周期性地读出再写回来刷新存储器。

 每位晶体管数相对访问时间持续的敏感的相对花费应用SRAM61x是否100x高速缓存存储器DRAM110x否是1x主存,帧缓冲区

DRAM中的位被分成d个超单元(单元、字),组织成r行c列,每个超单元有形如(i,j)的地址,存储w位信息。下图示例了从一个128位16×8的DRAM芯片读取一个超单元的内容的过程。

/media/note/2012/03/26/linux-memory/fig1.png

从128位16×8的DRAM芯片读取一个超单元的内容

DRAM存储器有很多种,如SDRAM和DDR SDRAM。

数据流通过总线在处理器和DRAM主存之间来回,这种数据传送称为总线事务,分为读事务(从主存传送数据到CPU)和写事务(从CPU传送数据到主存)。

总线是一组并行的导线,能携带地址、数据和控制信号。多个设备可以共享同一个总线。控制信号同步事务。

ROM

只读存储器(ROM)和RAM相比,可以在断电后仍保存数据,有些类型的ROM既可读又可写。

存储在ROM中的程序通常称为固件(firmware),如BIOS。很多设备都有固件,如显卡、磁盘、光驱等。

磁盘

磁盘(disk)由一或多个盘片组成,放在密封包装里。盘片表面覆盖磁性记录材料。每个表面由一组磁道(同心圆)组成,每个磁道划分为一组扇区,每个扇区包含相等数量的数据位(目前通常为512字节)。扇区由一些间隙分隔开,间隙不存储数据位,存储用来标识扇区的格式化位。

磁盘的容量由记录密度和磁道密度决定,记录密度和磁道密度的积称为面密度。

磁盘容量 = # 字节数/扇区 × 平均 # 扇区数/磁道 × # 磁道数/盘面 × # 盘面数/盘片 × # 盘片数/磁盘

磁盘用一个传动臂的读写头来读写存储的位,以扇区大小的块来读写数据。扇区的访问时间由寻道时间、旋转时间和传送时间的和决定。

平均寻道时间一般为6 ~ 9ms。平均旋转时间是最大旋转时间的一半,后者可通过转速确定,现在常见的磁盘转速有5400RPM和7200RPM。平均传送时间依赖于转速和每磁道扇区数,等于最大旋转时间/平均每磁道扇区数。通常传送时间可以忽略不计。寻道时间和旋转时间大致相等。和RAM相比,磁盘的访问时间是前者的几千到几万倍。

磁盘上有个磁盘控制器,可以将物理扇区映射到逻辑块号,操作系统通过逻辑块号读写磁盘。

磁盘等设备也通过总线进行访问,它们使用I/O总线,I/O总线比系统总线和存储器总线要慢,但可以容纳很多种类的第三方I/O设备,如磁盘控制器、图形适配器、USB控制器和网络适配器等。CPU使用存储器映射I/O技术来向I/O设备发射命令。

存储器层次结构

现代计算机的存储器采用分层结构,来利用程序的局部性弥补CPU和存储器之间的速度差距。

  • L0:寄存器,保存从高速缓存存储器取出的字。
  • L1:芯片上的L1高速缓存(SRAM),保存从L2高速缓存取出的缓存行。
  • L2:芯片外的L2高速缓存(SRAM),保存从主存取出的缓存行。
  • L3:主存(DRAM),保存从磁盘取出的磁盘块。
  • L4:本地二级存储(本地磁盘),保存从远程网络服务器磁盘上取出的文件。
  • L5:远程二级存储(分布式文件系统、Web服务器)。

从L5到L0,存储量更小、速度更快、成本更高。位于k层的存储设备作为k+1层的存储设备的缓存,缓存k+1层的块的一个子集,数据以块大小为传输单元在层之间复制。

当程序需要k+1层的某个数据对象d时,首先在k层的块中查找d,如果d缓存在k层中,称为缓存命中,程序直接从k层读取d。如果k层没有缓存d,称为缓存不命中,k层从k+1层取出包含d的块,如果k层缓存已满,则可能覆盖现有的一个块,称为替换(驱逐)这个块,块被称为牺牲块。由缓存的替换策略来决定该替换哪个块。

缓存不命中有不同种类。空缓存的任何数据访问都会不命中,空缓存称为冷缓存,这种不命中称为强制性不命中,或冷不命中。在缓存达到稳定状态后,就不会出现冷不命中了。缓存通常有严格的放置策略,有一定的映射规则,放置策略引起的不命中称为冲突不命中。如果某个阶段的工作集的大小超过了缓存的大小,缓存会出现容量不命中。

高速缓存存储器

高速缓存存储器包括L1高速缓存和L2高速缓存,它们处在CPU和主存之间。一般地,L1高速缓存会分成保存指令的L1 i-cache和保存数据的L1 d-cache,L2高速缓存则不分开。现在很多CPU已经开始使用三级缓存。

每个存储器地址有m位,形成M=2^m个不同的地址。m个地址位划分为t个标记位、s个组索引位和b个块偏移位。

高速缓存被组织成S=2^s个高速缓存组的数组,每组包含E个高速缓存行,每行由B=2^b字节的数据块组成,还有一个有效位指明该行的数据是否有意义,t个标记位标识存储在该行中的块,t = m-(b+s)。

因此,高速缓存的结构可以用 (S,E,B,m) 描述,高速缓存的大小为 C = S * E * B,即所有块大小的和。

/media/note/2012/03/26/linux-memory/fig2.png

高速缓存(S,E,B,m)的通用结构

一行总是存储一个块,因此行和块通常互换使用。

根据E,高速缓存可以分为直接映射高速缓存(E=1)、组相联高速缓存(1<E<C/B)和全相联高速缓存(E=C/B)。

高速缓存在确定一个请求是否命中并取出被请求的字w的过程为:组选择,行匹配,字抽取。

直接映射高速缓存

  1. 组选择:从w的地址中取出s个组索引位,由它的无符号数得到组S的索引。
  2. 行匹配:E=1时,每组只有1行。当该行设置了有效位,且标记和w的地址中的标记位匹配时,该行包含w的一份副本,即缓存命中;否则缓存不命中。
  3. 字抽取:缓存命中时,根据w的地址中的块偏移位确定字w在块中的第一个字节的偏移,取出字w;缓存不命中时,从下层存储中取出被请求的块,存储在该组的其中一行,对于直接映射高速缓存,即替换当前行。

高速缓存反复地加载和驱逐高速缓存块相同的组的现象称为抖动。即使程序有良好的空间局部性,如果引用的块被映射到了相同的高速缓存组,就会由于抖动而造成性能下降,一个解决办法是给数据结构(如数组)做一些填充,使引用的块映射到不同的组。

组相联高速缓存

  1. 组选择:和直接映射高速缓存相同。
  2. 行匹配:每组有多行。在组内查找设置了有效位且标记和w的地址中的标记位匹配的行,这时缓存命中;否则缓存不命中。
  3. 字抽取:和直接映射高速缓存相同,不过在缓存不命中时,因为组中有多行,所以会使用一定的替换策略选择其中一行。

全相联高速缓存

  1. 组选择:只有一个组。w的地址中没有组索引位。
  2. 行匹配:和组相联高速缓存相同。
  3. 字抽取:和组相联高速缓存相同。

因为标记位匹配的限制,全相联高速缓存只适合做小的高速缓存,如虚拟存储器系统中的TLB。

对于写操作,如果CPU写一个已经缓存的字w,称为写命中;如果要写的字w没有缓存,称为写不命中。

写命中时,高速缓存更新了w的副本后,需要更新w在存储器中的副本。一种方法是直写,就是立即将w的高速缓存块写回到存储器中,缺点是每条存储指令都会引起总线上的一个写事务。另一种方法是写回,只有当替换算法要驱逐已更新的块时,才把它写回到存储器,由于局部性,写回能显著减少总线事务的数量,但增加了复杂性。

写不命中时,也有两种方法。一种是写分配,加载相应的存储器块到高速缓存中,然后更新这个高速缓存块,它试图利用写的空间局部性。另一种是非写分配,避开高速缓存,直接把字写到存储器中。

直写的高速缓存通常是非写分配的,写回的高速缓存通常是写分配的。现实中的情况比较复杂,一般地可以使用写回写分配的高速缓存模型。

高速缓存的性能可以由命中率、命中时间和不命中处罚衡量:

  • 命中率:执行期间,存储器引用的命中比率。
  • 命中时间:从高速缓存传送一个字到CPU所需的时间,对于L1,通常为1~2个时钟周期。
  • 不命中处罚:由于不命中所需要的额外时间,L1需要由L2满足的处罚通常为5~10个时钟周期,L1需要由主存满足的处罚通常为25~100个时钟周期。

较大的高速缓存C可能会提高命中率,但同时可能会增加命中时间。

较大的块B可以利用空间局部性,提高命中率,但越大的块高速缓存行数越少,这会减少时间局部性带来的命中率,越大的块传送时间也越长,这会增大不命中处罚。

较高的相联度E可以降低高速缓存由于冲突不命中出现抖动的可能性,但会增加复杂度,这会增大命中时间和不命中处罚,并且造成较高的成本。

直写高速缓存比较容易实现,且能使用写缓冲区;写回高速缓存引起的传送比较少。一般存储器越往下层,越可能使用写回。

高速缓存和程序性能

程序从存储系统中读数据的速率称为读吞吐量(读带宽)。可以通过测量,得到覆盖读带宽的一个时间和空间局部性的二维函数,称为存储器山,它刻画了计算机的存储系统的能力,每台计算机有唯一 的存储器山。

典型地,可以通过重新排列循环来提高空间局部性,通过使用分块来提高时间局部性。

链接: http://www.yeolar.com/note/2012/03/26/linux-memory/
原创粉丝点击