3. Cache基础:Cache工作原理与命中缺失分析

Cache(高速缓存)是位于CPU与主存之间的高速存储层次,其核心目标是利用程序的时间局部性和空间局部性,减少CPU访问主存的平均延迟。在DMA传输与内存池设计中,Cache行为直接影响数据一致性和性能,因此理解Cache的底层结构是调试Cache一致性问题的前提。

3.1 Cache行(Cache Line)—— 最小传输单元

Cache与主存之间的数据交换不是以字节为单位,而是以Cache行为基本单元。Cache行是Cache存储的最小粒度,通常为32字节、64字节或128字节(ARM Cortex-A系列多为64字节)。

属性 说明
行大小 典型值:32B / 64B / 128B,由硬件设计决定
有效位 标记该行是否包含有效数据(1 bit)
标签 用于匹配地址的高位部分,判断是否命中
数据块 实际存储的连续内存数据
脏位 写回策略中,标记该行是否被修改(1 bit)
关键认知: 即使CPU只读写1个字节,Cache也会将整个Cache行从主存加载进来。DMA传输时,如果DMA修改了主存中某个Cache行内的部分数据,而CPU对应的Cache行尚未失效,就会产生Cache一致性问题。

3.2 Cache映射方式:直接映射、组相联、全相联

Cache映射方式决定了主存地址如何映射到Cache中的位置。三种主流方式在硬件复杂度、命中率和灵活性上各有取舍。

3.2.1 直接映射(Direct-Mapped Cache)

每个主存地址只能映射到Cache中唯一的一个行位置。地址被划分为:标签(Tag) + 索引(Index) + 块内偏移(Offset)。

  • 优点: 硬件简单,查找速度快(只需一次比较)。
  • 缺点: 冲突率高,多个频繁访问的地址映射到同一行时,会反复替换(抖动)。
DMA场景提示: 直接映射Cache中,如果DMA缓冲区和CPU频繁访问的变量映射到同一Cache行,即使数据不相关,也可能因冲突导致Cache行频繁换入换出,降低性能。
直接映射Cache结构 Tag(标签) Index(索引) Offset(偏移) 主存地址分解 Cache行阵列 行0 Tag V Data(64B) 行1 Tag V Data(64B) 行N Tag V Data(64B) 映射规则 Index = (地址 >> Offset位宽) mod Cache行数 每个地址只对应唯一行

3.2.2 组相联(Set-Associative Cache)

将Cache行分成若干组(Set),每个主存地址可以映射到某一组内的任意一行。组相联是直接映射和全相联的折中方案,也是现代处理器中最常用的映射方式。

  • n路组相联: 每组包含n个Cache行。例如4路组相联,每组有4个位置可选。
  • 优点: 冲突率低于直接映射,硬件复杂度可控。
  • 替换策略: 组内通常使用LRU(最近最少使用)或伪LRU算法。
4路组相联Cache结构 Tag(标签) Set Index(组索引) Offset(偏移) Cache组阵列 组0 Tag V Data Tag V Data 组1 Tag V Data Tag V Data 组N Tag V Data Tag V Data 4路组相联 每组4行 地址可映射到 组内任意行 替换策略:LRU

3.2.3 全相联(Fully-Associative Cache)

任何主存地址可以映射到Cache中的任意一行。没有索引字段,地址只分为标签和偏移。

  • 优点: 冲突率最低,空间利用率最高。
  • 缺点: 硬件实现复杂,比较器数量多,查找延迟高,通常仅用于TLB(页表缓存)等小型Cache。
映射方式 冲突率 硬件复杂度 查找速度 典型应用
直接映射 高 低 快 早期处理器、简单微控制器
组相联 中 中 中 ARM Cortex-A、x86 L1/L2 Cache
全相联 低 高 慢 TLB、小容量专用Cache

3.3 Cache命中与缺失

CPU访问内存时,Cache控制器根据地址查找Cache行,判断是否命中。

3.3.1 命中(Hit)与缺失(Miss)定义

  • Cache命中: 所需数据在Cache中,CPU直接从Cache读取,延迟极低(通常1~3个时钟周期)。
  • Cache缺失: 所需数据不在Cache中,CPU必须从主存加载整个Cache行,延迟较高(几十到几百个时钟周期)。

3.3.2 缺失类型(3C模型)

缺失类型 英文 原因 优化方向
强制缺失 Compulsory Miss 第一次访问该数据,Cache中从未加载 预取、大Cache行
容量缺失 Capacity Miss 工作集超过Cache容量,导致行被替换 增大Cache、优化数据布局
冲突缺失 Conflict Miss 多个地址映射到同一Cache位置,互相替换 提高相联度、地址重排
DMA一致性风险: 当DMA将数据写入主存时,如果CPU的Cache中对应行是脏(Dirty)状态,CPU尚未写回,DMA直接修改主存会导致数据丢失。这是Cache一致性调试中最常见的问题之一。

3.4 Cache查找流程

以组相联Cache为例,一次完整的访问流程如下:

  1. 地址分解: 从CPU地址中提取组索引(Set Index)。
  2. 定位组: 根据组索引找到对应的Cache组。
  3. 并行比较: 将地址标签与组内所有行的标签同时比较。
  4. 命中判断:
    • 若标签匹配且有效位为1 → 命中,直接读取/写入数据。
    • 若标签不匹配或有效位为0 → 缺失,触发Cache填充。
  5. 缺失处理:
    • 若组内有空行(有效位为0),直接加载数据。
    • 若组内全满,按替换策略(如LRU)淘汰一行,若该行脏则写回主存,然后加载新数据。
Cache访问流程(组相联) CPU发出内存访问 提取组索引(Set Index) 定位到对应Cache组 标签与组内所有行并行比较 命中? 命中:直接读写数据 缺失:触发Cache行填充 缺失处理 1. 选择替换行(LRU) 2. 若脏则写回主存 3. 从主存加载新行

3.5 Cache与DMA工程实践要点

工程经验: 在DMA内存池设计中,Cache的映射方式决定了地址对齐策略和Cache刷写粒度。
  • Cache行对齐: DMA缓冲区起始地址和大小应尽量对齐到Cache行边界(如64字节),避免一个Cache行被DMA和CPU部分修改。
  • Cache行大小查询: 在Linux中可通过以下命令获取:
# 查看L1 Cache行大小
cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size

# 查看所有Cache层级信息
ls /sys/devices/system/cpu/cpu0/cache/
  • 映射方式影响: 直接映射Cache中,如果DMA缓冲区和CPU热点数据索引相同,冲突缺失会显著增加。此时可考虑地址偏移或内存池地址重排。

3.6 本章小结

知识点 核心要点
Cache行 最小传输单元,典型64字节,包含Tag、有效位、脏位、数据块
直接映射 地址唯一映射到一行,硬件简单但冲突高
组相联 地址映射到组内任意行,折中方案,现代处理器主流
全相联 任意地址可映射到任意行,冲突最低但硬件复杂
命中/缺失 命中直接访问,缺失需加载主存;3C模型:强制、容量、冲突
DMA关联 Cache行对齐、脏行写回、地址冲突是Cache一致性调试的关键