Memory Consistency(上)

Memory Consistency


前言

Memory Consistency Model 介绍

之前我们介绍了Cache Coherency cache一致性, cache一致性会对多核处理器读取到数据的正确性,而memory consistency 则决定了多核处理器所看到的数据的顺序,即memory order。


一、Memory Consistency Model是什么?

Memory Consistency Model 定义了CPU见到的memory的访问次序。包括sequence order,pc order;弱序 weak order;释放一致性;惰性释放一致性。

Memory Coherency的规范决定了多核处理器读到数据的正确性,典型的moesi协议状态转换图如下:
在这里插入图片描述
我们考虑如下的情况:

P0:		P1:
S1: a = 1;	S3: ...=b;
S2: b = 1;  S4: ...=a;
			......
			S5: ...=a;

假设初始值数据a=0在P1的cache中缓存,b=0在P2的cache中缓存。如果P0,P1都是乱序执行的处理器,并且支持load乱序执行,那么P1 S4读到a时,可以直接从cache中获取,而S3读b时,需要等待S2执行完毕,也就是按照S4→S1→S2→S3的顺序执行,这样S4读到a的值为0;读到b的值为1。过了一段时间,重新读取a,这是,S1已经执行完毕,那么读到的a的值即为1。

这个case是满足cache moesi协议一致性的,也就是说,最终P1还是会读到修改过的b和a的值,只不过看到的修改memory的order不一致,这就是典型的弱序。

如果是强序的memory order,那么就会要求load→load,store→store保序,也就是说,只存在:

  • S1→S2→S3→S4
  • S1→S3→S2→S4
  • S3→S1→S2→S4
  • S3→S4→S1→S2

是不会存在S4→S1→S2→S3的顺序,也就不存在读取到A,B(0,1)的情况。

二、各个memory order介绍

1.sequence order

sequence order即序列一致性。Lamport【大神已经获得图灵奖,有一篇他定义Sequence Order, SC的paper】:如果每个处理器的操作都是以某种顺序的次序执行,每次执行的结果都相同,且这个序列中每个独立的处理器的操作都以程序指定的次序发生,则称该多处理器是顺序一致的。

P0:		P1:
S1: a = 1;	S3: ...=b;
S2: b = 1;  S4: ...=a;

因为保证了顺序一致性,因此P2中读到的(a,b)的最终值,可能是(0,0),(1,0),(1,1),但是(0,1)的值不可能。

P0:			P1:
S1: a = 1;		S3: b=1;
S2: ... = b;	S4: ... = a;

同理,P2中读到的(a,b)的最终值,可能是(1,0),(0,1),(1,1),但是(0,0)的值不可能。

SC Model的工作机制如下图所示:
在这里插入图片描述

1.1 基于总线的多处理器SC实现

在SC的基本实现中,存储器访问彼此之间必须原子地执行。最简单且正确的的原子操作的方法是每次只执行一个存储器访问操作,使存储器访问操作之间不重叠。
我们来看一下load和store会影响memory order的时机。
首先load的执行,在逻辑上分为4步

  1. 计算有效地址
  2. 向存储器发起访问请求
  3. 存储器返回地址对应数值
  4. 将值交回load指令对应的目标寄存器

store的执行:

  1. 计算有效地址
  2. 将地址和值写入写缓冲区(FIFO)
  3. 轮到当前store执行时,如果系统存在其他副本,首先需要无效其他副本
  4. 写入存储器

考虑到计算地址,写入寄存器或者FIFO的行为都是处理器本地的局部行为,我们认为:

  • Load指令在从高速缓存获得所需的值时即完成执行
  • Store指令在其独占读请求到达总线时即完成执行

考虑如下的指令序列:

S1: ld R1,A
S2:  ld R2,B
S3:  st C, R3

在S1执行前,不能向高速缓存发送第二个load,因为第一个load cache miss, 第二个load cache hit, 这样就破坏了memory sequence。 S3同样也要等到S2 执行完毕才可以发出。

当前的处理器为了挖掘指令集的并行性都采用了指令乱序执行技术,而像sequence order这样严格的序列,不允许后续的read指令提前发出,会降低运行时的性能,意味着非阻塞式的高速缓存失去了效用,并且编译器编译代码时进行的针对存储器访问次序的优化也被禁止,因此极大的限制了处理器的性能。

那么如何提高支持SC机制的处理器的性能呢?

  • prefech 数据,将数据提前预取到低级cache中
  • 投机执行,即使memory order不允许,但是我们仍旧可以投机执行。只不过如果在投机执行后,收到了来自外部的失效请求,那么投机执行reflow。

2 松弛的一致性模型

2.1 safety net

