《深入理解计算机系统》存储器层次结构——读书笔记

来源:互联网 发布:淘宝云客服待遇 编辑:程序博客网 时间:2024/04/30 09:08

一、存储技术

      1、 基本的存储技术包括随机存储器(RAM)、非易失性存储器(ROM)和磁盘。RAM分静态RAM(SRAM)和动态RAM(DRAM)。SRAM快些,也贵些,主要用做CPU芯片上的高速缓存,也可以用作芯片下的高速缓存。DRAM慢些,便宜些,主要用作驻村和图形帧缓冲区。ROM也叫做只读存储器,即使在断电的情况下,也能保持他们的信息,它们用来存储固件。

      2、传统的DRAM芯片单元被分成d个超单元,每个超单元由w个DRAM单元组成。一个dxW的DRAM总共存储了dw位信息。一个16x8的DRAM芯片组织如下图所示:

                                                                        

      3、电路设计者将DRAM组织成二维阵列而不是线性数组的一个原因是降低芯片上地址引脚的数量。(因为每个引脚一次只能传送一位)读一个DRAM超单元内容的方式如下图所示:

                                     

     DRAM芯片包装在存储器模块中,示例模块用8个64Mbit的8Mx8的DRAM芯片,总共存储64MB(兆字节),如下图所示:

                                               

       4、增强的DRAM:FPM DRAM , EDO DRAM , SDRAM , DDR DRAM , RDRAM , VRAM。

       5、访问主存,数据流通过总线在CPU和DRAM主存之间来来回回。

            movl A, %eax指令会发生如下流程:

    

      movl %eax, A指令会发生如下流程:

        

      6、磁盘存储(基本都没看)

         固态硬盘是一种基于闪存的存储技术。

二、局部性

      1、局部性通常分两种不同的形式,时间局部性和空间局部性。有良好局部性的程序比局部性差的程序运行的更快。在一个有良好时间局部性的程序中,被引用过一次的存储器位置很可能在不远的将来被多次引用;具有良好控件局部性的程序中,如果一个存储器被引用一次,那么程序可能在不久的将来引用附近的一个存储器位置。

      2、对程序数据引用的局部性

            a)一维数组示例如下:

                         

       对于sum来说,有很好的时间局部性,因为sum是标量,对于sum来说,没有空间局部性;对于变量v,有很好的控件局部性,但是因为每个向量元素只被访问一次,因此时间局部性很差。因此,总体来说,sumvec函数有很好的局部性。

        b)二维数组示例如下:

         该段代码有很好的局部性:

                            

       该段代码局部性不好:

                             

      3、取指令局部性

          因为程序指令是存放在存储器中的,CPU必须取出这些指令,所以我们也能评价一个程序关于取指令的局部性。例如,上述一维数组示例中,for循环中的指令是按照连续的存储器顺序执行的,因此循环有良好的空间局部性。因为循环体会被执行多次,所以也有很好的时间局部性。

      4、局部性小结

       一些量化评价一个程序中局部性的简单原则:

       重复引用同一个变量从的程序有良好的时间局部性;

       对于步长为k的引用模式的程序,步长越小,空间局部性越好。具有步长为1的引用模式的程序有很好的空间局部性;

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

三、存储器层次结构

       存储器层次结构的中心思想是,对于每个k,位于k层的更快更小的存储设备作为位于k+1层的更大更慢的存储设备的缓存。数据总是以块大小作为传送单元在第k层和k+1层之间来回拷贝的。存储器层次结构示例如下图所示:

                                             

       几个基本术语:缓存命中,缓存不命中(冷不命中,冲突不命中,容量不命中)

四、高速缓存存储器

       1、通用的高速缓存存储器结构

(m=t+s+b)

      2、直接映射高速缓存

          每组只有一行的高速缓存叫直接映射高速缓存。高速缓存确定一个请求是否命中,然后抽取出被请求的字的过程,分为三步:1)组选择 2)行匹配 3)字抽取

          a)组选择

                                        

       b)直接映射高速缓存行匹配

            当且仅当设置了有效位,而且告诉缓存行中的标记与w的地址中标记相匹配时,这一行中包含w的一个拷贝。(有效位+标记)

       c)直接映射高速缓存中的子选择

            块偏移位提供了所需要的字的第一个字节的偏移。

                      

 

3、综合示例

     假设我们有一个直接映射高速缓存,描述如下:(S,E,B,m)=(4,1,2,4),即4个组,每个组1行,每个块2个字节,地址是4位。这里假设每个字都是单字节,每次都读1个字。由上得知,

                         

                                 图 分析过程                                                                                                图 完整的直接映射高速缓存的4位地址空间

    示例过程如下:初始时,高速缓存是空的:

                                                                  

   a)读地址0的字。因为组0的有效位是0,缓存不命中,所以高速缓存从存储器取出块0,,并存储在组0中。然后高速缓存返回取出的高速缓存行的m[0]。

                                                                   

   b)读地址1的字。高速缓存命中。

   c)度地址13的字。

                                                                   

   d)读地址8的字。(组0的行确实有效,但标记不匹配)

                                                                    

    e)读地址0的字。又发生缓存不命中,因为前面引用地址8时,刚好替换了块8。

                                                                    

 

   6、直接映射高速缓存中的冲突不命中

        以下代码容易产生抖动问题:

                                                    

        简单来说,即使程序有良好的空间局部性,而且我们的高速缓存中也有足够的空间来存放x[i]和y[i]的块,每次引用还是会引起冲突不命中,这是因为这些块被映射到了同一个高速缓存组。参考如下表:

                                           

      采用如下方法,可以消除抖动,把x定义为float x[12],在x结尾加了填充,x[i]和y[i]现在就映射到了不同的组:

                                          

    7、组相连高速缓存:每个组都保存有多于一个的高速缓存行。

    8、全相联高速缓存:只有一个组,这个组包含所有的高速缓存行。

    9、有关写的问题

      a)写一个已经缓存了的字w写命中,两种方式:直写和写回。

          直写:立即将w的高速缓存块写回到紧接着的低一层中。

          写回:尽可能的推迟存储器更新,只有当替换算法要驱逐更新过的块时,才把它写到紧接着的低一层中。

     b)处理写不命中情况:写分配和非写分配

五、编写高速缓存友好的代码

    1、存储器山

         存储器系统的性能不是一个数字就能描述的。相反,它是一座时间和空间局部性的山,这座山的上升高度差别可以超过一个数量级。要是程序运行在山峰而不是低谷。

    2、示例:重新排列循环以提高空间局部性

         一对nxn矩阵相乘问题:C=AxB。一下是矩阵乘法的六个版本

 

原创粉丝点击