0x1 cpu缓存体系结构

image.png
现代cpu缓存体系结构

为什么需要缓存

现代cpu的运行速度远远超过了内存的访问速度,一次的内存访问与一次的cpu访问是2个数量级的区别,最终执行每条指令都需要等待内存加载,导致cpu流水线停顿。因此现代cpu在内存之上加了多级的高速缓存,缓解由于不对称带来的性能损耗。

缓存如何解决问题

缓存利用了程序的局部性原理,使得大多数的访问都能维持在高速缓存。

  • 空间局部性:数据和代码的访问一般访问了其中一个元素,相邻的下一步就会访问到
    • 数据段:结构体,数组,栈
    • 代码段:顺序执行
  • 时间局部性:相同的信息在不久的将来会再次访问,譬如循环的代码。

0x2 缓存如何工作


缓存的构造

下图是一个32位的,具有16个Set,2个way,每个缓存行256字节的高速缓存。
image.png

  • Tag:tag的位数由Set的个数和data的大小决定,tag = 32 - log2(sets) - log2(data) = 20

缓存读取流程

缓存一致性 - 图3

缓存行定位策略 优点 缺点
tag/index为虚拟地址 访问无需经过页表的转换
1. 进程切换会导致缓存失效
1. 共享的内存需要保存多份
tag/index为物理地址 与虚拟地址相反
tag为物理地址,inde为虚拟地址
(虚拟地址和物理地址具有相同的页内偏移,而且比高速缓存的index+offset大)
地址转换和高速缓存读取可以并行提高读取效率

缓存写入流程

  • 缓存存在的回写策略
    • write-back:只写缓存,只有缓存被淘汰的时候才需要写入内存
    • write_through:同时写缓存和内存
  • 缓存失效的写入策略
    • 写分配:分配缓存,将所需要写的数据写入缓存
    • 不按写分配:直接写入内存 | 回写策略 | 分配策略 | 当……时 | 写到…… | | —- | —- | —- | —- | | 写回 | 分配 | 命中 | 缓存 | | 写回 | 分配 | 失效 | 缓存 | | 写回 | 非分配 | 命中 | 缓存 | | 写回 | 非分配 | 失效 | 内存 | | 写通 | 分配 | 命中 | 快取和内存 | | 写通 | 分配 | 失效 | 快取和内存 | | 写通 | 非分配 | 命中 | 快取和内存 | | 写通 | 非分配 | 失效 | 内存 |

0x3 缓存一致性协议MESI


image.png

  • M(modified):已修改,这个时候缓存和主存是不一致的。
  • E(Exclusive):独占,这个时候缓存和主存是一致,并且只有当前这个cpu有这个缓存。可以直接修改缓存。
  • S(shared):共享,这个时候缓存和主存是一致的,有多个cpu都拥有该缓存,如果要修改缓存需要先广播一个消息让其他cpu置为无效,收到回复后再修改。
  • I(invalidated):已失效。

    状态机

image.png

存储缓存区

image.png

  • Q:cpu在写入一个数据到缓存的时候,需要先获取缓存的读写权限,这个时候需要等待其他cpu的回复。
  • A:在缓存和cpu之间增加store-buffer,先缓存要写入的数据,之后等到其他cpu回复再刷入缓存。

无效队列

image.png