考虑到支持SC Model,对处理器性能影响很大,因此为了让程序员能够指明对存储器访问之间的严格次序,典型的做法是提供安全网, safety net。典型的安全网是以栅栏(fence) 指令实现的。

栅栏指令:
在位于它之前的存储器访问都已经执行完毕之前,禁止执行它后面的存储器访问。比如X86指令集中的mem fence, store fence,load fence。

那么如何实现栅栏指令呢?
在碰到一条栅栏指令时,流水线中跟在栅栏指令之后的存储器的指令都被flush(如果还未取指,则不取)。等栅栏指令之前的指令执行完毕之后,恢复到栅栏指令点的状态。然后执行后续指令。

2.1 处理器一致性

SC一致性要求保证load→load,store→store,store→load,load→load的次序。处理器一致性(PC)模型中放松了store→load一致性。当一条store指令还未被执行(也就是发出无效请求到总线)时,允许较晚的load执行向高速缓存发出请求甚至结束。

这样store指令会将地址和数据放到write buffer 写缓冲区中排队并在稍晚执行,load无需等待较早的store结束就可以访问高速缓存,并且如果后续的load和前面的store是相同的地址,也write buffer也可以直接将数据forward给后面的load(PC和total store ordering TSO支持)。

在这里插入图片描述

2.1.1 AMD Memory Model

AMD和Intel都是支持TSO(total strong order, 处理器一致性的一个变种),我们看一下AMD对其的支持:

  • load 不能和之前的load乱序。Store也不能pass 之前的store。
    Forbidden: B读到1,A读到0
    Forbidden: B读到1,A读到0

  • store 不能pass 之前的load 在这里插入图片描述
    Forbidden: B读到1,A读到1

  • 同一个处理器执行store是按照program order执行的,但是因为存在store buffer,因此会存在延迟。
    在这里插入图片描述
    读A和读B都可能读到1.

  • Non-overlapping Load 可以pass stores
    在这里插入图片描述
    A和B可以读取到(1,0),(1,1),(0,0),(1,1)。注意,序列一致性SC是不允许出现(0,0)的。

  • 处理器局部所见的顺序可能和全局的顺序不一致。不过program order仍然是一致的。
    在这里插入图片描述
    P0可以读到A = 1;B=0; 但是P1 读到A=0,B=1; 注意,这在序列一致性SC也是不允许出现的。 在total strong order(TSO)中,对P0发起的store操作和P1发起的store操作的相对关系是不限制的

    那么如何保证上述的一致性呢?可以在两边的store操作后都加上MFENCE操作,这样会清空流水线,保证一致性。

2.1.2 Intel Memory Model

摘自“Intel Architecture Memory Ordering White Paper”:
1.Loads are not reordered with other loads.
2.Stores are not reordered with other stores.
3.Stores are not reordered with older loads.
4.Loads may be reordered with older stores to different locations but not with older stores to the same location.
5.In a multiprocessor system, memory ordering obeys causality (memory ordering respects transitive visibility).
6.In a multiprocessor system, stores to the same location have a total order.
7. In a multiprocessor system, locked instructions have a total order.
8.Loads and stores are not reordered with locked instructions.

即:

  1. load,load之间保序
  2. store,store之间保序
  3. load可以和之前的不同目标地址的store乱序,但和之前的相同地址的store保序
  4. 在多核系统中,store order保序可迁移
  5. 在多核系统中,对同一个地址的存储有total order
  6. 在多核系统中,lock指令有total order
  7. store 和load 与lock指令保序

Intel和AMD的memory order是一致的,简单的case在2.1.1中已经介绍过,我们再看看其他的case:

P0:			P1:			P2:
S1: a = 1;		S2: s2 = a;		S4: s4 = b 
				S3: b = 1;		S5: s5 = a

Forbidden: s2 =1 & s4=1 & s5 = 0 (初始值a=0,b=0)

以上的结果所示不可存在,是因为如果S4 看到了1,那么S3肯定已经执行完毕。而load→store保序,并且s2读到了1,那么,顺序就应当是S1→S2→S3→S4,又因为load→load保序,所以S5一定读到的是最新的a的值,即为1。

P0:			P1:			P2:				P3:
S1: a = 1;		S2: a = 2;		S3: s3	= a;	S5: s5 = a;
								S4: s4	= a;	s6: s6 = a;

Forbidden: s3 = 1 & s4 = 2 & s5 = 2 & s6 = 1
按照第五条,对同一个地址的store操作是保序的,既然P2可以读到 s3 = 1 , s4 = 2;那么时间线上就一定是S1→S2;所以P3不可能读到 s5 = 2,s6 = 1。

在这里插入图片描述

欢迎关注我的公众号《处理器与AI芯片》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值