Multicore Programming & MSI Protocol

189 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

为什么会出现多核结构

提高代码的并行性中,很有效的一个方式就是多核结构。

时钟频率无法再提高的原因是功率或者说热量。在传统的CMOS芯片中,每个晶体管所需要的能耗与该晶体管驱动的容性负载与电压平方的乘积成正比:

动态容性负载2能耗_{动态} \propto 容性负载 * 电压^2

该结果是逻辑转变脉冲从0->1->0或者1->0->1需要的能量,那么一次01转换的能耗就是:

动态12容性负载2能耗_{动态} \propto \frac{1}{2}容性负载 * 电压^2

那么每个晶体管锁需要的功率就是一次转换的能耗和转换频率的乘积:

动态12容性负载2开关频率功率_{动态}\propto \frac{1}{2}容性负载 * 电压^2*开关频率

从这一点我们可以看出,对于一个固定的任务,降低时钟频率可以降低功率,但是不会降低能耗。

而随着频率的提升,整体的功率提升,其产生的热量也会提升,这会极大的影响芯片的运行。因此厂商们将目光投向了多核结构。

抽象多核结构

我们将多核处理器进行高层次的抽象:

image-20230206201312342

可以看出,每个处理器(P)都拥有属于其自己的高等级cache($),多个处理器共用Network、Memory和I/O模块。为了能够让多核结构正确的运行,我们需要解决多核内存访问问题。

MSI协议

缓存一致性协议是多核内存访问中很重要的环节,因为缓存可以加速运行,这也需要我们去保证其一致性。

正常来说,缓存的读取是这样的:

image-20230206202218688

当处理器P1从内存中取出x时,其会被记载到cache中,同样的,其他的处理器读取x也会有这样的操作:

image-20230206202306005

一般来说,多读是没有问题的,因为并没有改变状态。但是涉及到写入的时候,就会出现冲突。我们假设处理器Pn要写入x=5:

image-20230206202359500

在这之后,处理器P1要使用到x的值,如果其再去读取缓存中x=3的结果,就会运行错误:

image-20230206202435514

因此,我们需要通知P1,x的值已经被修改了。于是就有了MSI协议。MSI协议是比较基础的缓存一致性协议,此处不涉及像MESI这样的更复杂的协议。

MSI协议中,每个cache line有一个标志位,记录其状态:

  • M:Modified,这个cache已经被修改了,在其他的cache中不能有同样的变量且为S或者M状态;
  • S:Sharing,这个cache块正在共享状态中;
  • I:Invalid,无效的cache块,需要更新。

我们举例来进行说明,假设初始状态四个处理器的Cache分别如下图所示:

image-20230206202745773

这时候,我们要修改P2中y的值。此时y处于S状态,说明其他处理器中有cache和它共享该变量:

image-20230206202832047

而此时我们需要修改y的值,所以P1和P4中的状态应该变为I,也即无效状态:

image-20230206202939522

而P2中的状态应该变为M状态,标志这个cache line经过了修改:

image-20230206203006472