前言
在物理层面我们看到的数据传输只是高低电平的交替,并不知道每一部分对应什么内容。因此在SerDes层面加入的抗串扰编码是直接作用于物理层的。然而大模型的压缩编码仅仅针对于被传输的实际数据本身,并不会作用于其他一些控制位地址位。要研究两者的平衡我们必须知道这些数据是如何被封装传输的。
研究的物理背景
CPU直接读取DRAM当中的数据,假设这一部分数据全部没有被读取过,因此在三级缓存查询中均miss,直接从内存读取。
Cache Line
+--------------------------------------------------+
| Tag | State | Dirty | Valid | (其它控制位) | Data |
+--------------------------------------------------+
↑
64 Bytes
数据都是被封装在cache line中被传输的,一个cache line的数据部分典型大小(英特尔x86)是64字节,前部还附加了控制位。控制位包含标记位,有效位,一致性状态位,脏位,以及一些其他自定义的位。
Data Block(数据块)
这是cache line的主体:
大小:通常64字节
内容:普通数据(load/store)或指令(I-cache)
这是唯一会从内存读入,被写回内存,且经由DDR burst传输的部分。
Tag(标记)
Tag记录这64B数据对应内存中的哪一段地址。
地址拆分(以64B line为例):
| Tag | Index | Offset |
Offset:6 bit(2⁶ = 64B)
Index:决定落在哪一组(set)
Tag:剩余高位地址
Valid bit(有效位)
表示这一条 cache line 是否包含有效数据
cache 冷启动时全部为 0
Dirty bit(脏位,D-cache)
只存在于写回型 cache
表示数据是否被 CPU 修改过
dirty line 被替换时才需要写回内存
一点附加解释:
因为 cache 是由多级组成,所以写策略一般而言有两种:写直达(write-through)和写回(write-back)。通过这两种策略使在 cache 中写入的数据和主存中的数据保持一致。
写直达就是在将数据写入 cache 之后同时将这个数据立马写入到主存中,但是由于主存和 cache 本身性能差异,那么每次在写入主存的时候都将花费大量的时间。解决办法就是加一层写缓冲(write buffer),这样 CPU 在将数据写入 cache 和缓冲之后可以继续执行,等到缓冲写入到主存中再释放。
但是如果写入速度大于缓冲释放速度,那么还是会阻塞 CPU 执行。那么可以考虑一下写回策略,这种机制会在每次写入的时候仅将新值写入 cache 中,只有当修改过的块被替换时才需要写到较低层存储结构中。脏位就是用以标注这种情况。
Cache Coherence State(一致性状态位)
由于现在都是多核 CPU,并且 cache 分了多级,并且数据存在共享的情况,所以需要一种机制保证在不同的核中看到的 cache 数据必须时一致的。最常用来处理多核 CPU 之间的缓存一致性协议就是 MESI 协议。
MESI 协议,是一种叫作写失效(Write Invalidate)的协议。在写失效协议里,只有一个 CPU 核心负责写入数据,其他的核心,只是同步读取到这个写入。在这个 CPU 核心写入 cache 之后,它会去广播一个“失效”请求告诉所有其他的 CPU 核心。
MESI 协议对应的四个不同的标记,分别是:
M:代表已修改(Modified)
E:代表独占(Exclusive)
S:代表共享(Shared)
I:代表已失效(Invalidated)
“已修改”和“已失效”比较容易理解,我们来看看 独占”和“共享” 两个状态。
在独占状态下,对应的 cache Line 只加载到了当前 CPU 核所拥有的 cache 里。其他的 CPU 核,并没有加载对应的数据到自己的 cache 里。这个时候,如果要向独占的 cache Block 写入数据,我们可以自由地写入数据,而不需要告知其他 CPU 核。
那么对应的,共享状态就是在多核中同时加载了同一份数据。所以在共享状态下想要修改数据要先向所有的其他 CPU 核心广播一个请求,要求先把其他 CPU 核心里面的 cache ,都变成无效的状态,然后再更新当前 cache 里面的数据。