「计算机组成原理」:现代存储器的结构( 六 )


高速缓存(Cache)是一个小而快速的存储设备 , 用来作为存储在更大更慢设备中的数据对象的缓冲区域 。 而使用高速缓存的过程称为缓存(Caching) 。
存储器层次结构的中心思想是让层次结构中的每一层来缓存低一层的数据对象 , 将第k层的更快更小的存储设备作为第k+1层的更大更慢的存储设备的缓存 。
该结构之所以有效 , 是因为程序的局部性原理 。 相比于第k+1层的数据 , 程序会倾向于访问存储在第k层的数据 。 如果我们访问第k+1层存储的数据 , 我们会将其拷贝到第k层 , 因为根据局部性原理我们很有可能将再次访问该数据 , 由此我们就能以第k层的访问速度来访问数据 。 而且因为我们不经常访问第k+1层的数据 , 我们就可以使用速度更慢且更便宜的存储设备 。
「计算机组成原理」:现代存储器的结构文章插图
上图展示的是存储器层次结构的基本缓存原理 。 每一层存储器都会被划分成连续的数据对象组块 , 称为块(Block) , 每个块都有一个唯一的地址或名字 , 并且通常块的大小都是固定的 。 第k层作为第k+1层的缓存 , 数据会以块大小作为传送单元(Transfer Unit)在第k层和第k+1层之间来回赋值 , 使得第k层保存第k+1层块的一个子集的副本 。 通常存储器层次结构中较低层的设备的访问时间较长 , 所以较低层中会使用较大的块 。
3.1 缓存命中当程序需要第k+1层的某个数据对象d时 , 会先在第k层的块中搜索d , 如果d刚好缓存在第k层中 , 则成为缓存命中(Cache Hit) , 则该程序会直接从第k层中读取d 。 根据存储器层次结构 , 可以知道第k层的读取速度更快 , 因此缓存命中会使得程序更快 。
3.2 缓存不命中如果第k层没有缓存数据对象d , 则称为缓存不命中(Cache Miss) , 则会从第k+1层中取出包含d的块 , 然后第k层的缓存会执行某个放置策略(Placement Policy)来决定该块要保存在第k层的什么位置

  • 来自第k+1层的任意块能保存在第k层的任意块中 , 如果第k层的缓存满了 , 则会覆盖现存的一个牺牲块(Victim Block) , 称为替换(Replacing)或驱逐(Evicting)这个牺牲块 , 会根据替换策略(Replacement Policy)来决定要替换第k层的哪个块:随机替换策略:会随机选择一个牺牲块最近最少被使用(LRU)替换策略:选择最后被访问的时间离现在最远的块
随机放置块会使得定位起来代价很高 。
  • 可以采用更严格的放置策略 , 将第k+1层的某个块限制放置在第k层块的一个小的子集中 , 比如第k+1层的第i个块保存在第k层的i mod 4中 。 但是该放置策略会引起冲突不命中(Conflict Miss) , 此时缓冲区足够大 , 但是由于需要的对象会反复映射到同一个缓存块 , 使得缓存一直不命中 。 此时就需要修改放置策略 。
比较特殊的情况是第k层的缓存为空 , 那么对于任意的数据对象的访问都会不命中 。 空的缓存称为冷缓存(Cold Cache) , 该不命中称为强制性不命中(Compulsory Miss)或冷不命中(Cold Miss) 。
程序通常会按照一系列阶段来运行 , 每个阶段会访问缓存块的某个相对稳定不变的集合 , 则该集合称为工作集(Working Set) , 如果工作集大小超过缓存大小 , 则缓存会出现容量不命中(Capacity Miss) , 这是由缓存太小导致的 。
3.3 缓存管理对于每层存储器 , 都会有某种形式的逻辑来管理缓存:将缓存划分成块、在不同层之间传递块、判断缓存是否命中并进行处理 。
  • 编译器管理寄存器文件 , 当寄存器文件中不含有数据时出现不明中 , 它会决定何时发射加载操作 , 以及确定用哪个寄存器来存放数据 。
  • SRAM高速缓存是DRAM主存的缓存 , 由内置在缓存中的硬件逻辑管理的 。
  • 在有虚拟内存的系统中 , DRAM主存是本地磁盘的缓存 , 由操作系统软件和CPU上的地址翻译硬件共同管理 。
  • 在具有分布式文件系统的机器中 , 本地磁盘作为缓存 , 由运行在本地机器上的客户端进行管理 。

「计算机组成原理」:现代存储器的结构文章插图
通过以上内容 , 就能解释局部性好的程序的优势: