01.CPU缓存相关知识

@ref: 与程序员相关的CPU缓存知识 | 酷 壳 - CoolShell

CPU Cache基础

  • 一般来说, CPU Cache分三级: L1/L2/L3
  • CPU Cache大小: L1 < L2 < L3
    • 例如:Intel Core i7-8700K ,是一个6核的CPU,每核上的L1是64KB(数据和指令各32KB),L2 是 256K,L3有2MB
  • 读取速度: L1> L2> L3
    • L1 = 4个时钟
    • L2 = 11个时钟
    • L3 = 39个时钟
    • 内存= 107个时钟
  • L1 分指令和数据Cache, 每个Core各一个指令和数据Cache, 每个Core一个L2, 所有Core 共享L3(见下图)

../_images/CPU_CACHE.png

CPU Cache命中

➤ Cache Line 和N-Way查找策略

  • 当要读取某个变量的值, 首先从CPU的L1 Cache里读, 读不到则取L2 Cache读…这样需要把内存地址映射到CPU Cache的某个地址
  • Cache Line: CPU把数据从内存加载到CPU Cache 并不是逐个字节加载的, Cache Line 是一次加载的最小单位, 一个主流的CPU的Cache Line 是 64 Bytes(也有的CPU用32Bytes和128Bytes)
  • CPU 一般使用”N-Way 关联” (N-Way Associative)方式, 比如8-Way :
    • 如果某CPU的L1 Cache有32KB, 则共有32KB/64 Bytes = 512个Line
    • 因为是 8 way,故每一 Way 的 Line 数有: 512/8= 64个
  • 此外,每个 Cache Line 前都有独立的 24 bit 来存”tag”, 也即内存地址的前 24 bit

../_images/CPU-Cache-8-Way.png

➤ 【图】8-Way Associative 如何对 Cache 进行查找(36 bits 的物理内存地址,映射到 L1 Cache 的过程)

  • 内存地址(36bit)分三部分: 24bit, 6bit, 6bit
    • Index: 中间6bit 可以索引 2^6 = 64 行 (下图每行是一组, Set), 中间6位也叫做”Set Index”, 该 Set 有8个 Line
    • Tag: 然后对这8个 Line(所以叫8Way) 进行 O(n) / n=8的遍历, 如果内存地址前24bit, 等于 Line 的 tag, 则找到了 Cache Line
    • Offset: 内存地址后6位, 是在该 Line 内的偏移
  • 通过内存的中间 6 位,寻找对应的 Set Index ,这一步是 O(1)的,然后通过前 24 位的 Tag 进行匹配,这一步是 O(n) n=8 的
  • 当 CPU Cache 未命中时, 会从内存(以 Cache Line 为最小单位)加载到 Cache, 但每次并不仅仅加载一个 Cache Line 的数据, 因为访问内存太慢了, CPU 会通过”预加载” (Prefetching)技术预先加载更多的内存到 CPU Cache. 比如,你在 for-loop 访问一个连续的数组,你的步长是一个固定的数,内存就可以做到 prefetching。

缓存一致性

@todo 未完待续