CPU缓存的访问机制

CPU缓存的访问机制 1. 缓存里面到底存了什么以32KB L1 Data Cache8 路组相联64 字节 Cache Line为例。可以把整个缓存看成一张二维表共有64 组Set 0 ~ Set 63每组有8 路Way 0 ~ Way 7每路就是一个缓存条目里面包含组成部分说明Valid bit1 位表示这个条目里是否存放了有效数据上电或刷新后为 0防止误匹配Dirty bit1 位写回策略时用表示这行数据被修改过和内存不一致将来替换时要写回Tag地址的高位部分用来唯一标识这个 Cache Line 对应的是哪一块内存Data Block64 字节的连续数据也就是常说的那个Cache Line 数据可能还有LRU 位用于记录访问历史帮助替换策略选择丢掉哪一路所以“缓存行”不只是一个数据块它是Tag 状态位 64 字节数据块的整体。2. 怎么判断数据在不在缓存里地址被怎样拆分假设我们运行在32 位物理地址的 CPU 上举例方便。缓存配置32KB8 路组相联行大小 64 字节。2.1 先算出三个部分的位数块内偏移 Offset64 2⁶需要6 位用于在 64 字节里选具体字节。组数总条目 32KB / 64B 512。8 路组相联 ⇒ 组数 512 / 8 64 组。需要6 位组索引。Tag 位剩下的高位 32 - 6 - 6 20 位。2.2 地址拆分图32 位物理地址|←——— Tag 20 位 ———→|← Index 6 位 →|← Offset 6 位 →| [31 .. 12] [11 .. 6] [5 .. 0]字段位数位域示例作用Tag20[31:12]存放在缓存条目里用来“对号”确认是哪一块内存Index6[11:6]选出64 组中的哪一组Offset6[5:0]在 64 字节的块里找到CPU 真正要的那个字节3. 查找过程Tag、Index、Offset 如何联动当 CPU 执行一条 LOAD 指令比如mov eax, [0x12345678]物理地址就是0x12345678。拆地址Offset 低 6 位Index (地址 6) 的低 6 位比如得到 0x1A第 26 组Tag 剩下的高位 0x48D15 之类选中组用 Index 找到第 26 组这个组里有 8 个 Way。并行比较 Tag把该组 8 路的Tag 和 Valid 位一起读出来实际硬件同时做和当前地址的 Tag 比对而且要求 Valid1。命中 (Hit)假如 Way 3 的 Tag 完全相等且 V1那就是命中。选中 Way 3 的 64 字节 Data Block用 Offset 从这 64 字节中提取所需的 4 字节或 1 字节返回给 CPU 寄存器更新 LRU 信息表示 Way 3 刚被访问过缺失 (Miss)如果 8 路里没有任何一个 Tag 匹配或者 V0就是未命中。硬件暂停流水线向下一级存储L2 / L3 / 内存发出“读取整块 64 字节”的请求数据回来后放入当前组第 26 组的某一 Way比如根据 LRU 选一个最近最少使用的 Way如果要替换的 Way 的 Dirty bit 为 1说明它曾修改过需要先把这 64 字节写回内存将新块的 Tag 写入该 Way设置 Valid1Dirty0然后像命中一样从新块里用 Offset 取数据返回 CPU4. 其他关键标志位Valid Dirty 等Valid (V)开机时所有 Valid0。不加这一位垃圾 Tag 可能和数据匹配读到错数据。Dirty (D)只在写回write-back策略下有效。如果 CPU 写过这个缓存行D1表示它比内存新。将来被替换时必须写回内存如果 D0可以直接丢弃。LRU 位 / 伪 LRU 位记录这一组里各 Way 的访问新旧顺序用来决定踢谁。MESI 等一致性状态位多核系统里标记该行是 Modified / Exclusive / Shared / Invalid保证多核看到的数据一致。5. 完整流程从一条 LOAD 指令到拿到数据以物理地址访问 L1 Data Cache为例屏蔽 TLB 细节。指令发出LOAD R1, [A]A 是物理地址地址拆分硬件抽取 Index6 位、Offset6 位、Tag高位访问 L1 数据缓存用 Index 找到 Set读出该 Set 所有 8 路的 Tag、Valid、Dirty、Data 块Tag 比较 Valid 检查比较器组并行工作(Way[i].Tag A.Tag) Way[i].Valid命中路径选路信号控制一个多路选择器挑中 Way[i] 的 64 字节数据再根据 Offset 做字节移位/选择得到最终数据数据返回 CPULOAD 完成缺失路径生成缺失请求物理地址 A发往 L2L2 同样用它的 Index/Tag 查找若 L2 命中则返回整块 64B否则继续向 L3/内存最终 64 字节数据抵达 L1填入指定 Set 的替换 Way更新 Tag、Valid、重置 Dirty可能更新 LRU然后重新执行第 3 步或直接旁路将数据同时返回 CPU6. 一个刻在脑子里的生活比喻图书馆档案室想象一个图书馆档案室馆内有64 个书架→ 这对应64 组 (Set)每个书架有8 层→ 这对应8 路 (Way)每层可以放一个档案盒→ 这就是一个Cache Line 条目档案盒里正好有64 页纸→ 这对应64 字节数据块档案盒书脊上贴着标签 (Tag)→ 写明了“这是哪一本档案的第几卷”盒子上还有一张“有效”便利贴 (Valid)→ 空盒子没有便利贴不能拿给读者如果有人在盒子里涂改了就贴一张“已修改”(Dirty)便利贴现在有读者要查阅地址 A的第 K 页根据地址里的书架编号 (Index)直接走到那个书架前。扫一眼这个书架的8 层比较书脊上的标签Tag和地址里的 Tag并且必须看到“有效”便利贴。如果找到标签匹配、且有效的档案盒 →命中。从盒子里翻到第 K 页 (Offset)交给读者。如果这个书架 8 层都没有匹配的标签或者盒子无效→缺失。管理员去仓库内存找到对应的档案盒拿回来如果书架满了根据“最少借阅”记录选一层把旧盒子取下来。如果旧盒子贴着“已修改”必须先把它的内容抄回仓库写回。新盒子放上去贴上正确的标签和“有效”便利贴把第 K 页交给读者。这样一来缓存行就是那个连盒带签的档案盒。组相联就是书架固定、但书可以灵活放在任意一层。Tag/Index/Offset就是找书架、看标签、翻页数的过程。Valid/Dirty就是盒子上的便利贴。有了这个书架模型整个缓存查找和替换的直觉就非常牢固了以后很难再混淆。