关于 Coherence 的基础知识
我觉得我现在有点像是挑重点翻译原文……anyway,这反正是个人的读书笔记,我就随便写写好了。
在讨论 consistency 之前,我们需要先铺垫一点 coherence 的知识。
基线系统模型
我们考虑这样的系统:
- 有一个多核处理器和一块内存;
- 每个核心是单线程的,且每个核心有自己的 data cache;
- 所有核心共用一个 LLC (last-level cache) ;
- 用物理地址,write-back 策略
这个简单的系统模型已经足够支持下文的讨论了。
为什么会有 Incoherence
为什么呢?原文是这么说的:
there exist multiple actors with access to caches and memory
其中的 actor 有多种,但我们先只考虑处理器核心。
简单来说,考虑有两个核心,按时间顺序执行了下面的指令:
core 1 core 2
load r1, mem[A]
load r1, mem[A]
add r1, r1, #1
store r1, mem[A]
第一个核心先把mem[A]
读进自己寄存器里(为此,这个值进了第一个核心的 cache 里),第二个核心再把同样内存位置的值读进自己的 cache 里,然后第一个核心把这个值修改了一下并存回内存去(当然是先存到自己 cache 里)。然后两个核心的 cache 里的值就不一样了,这就是出现 incoherence 了。
如何定义 Coherence
作者用了两个 invariant 来定义 coherence。
SWMR Invariant
第一个是所谓 single-writer-multiple-reader (SWMR) invariant。我们假设对某一个内存位置的访问在时间上可以分成很多个阶段,那么这些阶段只能是如下两种:
- 有一个核心在写(也可能在读),我们叫它 read-write 阶段;
- 有零或多个核心在读,不能写,我们叫它 read-only 阶段。
Data-Value Invariant
第二个就更好理解了,就是说一个内存位置上的值在被写过之后要保持不变(直到下次被修改),且多个核心在读它的时候读到的都要是那个值。这个话讲起来好像有点绕,但反正意思大家都懂。一个比较 formal 的定义是,一个内存位置上的值在每个阶段开始时都要和它上一个 read-write 阶段结束时的值一样。
维护 Coherence Invariants
绝大多数 coherence protocol 都是所谓的 "invalidate protocol",专门设计来维护这些个 invariants。
- 如果一个核心想读一个内存位置,它就给其他核心发消息从而得到那个内存位置上的值,并且保证其他核心的 cache 中没有那个内存位置上的值。然后,read-write 阶段结束,read-only 阶段开始。
- 如果一个核心想写一个内存位置,它就在自己的 cache 没有这份数据的时候给其他核心发消息从而得到那个内存位置上的值,并且保证其他核心的 cache 中没有那个内存位置上的值。然后,不管先在是 read-write 阶段还是 read-only 阶段,一律结束,变成新的 read-write 阶段。
注:斜体中的表述似乎原文如此,但我没太明白……是不是说如果现在这个位置是 read-only 的,且有一个别的核心已经有个 cached copy 了,那这个核心就不用去内存中拿,而是直接从那个核心中拿数据就可以了啊……还是说现在这个位置是 read-write 的,确实有一个核心占领了这个位置,那么那个核心手里的 cached copy 就可以拿过来了。嗯,感觉是后者……
Coherence 的 Granularity
(这样的翻译真的有用吗)
上文中我们大量用“内存位置”这个不精确的表述。这个东西具体多大是可以变化的,但一般来说我们都会把 granularity 设置在 cache block 或者说 cacheline 这个级别。也就是说,我们探讨的内存位置的基本单位都是 block,而不是 byte 级别的。
Coherence 的范围
没太看懂,似乎大概意思是:coherence 适用于 L1d cache, L1i cache, L2 cache, LLC (namely L3 cache, 也许吧), 还有 main memory 和 TLB;但是 coherence 不是体系结构级别的(哈?啥意思?),有的系统是 consistent 但不 coherent 的。算了,讨论这些系统目前看来也没啥意义,不管了……