缓存设计回顾

写缓存

  • 直写(write-through):直接将高速缓存块写回低一层中,每次都会引起总线流量,低效。
  • 写回(write-back):直到替换算法要驱逐缓存块时,才将它写回低一层中,需要额外的修改位(dirty bit)表示高速缓存块是否被修改过。

处理写不命中

  • 写分配(write-allocate):加载低一层块到高速缓存中并更新,与写回搭配。
  • 非写分配(not-write-allocate):直接写到低一层中,与直写搭配。

缓存一致性问题

来源

共享内存多处理器中,每个处理器缓存中的内存备份不一致。

不能用锁解决?锁只能用于共享变量的互斥,而缓存一致性的问题在于对内存的备份不一致。

简单例子:单核处理器

I/O操作+DMA

例如,处理器写共享缓冲区,网卡异步地从共享缓冲区中读数据,如果缓冲区没有刷新,网卡会得到错误数据。

解决

CPU使用非缓存(uncached)写法,操作系统标记含有共享缓冲区的内存为非缓存的;和CPU的load/store比,DMA的使用频率很低,因此这种软件解决方法开销不大。

定义

对内存X读的结果必须是上一次写完后的结果。在多处理模型中:

  • 读写符合单处理器顺序(即程序顺序)
  • 多处理器中,其他处理器的写操作必须更新后才能读
  • 多处理器中,任意两个处理器的写操作在其他处理器看来是有顺序的。

硬件解决方案

  • 监听snooping
  • 目录directory

监听式缓存

共享缓存(作为对比)

  • 解决缓存一致性问题
  • 可拓展问题,多个处理器有竞争关系
  • 失去局部性、快速的特点

监听式缓存

缓存监听器监听内存操作,并传播到其他缓存的缓存监听器

简单的直写式(write-through)

一旦发生写操作,该处理器的缓存控制器传播无效信号,其他处理器的缓存控制器接收信号,接下来的读操作会触发缓存丢失,从而直接到内存中读。

状态图

  • 状态:Invalid,Valid
  • 操作:PrRd,PrWr(当前处理器操作),BusRd,BusWr(总线操作)

写回式(write-back)

MSI状态图

  • 状态:Invalid,Modified(缓存行只对当前有效,可写),Shared(缓存行对所有都有效,可读不可写)
  • 操作:PrRd,PrWr,BusRd(复制缓存行但不修改),BusRdX(复制缓存行并修改),flush(将dirty line写回内存)
  • Modified缓存行可以被直接修改
  • 处理器只能修改Modified缓存行,即对其他状态的缓存行需要一种方式使得当前缓存行成为Modified状态

多层缓存结构

  • 缓存的包含性
  • L2包含L1,只需对L2监听

代码编写

False-sharing:处理器对不同地址进行写操作,然而不同地址却映射到同一个缓存行。

// bad
int myPerThreadCounter[NUM_THREADS];

// better
struct PerThreadState{
    int myPerThreadCounter;
    char padding[CACHE_LINE_SIZE-sizeof(int)];
}
PerThreadState myPerThreadCounter[NUM_THREADS];

ShengYg

Step after step the ladder is ascended.


Tags •