Memory Model
Table of Contents
1. Memory Model
1.1. barrier
https://mariadb.org/wp-content/uploads/2017/11/2017-11-Memory-barriers.pdf
https://www.kernel.org/doc/Documentation/memory-barriers.txt
出于性能考虑, cpu/cache 等可以对内存访问进行各种优化, 例如 reorder, defer, combine 等, 通过 barrier 可以对这些优化进行限制, 以避免产生错误的程序, 例如:
1 /* thread1 */ 2 result = 2; 3 atomic ready = 1; 4 // thread 2 5 while (ready != 1) 6 ; 7 assert(result == 2);
上述代码可能会 abort, 因为 2/3 可能 reorder, 5/7 可能 reorder.
所谓的 reorder, 并非是两个指令通过乱序执行交换了顺序. 因为 ROB (reorder buffer) 会保证指令的 commit (例如内存的写回) 时按程序的顺序执行. 但 cpu 的`内存写回`和 `内存对其它 core 可见`并非一回事. 这里的 `reorder` 主要是指 memory model (cache, memory controller, …) 导致的 reorder, 例如 cache 导致数据没有写回, 或者 memory controller (例如 AXI memory controller) 导致的 reorder
为了保证上面的结果正确, 需要保证:
- 5/7 不能 reorder
- 2/3 不能 reorder
前者通过 acquire barrier 保证, 后者通过 release barrier 保证.
1.1.1. acquire barrier
acquire barrier (read barrier) 表示 barrier 前后的 read 操作不能交换位置.
riscv 中带 `aq` 后缀的原子指令 (amo/lr) 相当于一个 acquire barrier, aq 自身与 aq 之后的指令保持`顺序`不变, 即 `lr.aq; lw` 相当于 `lr; acquire_barrier; lw`
1.1.2. release barrier
riscv 中带 `rl` 后缀的原子指令 (amo/sc) 相当于一个 release barrier, rl 自身与 rl 之前的指令保持`顺序`不变, 即 `sc.rl; sw` 相当于 `sc; release_barrier; sw`
1.1.3. example
通过 aquire/release barrier, 可以解决前面提到的代码中的问题:
// thread 1 result = 2; __release_barrier__(); atomic ready = 1; // thread 2 while (ready != 1) __acquire_barrier__(); assert(result == 2);
Backlinks
AArch64 Tutorial (AArch64 Tutorial > AArch64 Assembly > instructions > Misc > LDXR/STXR/LDAXR/STLXR): LDAXR 类似于 RISC-V 的 lr.aq, STLXR 类似于 RISC-V 的 sc.rl, 即包含隐式的 barrier 语义
CAS (RISC-V Tutorial > Standard Extention > RV32A > CAS): 另外, AMO 和 LR/SC 都支持额外的 ordering 信息 (aq/rl), 可以做为 barrier 使用
1.2. RISC-V memory model
https://riscv.org/wp-content/uploads/2018/05/14.25-15.00-RISCVMemoryModelTutorial.pdf
RVWMO 定义了一种宽松的 memory model, 性能会更好, 同时要求代码中使用 aq/rl 进行更精细的控制.
RVTSO 比 RVWMO 严格一些, 同时性能也会差一些, 例如所有的 load 隐含着 aq, 所有的 store 隐含着 rl 等. RVTSO 主要是为了与 x86 兼容.