启动 RFO 可以与将存储数据放入 LFB 分开;例如尽早为尚未位于存储缓冲区头部的条目启动 RFO 可以允许存储的内存级并行性。 您已经证明,要做到这一点,存储数据不能总是移动到 LFB(行填充缓冲区,也用于 NT / WC 存储)。
如果 RFO 只能通过将存储数据从存储缓冲区 (SB) 移动到 LFB 来发生,那么是的,您只能对 SB 的头部进行 RFO,而不能并行处理任何分级条目。 (“毕业”商店是指微商已从 ROB 退休,即不再投机)。但是,如果您没有这个要求,您可以更早地进行 RFO,甚至可以推测,但您可能不想这样做。1
(鉴于@BeeOnRope 发现同一行的多个缓存未命中存储如何提交到一个 LFB,然后另一个 LFB 用于另一行,这可能是让多个 RFO 处于飞行状态的机制,而不仅仅是 SB 头. 我们必须检查 ABA 存储模式是否限制了内存级别的并行性。如果是这种情况,那么可能启动 RFO 与将数据从 SB 移动到 LFB 相同,释放那个 SB 条目。
但请注意,在那些未决的 RFO 完成并提交来自 LFB 的存储之前,SB 的新负责人仍然无法提交。)
一个非常接近现实的简单心智模型
在存储未命中时,存储缓冲区条目会保存存储数据,直到 RFO完成,并直接提交到 L1d(将行从 Exclusive 状态翻转到 Modified 状态)。从存储缓冲区的头部按顺序提交确保了强排序2。
正如@HadiBrais 在回复Where is the Write-Combining Buffer located? x86 时所写的那样
我的理解是,对于可缓存的存储,只有 RFO 请求是
保存在 LFB 中,但要存储的数据在存储缓冲区中等待
直到目标行被提取到为其分配的 LFB 条目中。
这得到第 2.4.5.2 节中的以下声明的支持
英特尔优化手册:
L1 DCache 可以从分配中维护多达 64 个加载微操作
直到退休。它可以维持多达 36 家商店的运营,从
分配,直到存储值提交到缓存,或写入
在非临时存储的情况下到行填充缓冲区 (LFB)。
这对于考虑性能调整来说非常好,但可能不是MDS vulnerabilities,它可以推测性地使用从 LFB 或其他什么读取错误负载的陈旧数据。
任何存储合并或其他技巧都必须尊重内存模型。
但就这么简单吗?没有
我们知道 CPU 不能违反它们的内存模型,并且推测 + 回滚不是提交到 L1d 等全局可见状态的选项,也不是一般的分级存储的选项,因为 uops 已从 ROB 中消失。就本地 OoO 执行官而言,它们已经发生了,只是它们何时对其他核心可见。我们还知道 LFB 本身是不全局可见的。 (有一些迹象表明,LFB 会被来自该内核的负载窥探,例如存储缓冲区,但就 MESI 而言,它们更像是存储缓冲区的扩展。)
@BeeOnRope 做了更多实验,发现一些证据表明,像 AAABBCCCC 这样的一系列商店可以引流到 A、B、C 线的三个 LFB。RWT thread 有一个实验证明该理论预测的 4 倍性能差异。
这意味着 CPU 可以跟踪 LFB 之间的顺序,尽管当然仍然不能在单个 LFB 中。像 AAABBCCCCA(或 ABA)这样的序列将无法提交超过最终的 A 存储,因为“当前头部”LFB 用于线路 C,并且已经有一个 LFB 等待线路 A 到达。第 4 行 (D) 可以,打开一个新的 LFB,但添加到已经打开的 LFB 以等待不是头部的 RFO 是不行的。见@Bee's summary in comments。
所有这些仅针对英特尔 CPU、AFAIK 进行测试。
在此之前,我们认为英特尔/AMD 上没有存储合并,但长期以来一直对英特尔手册中关于 LFB 充当普通(强排序)WB 内存存储的 WC 缓冲区的提示感到困惑
(此部分未根据@BeeOnRope 的新发现进行更新)。
也没有确凿的证据表明商店中存在任何类型的商店合并/合并
现代 Intel 或 AMD CPU 上的缓冲区,或使用 WC 缓冲区(Intel 上的 LFB)在等待高速缓存行到达时保存存储数据。请参阅Are two store buffer entries needed for split line/page stores on recent Intel? 下的 cmets 中的讨论。我们不能排除在存储缓冲区提交端附近的一些次要形式。
我们知道some weakly-ordered RISCs microarchitectures definitely do merge stores before they commit,尤其是创建一个完整的 4 字节或 8 字节写入缓存 ECC 颗粒以避免 RMW 循环。但英特尔 CPU 不会对缓存行内的狭窄或未对齐存储有任何惩罚。
有一段时间,@BeeOnRope 和我认为有一些商店合并的证据,但我们改变了主意。 Size of store buffers on Intel hardware? What exactly is a store buffer? 有更多细节(以及旧讨论的链接)。
(更新:现在终于有了 store 合并的证据,并解释了一种有意义的机制。)
脚注 1: RFO 消耗共享带宽并从其他内核窃取线路,从而减慢它们的速度。如果您过早地进行 RFO,您可能会在真正投入之前再次失去这条线。加载也需要 LFB,您不想饿死(因为在等待加载结果时执行会停止)。负载与商店根本不同,并且通常具有优先级。
因此,至少等待 store 毕业是一个不错的计划,并且可能只为 head 之前的最后几个 store-buffer 条目启动 RFO。 (您需要在启动 RFO 之前检查 L1d 是否已经拥有该行,并且至少需要一个缓存读取端口来读取标签,尽管不是数据。我可能猜想存储缓冲区一次检查 1 个条目并标记一个条目可能不需要 RFO。)另请注意,1 个 SB 条目可能是未对齐的缓存拆分存储并触及 2 个缓存行,最多需要 2 个 RFO...
脚注 2:
存储缓冲区条目按程序顺序分配(在缓冲区的尾部),因为指令/微指令被发送到无序后端并为它们分配后端资源。 (例如,用于写入寄存器的 uop 的物理寄存器,用于可能错误预测的条件分支 uop 的分支顺序缓冲区条目。)另见 Size of store buffers on Intel hardware? What exactly is a store buffer?。有序分配和提交保证了商店的程序订单可见性。存储缓冲区将全局可见的提交与存储地址和存储数据 uop(写入存储缓冲区条目)的无序推测执行隔离开,并且通常将执行与等待缓存未命中存储解耦,直到存储缓冲区已满。
PS 英特尔将存储缓冲区 + 加载缓冲区统称为内存顺序缓冲区 (MOB),因为它们需要相互了解才能跟踪推测性的早期加载。这与您的问题无关,仅适用于推测性早期加载和检测内存顺序错误推测和对管道进行核爆的情况。
对于退役的存储指令(更具体地说,它们的“分级”存储缓冲区条目),它只是必须按程序顺序提交到 L1d 的存储缓冲区。