2. RISC-V基础回顾

各位同学,在正式进入 RISC-V 多核缓存一致性协议之前,我觉得有必要先把缓存的基础知识夯实一下。说实话,我见过不少工程师,一上来就研究 MESI 协议,结果连写回和写直达的区别都说不清楚——这就像还没学会走路就想跑马拉松。

缓存这东西,说白了就是一块离 CPU 更近、速度更快的小容量存储器。它的存在,就是为了填补 CPU 和主存之间那巨大的速度鸿沟。我个人习惯把缓存看作 CPU 的「工作台」——你常用的工具放在手边,不常用的收进柜子里。

2.1 局部性原理:缓存能工作的根本原因

为什么缓存能生效?答案就四个字:局部性原理。这不是什么高深理论,你想想看,程序执行时是不是总在反复访问同一块代码或数据?

  • 时间局部性:刚访问过的数据,很可能很快再次被访问。比如循环体里的变量,每次迭代都要读写。
  • 空间局部性:访问了某个地址,它附近的地址也很快会被访问。数组遍历就是典型例子——你访问了 a[0],紧接着就是 a[1]、a[2]……

核心观点:局部性原理是缓存设计的理论基础。没有局部性,缓存就毫无意义。

我在项目中遇到过这样一个案例:某团队优化一个图像处理算法,发现缓存命中率只有 30%。后来一查,代码里把图像数据按列遍历,而不是按行——这完全违背了空间局部性。改成按行访问后,命中率直接飙到 85%。你看,理解局部性原理,比盲目调参有用得多。

2.2 缓存组织方式:三种映射结构

缓存怎么把主存地址映射到自己的存储单元?主要有三种方式。嗯,这里我建议你重点理解组相联,因为它是现代处理器的主流选择。

组织方式 映射规则 优点 缺点 典型应用
直接映射 每个主存块只能映射到缓存中唯一的位置 硬件简单、访问速度快 冲突率高,容易颠簸 早期处理器、简单嵌入式
全相联 任何主存块可映射到任何缓存行 冲突率最低,利用率高 硬件复杂,比较器太多,速度慢 TLB(页表缓存)
组相联 缓存分成若干组,组内全相联,组间直接映射 冲突率适中,硬件复杂度可控 比直接映射稍复杂 现代 CPU 的 L1/L2 缓存

直接映射:说白了就是「一个萝卜一个坑」。主存地址的某些位直接决定它该放哪个缓存行。好处是查找快——看一眼地址就知道有没有命中。坏处呢?如果两个频繁访问的地址恰好映射到同一行,就会互相踢来踢去,这叫「颠簸」。我曾经调试过一个网络包处理程序,性能忽高忽低,最后发现就是直接映射导致的颠簸问题。

全相联:这个就灵活多了,任何数据可以放在任何位置。但代价是什么?每次访问都要和所有缓存行比较,硬件上需要大量的比较器。你想想看,一个 64KB 的缓存,如果全相联,每次访问要同时比较上千个标签——这延迟谁受得了?所以全相联一般只用在条目数很少的场景,比如 TLB。

组相联:这是工程上的最佳折中。把缓存分成若干组,组内是全相联,组间是直接映射。比如 4 路组相联,就是每组有 4 个位置。这样既控制了比较器的数量(每组只需要 4 个),又大大降低了冲突率。现代处理器的 L1 缓存通常是 4~8 路组相联,L2 可能是 8~16 路。

我的建议:做多核缓存设计时,组相联的路数选择很关键。路数太少,冲突率高;路数太多,访问延迟和功耗都会增加。一般 4~8 路是比较平衡的选择。

2.3 写策略:写直达 vs 写回

缓存读操作相对简单——命中就直接读,没命中就从下一级取。但写操作就复杂了,因为要处理缓存和主存之间的数据一致性。这里有两种基本策略。

写策略 操作方式 优点 缺点 适用场景
写直达 写缓存的同时也写主存 实现简单,主存始终最新 写操作慢,带宽浪费严重 对一致性要求极高、写操作少的系统
写回 只写缓存,被替换时才写回主存 写操作快,带宽利用率高 实现复杂,需要脏位标记 现代高性能处理器

写直达:每次写操作,既要更新缓存,也要更新主存。好处是主存里的数据永远是最新的——这对多核系统来说很诱人,因为其他核可以直接从主存读到最新值。但代价呢?每次写操作都要等慢速的主存,性能大打折扣。我记得早期的一些嵌入式处理器就用写直达,因为实现简单,但后来基本都被写回取代了。

写回:写操作只更新缓存,并标记该缓存行为「脏」(dirty)。只有当这个脏行被替换出去时,才把数据写回主存。这样大部分写操作都只发生在高速缓存里,性能好得多。但问题来了——主存里的数据可能是过期的。在多核系统中,这就需要一个一致性协议来协调各个核的缓存视图。

注意:写回策略中的「脏位」是实现的关键。每个缓存行都需要一个额外的 dirty bit。我在设计一个 RISC-V 多核原型时,就曾因为漏掉了脏位的处理,导致数据写回时覆盖了其他核的更新——那调试过程,简直不堪回首。

2.4 知识结构总览

下面这张图把本章的核心知识点串了起来。你可以把它当作一个思维导图来理解。

缓存基础知识体系 缓存基础知识 局部性原理 时间局部性 空间局部性 缓存组织方式 直接映射 组相联 全相联 写策略 写直达 写回 核心要点 • 局部性原理是缓存能生效的根本原因 • 组相联是工程上最平衡的缓存组织方式 • 写回策略是现代高性能处理器的首选,但需要一致性协议配合

2.5 缓存行与标签结构

不管哪种组织方式,缓存的基本单元都是「缓存行」(Cache Line)。一个缓存行通常包含以下几部分:

  • 有效位:标记该行是否包含有效数据
  • 标签:存储主存地址的高位部分,用于判断是否命中
  • 数据块:实际存储的数据,通常是 32~64 字节
  • 脏位(仅写回策略):标记该行数据是否被修改过

关键点:缓存行的长度(即数据块大小)直接影响空间局部性的利用效果。行太长,浪费带宽;行太短,空间局部性利用不充分。64 字节是当前的主流选择。