RISC-V RVWMO 内存模型解释
引言
本文介绍 RISC-V RVWMO 内存模型。RVWMO 内存模型定义了什么样的全局内存顺序才是合法的。本引言部分将解释为什么会出现不合法的全局内存顺序,以及为什么需要内存模型。
首先引起乱序的全局内存顺序(指令重排序)有两种原因,一种是软件编译器带来的,另外一种是硬件执行上带来的。
软件带来指令重排序很好理解,如下面的例子:
x = 1;
while(x)
x = memory[0];
y = 1;
在程序编译时期编译器无法预知多核执行的动态性,因此编译器可以认为语句 y = 1 和 x 的值没有必然联系,因此 y = 1 可能比 x = 1 先执行,从而跳过循环,在编译器看来这并不违反语义。
第二种由硬件执行产生的指令重排序,在单核单线程程序中,程序的执行的顺序看起来应该总是和程序设计的顺序一致,但是在硬件实现的视角中,情况却完全不同,首先我们定义对于内存操作,有两种内存操作原语,即读内存和写内存。
我们定义一个完成一个读操作是瞬时原子的,因为读操作不需要通知其他线程,因此读操作一旦完成,其他线程默认均可见。但是写操作的情况却完全不同,一个写操作可能不是原子,这有点反直觉,但确实如此,一个写操作需要通知所有其他线程修改了写地址上的内容之后,一个写操作才算完成,称为写可见性。
如果读取了一个未完成的写操作,即写操作还没有对所有的线程都可见,此时就会发生读非原子的写操作,此时读写会发生重排序,通常情况下,处理器内核通常具有写缓冲区,例如下面的例子:

程序依次发生的顺序为:
- 首先 P1 将
Flag1 = 1写入缓冲区,此时Flag1 = 1对线程 P2 不可见。 - P2 将
Flag2 = 1写入缓冲区,此时Flag2 = 1对线程 P1 不可见。 - P1 读取 Flag2 的值为 0,进入临界区。
- P2 读取 Flag1 的值为 0,进入临界区。
Flag1 = 1从写缓冲区写入内存。Flag2 = 1从写缓冲区写入内存。
在这种情况下,因为写的非原子性,产生了乱序的读写,导致两个线程同时进入临界区。但是写缓冲区带来了屏蔽等待写入时间的效果(将指令执行的时间重叠)。
除了写缓冲区,硬件还有其他的实现,例如 Overlapped writes, Non−blocking reads 这些都会产生读写的重排序。
不同的 Relaxed Memory 内存模型允许不同情况的重排序,RISC-V 采用了 RVWMO 内存模型,方便软件产生最大程度上的优化,以及最大程度上的硬件实现自由。
程序顺序、全局内存顺序以及保留程序顺序
在多线程内存模型中,存在三种程序执行顺序,即程序顺序、全局内存顺序以及保留程序顺序。最容易理解的是程序顺序,一个程序顺序定义为程序在指令流中的顺序,也是程序设计者所编写的顺序,例如对于一个 Hart 看到的指令流:
(a) li t1, 1
(b) sw t1, 0(s0)
(c) lw a0, 0(s0)
则称在程序顺序中指令 (b) 先于指令 (c) 。
上文已经解释过假设有两个线程 A 和线程 B ,为什么线程 B 看到 A 的执行顺序与线程 A 的程序顺序完全不同。而全局内存顺序定义了所有线程所看到的内存的全局性事件列表,例如对于两个 Hart 的指令流:
Hart 0:
(a) li t1, 1
(b) sw t1, 0(s0)
Hart 1:
(c) li t1, 2
(d) sw t1, 0(s0)
(e) lw a0, 0(s0)
则对于线程0来说,一种可能的全局内存顺序为: (c)(d)(a)(b)(e) ,即在事件 (c)(d) 结束后,线程0观测到了线程1的 (a)(b) 发出的全局事件,因此指令 (e) 读取到的值为1。
保留程序顺序在原文中的定义为:
Preserved program order represents the subset of program order that must be respected within the global memory order.
简单的理解为,因为全局内存顺序无法保证和程序顺序相同,但是为了程序语义的正确,至少必须保证程序顺序的一个子集,称为保留程序顺序,在全局内存顺序中和程序顺序相同。
RISC-V RVWMO 模型定义了13条保留程序顺序的规则和3条公理,本文剩下的部分将讲解这13条规则和3条公理。
3条公理
加载值公理(Load Value Axiom)
加载值公理定义了一个具有 load 语义的指令可以返回值,原文如下:
Load Value Axiom: Each byte of each load i returns the value written to that byte by the store that is the latest in global memory order among the following stores:
- Stores that write that byte and that precede i in the global memory order
- Stores that write that byte and that precede i in program order
也就是说 load 指令可以返回的值必须是在全局内存顺序以及在当前线程程序顺序中的最后一条 store 指令所写入的值。

本文详细介绍了RISC-V RVWMO内存模型,解释了出现不合法全局内存顺序的原因,阐述了程序顺序、全局内存顺序和保留程序顺序。还介绍了该模型的3条公理和13条规则,以及IO内存的相关特性,方便软件优化和硬件自由实现。
5572

被折叠的 条评论
为什么被折叠?



