嵌入式Linux驱动性能优化与cache刷新策略 - 第2节
2.1 Cache 的层次结构(L1 / L2 / L3)
现代嵌入式 SoC 普遍采用多级 Cache 架构,以平衡访问速度与芯片面积/功耗的矛盾。CPU 核心首先访问速度最快、容量最小的 L1 Cache;未命中时逐级向下查找,直至主存。各级 Cache 的典型参数如下表所示:
| 层级 | 典型容量 | 访问延迟(CPU cycles) | 关联方式 | 位置 |
|---|---|---|---|---|
| L1 Cache | 16 KB – 64 KB | 2 – 4 cycles | 指令/数据分离 | CPU 核心内 |
| L2 Cache | 128 KB – 512 KB | 10 – 20 cycles | 统一(指令+数据) | CPU 核心内或簇内 |
| L3 Cache | 512 KB – 2 MB+ | 30 – 50 cycles | 统一,多核共享 | SoC 全局 |
嵌入式要点: 在 Cortex-A 系列处理器中,L1 通常采用 Virtually Indexed Physically Tagged (VIPT) 方式,L2/L3 采用 Physically Indexed Physically Tagged (PIPT)。驱动开发者需要关注 Cache 行大小(通常 64 字节)对 DMA 缓冲对齐的影响。
2.2 Cache Line 与 Set Associativity
2.2.1 Cache Line(缓存行)
Cache 与主存之间数据交换的最小单位称为 Cache Line。ARMv8 架构中 Cache Line 大小固定为 64 字节(部分 Cortex-M 系列为 32 字节)。这意味着即使 CPU 只访问 1 字节数据,Cache 控制器也会将整个 64 字节块加载到 Cache 中。
驱动影响: DMA 缓冲区的起始地址和长度必须 Cache Line 对齐(通常 64 字节对齐),否则 Cache 刷新/无效操作可能破坏相邻数据。
2.2.2 关联方式对比
| 关联方式 | 映射规则 | 硬件复杂度 | 命中率 | 典型应用 |
|---|---|---|---|---|
| 直接映射 | 主存地址 → 唯一 Cache 槽位 | 低 | 低(冲突频繁) | 早期嵌入式 MCU |
| 全相联 | 任意地址 → 任意空闲槽位 | 极高 | 最高 | TLB 缓存 |
| 组相联(Set Associative) | 地址 → 固定组,组内多路选择 | 中 | 高 | 主流 ARM Cortex-A |
2.2.3 组相联(Set Associativity)工作原理
以 4 路组相联 为例:Cache 被划分为若干组(Set),每组包含 4 个 Cache Line 槽位(Way)。主存地址中的 Index 字段决定数据属于哪个组,Tag 字段用于组内比较。替换策略通常采用 LRU(最近最少使用)或伪 LRU。
2.3 Cache 的写策略:Write-Through vs Write-Back
2.3.1 策略对比
| 特性 | Write-Through(写通) | Write-Back(写回) |
|---|---|---|
| 写操作流程 | 同时写入 Cache 和主存 | 仅写入 Cache,标记脏位 |
| 主存一致性 | 始终一致 | 仅在 Cache Line 被替换或显式刷新时同步 |
| 写延迟 | 高(等待主存写入完成) | 低(仅写入 Cache) |
| 总线带宽消耗 | 高(每次写都触发总线事务) | 低(脏行替换时才写回) |
| 典型应用 | 早期处理器、对一致性要求严格的 I/O 区域 | 现代高性能 CPU、DMA 缓冲区 |
驱动陷阱: 使用 Write-Back 策略时,如果 DMA 设备直接访问主存,而 CPU 修改过的数据仍留在 Cache 中(脏行),DMA 将读到过时的数据。必须调用
dma_map_single() 或显式执行 flush_dcache_range() 保证一致性。
2.3.2 写策略与 Cache 一致性协议
在多核系统中,每个核心的私有 L1/L2 Cache 可能持有同一主存地址的不同副本。MESI 协议(Modified / Exclusive / Shared / Invalid)通过状态转换维护一致性:
- Modified(M): 该行仅在本 Cache 中有效且已被修改(脏),主存副本过时。
- Exclusive(E): 该行仅在本 Cache 中有效且与主存一致。
- Shared(S): 该行在多个 Cache 中有效且与主存一致。
- Invalid(I): 该行无效,需要从其他 Cache 或主存重新获取。
2.3.3 驱动开发中的写策略选择
- 普通数据内存: 使用 Write-Back 策略获得最佳性能,配合
dma_alloc_coherent()或dma_map_single()管理一致性。 - 设备寄存器/MMIO 区域: 必须使用 Device memory 类型(nGnRnE 属性),禁止 Cache 缓存,或使用 Write-Through 策略确保写操作立即到达设备。
- 共享内存(多核间): 使用 Write-Back 时,必须通过
smp_mb()和 Cache 维护指令(如DC CVAC)保证跨核可见性。
性能优化提示: 在 Write-Back 策略下,批量写入数据后只执行一次 Cache 刷新(而不是每次写入都刷新),可显著降低总线流量。例如网络驱动中,将多个小数据包合并为一个大缓冲区后再刷新。