为什么RFO报废后不按顺序中断内存?

问题描述 投票:2回答:1

我以为我了解如何处理L1D写入未命中,但是仔细思考就使我感到困惑。

这里是汇编语言片段:

;rdi contains some valid 64-bytes aligned pointer
;rsi contains some data
mov [rdi], rsi
mov [rdi + 0x40], rsi        
mov [rdi + 0x20], rsi

假定[rdi][rdi + 0x40]行在l1d中未处于排他或修改状态。然后,我可以想象以下操作顺序:

  1. mov [rdi], rsi退休。
  2. mov [rdi], rsi尝试将数据写入l1d。启动RFO,将数据放入WC缓冲区。
  3. [mov [rdi + 0x40], rsi退休([mov [rdi], rsi已经退休,所以有可能)
  4. [mov [rdi + 0x40], rsi为连续的高速缓存行启动RFO,将数据放入WC缓冲区。
  5. [mov [rdi + 0x20], rsi退休([mov [rdi + 0x40], rsi已退休,因此有可能)]
  6. mov [rdi + 0x20], rsi注意到正在进行[rdi]的RFO。数据被放入WC缓冲区。

  7. BOOM![rdi]RFO恰好在[rdi + 0x40] RFO之前完成,因此现在可以将mov [rdi], rsimov [rdi + 0x20], rsi的数据提交到缓存中。它破坏了内存顺序。

如何处理这种情况以保持正确的内存顺序?

assembly x86-64 cpu-architecture cpu-cache rfo
1个回答
1
投票

是的,将存储缓冲区提交到不跟踪顺序的WC缓冲区中将违反x86的强排序模型。

这是[[为什么我们可以确定x86 CPU实际上没有这样做,而是将存储数据保留在存储缓冲区1中。它必须按程序顺序从存储缓冲区提交到相干的L1d(即变得全局可见)。这意味着如果该行尚未处于“修改”或“互斥”状态,则等待RFO完成。存储缓冲区会为尚未到达存储缓冲区末尾的存储执行RFO,因此它可以通过运行多个RFO来实现内存级别的并行性,但是需要保留它们的顺序直到提交为止到L1d。

如@BeeOnRope在回答Where is the Write-Combining Buffer located? x86时所写

我的理解是,对于可缓存商店,

只有RFO请求是 保留在LFB中,但是要存储的数据在存储缓冲区中等待] 直到将目标行提取到为其分配的LFB条目中。 以下的第2.4.5.2节 英特尔优化手册:

L1 DCache可以通过分配维护多达64个加载微操作 直到退休。它最多可以维护36个商店操作 分配,直到将存储值提交到缓存或写入 如果是非临时存储,则将它们添加到行填充缓冲区(LFB)。

退休后的RFO可以。问题将是将存储数据提交到无序的WC缓冲区中。


也没有确凿的证据表明商店中有任何类型的商店合并/合并缓冲区在现代Intel或AMD CPU上使用,或者使用WC缓冲区(在Intel上为LFB)在等待高速缓存行到达时保存存储数据。参见Are two store buffer entries needed for split line/page stores on recent Intel?下注释中的讨论。我们不能排除它在存储缓冲区的提交端附近的一些次要形式。

[我们知道some weakly-ordered RISCs microarchitectures definitely do merge stores before they commit,特别是创建高速缓存ECC颗粒的完整4字节或8字节写入,以避免RMW周期。但是,对于高速缓存行内狭窄或未对齐的存储区,Intel CPU不会受到任何惩罚。

一段时间以来,@ BeeOnRope和我以为有一些商店合并的证据,但是我们改变了主意。 Size of store buffers on Intel hardware? What exactly is a store buffer?有更多详细信息(以及指向较早讨论的链接)。

脚注1:英特尔将存储缓冲区+加载缓冲区统称为内存顺序缓冲区,因为它们需要彼此了解才能跟踪推测性早期加载。但是对于已退休的存储指令(更具体地说,是其“已分级”的存储缓冲区条目),它只是一个存储缓冲区,必须按程序顺序提交到L1d。

© www.soinside.com 2019 - 2024. All rights reserved.