全局不可见加载指令
Globally Invisible load instructions
由于存储加载转发,某些加载指令是否永远不会全局可见?换句话说,如果加载指令从存储缓冲区中获取其值,则它永远不必从缓存中读取。
一般说一个load从L1D缓存读取时是全局可见的,不从L1D读取的应该是全局不可见的。
让我稍微扩展一下这个问题,讨论实现存储负载转发的正确性方面。 (Peter的后半部分回答直接回答了我认为的问题)
存储负载转发改变了负载的延迟,而不是它的可见性。除非由于某些错误推测而被冲掉,否则该商店最终将变得全球可见。如果没有存储负载转发,负载必须等到所有冲突的存储退出。然后负载就可以正常取数据了。
(冲突存储的确切定义取决于 ISA 的内存排序模型。在 x86 中,假设 WB 内存类型允许存储加载转发,程序顺序中较早的任何存储及其目标物理内存位置与加载的内存位置重叠是冲突存储)。
尽管如果系统中存在来自另一个代理的任何并发冲突存储,那实际上可能会更改加载的值,因为外部存储可能在本地存储之后但在本地加载之前生效。通常,存储缓冲区不在一致性域中,因此存储负载转发可能会降低类似情况发生的可能性。这取决于存储负载转发实现的限制;通常无法保证任何特定的加载和存储操作都会发生转发。
存储负载转发也可能导致全局内存顺序,没有它就不可能实现。例如,在x86的强模型中,允许store-load reordering,加上store-load forwarding可以让系统中的每个agent以不同的顺序查看所有的内存操作。
一般来说,考虑一个恰好有两个代理的共享内存系统。令 S1(A, B) 为序列 A 和 B 具有存储负载转发的可能全局内存顺序集,令 S2(A, B) 为序列 A 和 B 不带存储的可能全局内存顺序集-负载转发。 S1(A, B) 和 S2(A, B) 都是所有合法全局内存顺序集合 S3(A, B) 的子集。存储负载转发可以使 S1(A, B) 不是 S2(A, B) 的子集。这意味着如果 S2(A, B) = S3(A, B),则存储负载转发将是非法优化。
存储负载转发可能会改变每个全局内存顺序发生的概率,因为它减少了负载的延迟。
加载的全局可见性概念很棘手,因为加载不会修改内存的全局状态,其他线程不能直接观察到它。
但是一旦乱序/推测执行后尘埃落定,我们就可以知道如果线程将负载存储在某个地方或基于它的分支,负载将获得什么值。线程的这种可观察行为很重要。 (或者我们可以用调试器观察它,and/or 只是推理负载可能看到的值,如果实验很困难。)
至少在像 x86 这样的强序 CPUs 上,所有 CPUs 可以就商店的总顺序达成一致变得全局可见,更新单一连贯+一致缓存+内存状态。在不允许 StoreStore reordering 的 x86 上,此 TSO(总存储顺序)与每个线程的程序顺序一致。 (即总顺序是每个线程的程序顺序的一些交错)。 SPARC TSO 也是这种强烈有序的。
(正确观察自己店铺相对于其他店铺的全局顺序需要mfence
或类似的:否则store-forwarding意味着你可以正确地看到自己的店铺在它们对其他核心可见之前离开。x86 TSO 基本上是程序顺序加存储转发。)
(对于绕过缓存的存储,全局可见性是指它们从私有写组合缓冲区刷新到 DRAM 中。英特尔行填充缓冲区或任何等效的私有写组合机制,其中存储数据仍然对其他人不可见CPUs 实际上是我们重新排序目的的存储缓冲区的一部分。)
在弱排序的 ISA 上,线程 A 和 B 可能不同意线程 C 和 D 完成的存储 X 和 Y 的顺序,即使读取线程使用获取加载来确保它们自己的加载是没有重新订购。即可能根本 商店的全局顺序,更不用说它与程序顺序不同了。
IBM POWER ISA 很弱,C++11 内存模型(). But the mechanism in practice on POWER is that (retired aka graduated) stores become visible to some other cores before they become globally visible by committing to L1d cache. Cache itself really is coherent even in POWER systems, like all normal CPUs, and allows sequential-consistency to be recovered with barriers. These multiple-order effects only happen due to SMT(一个物理 CPU 上的多个逻辑 CPU)提供了一种方法无需通过缓存即可查看来自其他逻辑核心的存储。
(一种可能的机制是让其他逻辑线程甚至在它们提交给 L1d 之前就从存储缓冲区中侦听非推测存储,只将尚未退休的存储保留为逻辑线程的私有。这可以减少交互线程延迟略微。x86 不能这样做,因为它会破坏强内存模型;当两个线程在内核上处于活动状态时,Intel 的 HT 静态分区存储缓冲区。但是正如@BeeOnRope 评论的那样, 的抽象模型允许重新排序可能是一种更好的推理正确性的方法。仅仅因为你想不出一种硬件机制来导致重新排序并不意味着它不会发生。)
没有 POWER 弱的弱排序 ISA(实际上 and/or 在纸面上)仍然在每个内核的本地存储缓冲区中重新排序,如果不使用障碍或释放存储, 尽管。在许多 CPU 上,所有商店都有一个全局顺序,但这不是程序顺序的一些交错。 OoO CPUs 必须跟踪内存顺序,因此单个线程不需要屏障来按顺序查看自己的存储,但是允许存储从存储缓冲区提交到程序顺序之外的 L1d 肯定会提高吞吐量(尤其是如果同一行有多个存储挂起,但程序顺序会从每个存储之间的集合关联缓存中逐出该行。例如,讨厌的直方图访问模式。)
让我们做一个关于负载数据从何而来的思想实验
以上仍然只是关于商店知名度,而不是负载。 我们能否将每个加载看到的值解释为在某个时刻从全局 memory/cache 读取(忽略任何加载排序规则)?
如果是这样,那么所有加载结果都可以通过将所有线程的所有存储和加载放入某种组合顺序来解释,读取和写入一致的全局内存状态.
事实证明不,我们不能,存储缓冲区打破了这个:部分存储到加载转发给了我们一个反例(例如在x86上).窄存储后跟宽负载可以在存储变得全局可见之前将来自存储缓冲区的数据与来自 L1d 缓存的数据合并。 真正的 x86 CPUs 实际上是这样做的,我们有真实的实验来证明它。
如果您只看完整的存储转发,其中加载仅从存储缓冲区中的一个存储中获取数据,您可能会争辩说加载被存储缓冲区延迟了。即负载出现在全局总加载-存储顺序中,紧接在使该值全局可见的存储之后。
(这个全局总加载-存储顺序并不是创建替代内存排序模型的尝试;它无法描述 x86 的实际加载排序规则。)
部分存储转发暴露了加载数据并不总是来自全局一致缓存域的事实。
如果来自另一个核心的存储更改了周围的字节,原子范围的加载可能会读取一个不存在的值,并且永远不会 将 存在,在全局相干状态。
请参阅我在 上的回答,以及 Alex 的回答以实验证明这种重新排序可能发生,从而使该问题中提议的锁定方案无效。 存储然后从同一地址重新加载不是 StoreLoad 内存屏障。
有些人(e.g. Linus Torvalds) describe this by saying the store buffer isn't coherent。 (Linus 正在回复其他独立发明了相同无效锁定想法的人。)
另一个涉及存储缓冲区和一致性的问答:。您可以执行一些非原子 OR 来设置位,然后返回并检查是否由于与其他线程冲突而错过更新。但是您需要一个 StoreLoad 屏障(例如 x86 lock or
)以确保您在重新加载时不会只看到自己的商店。
提议的定义:负载在读取其数据时变得全局可见。通常来自 L1d,但存储缓冲区或 MMIO 或不可缓存的内存是其他可能的来源。
此定义与 x86 手册一致,其中指出负载不会与其他负载一起重新排序。即 它们从本地核心的内存视图加载(按程序顺序)。
加载本身可以变得全局可见,而不管任何其他线程是否可以从该地址加载该值。
尽管 完全不谈论可缓存加载的“全局可见性”可能更有意义,因为它们正在从[=]中提取数据 86=] 某个地方,没有做任何有明显效果的事情。只有不可缓存的加载(例如来自 MMIO 区域)才应被视为可见的副作用。
(在 x86 上,不可缓存的存储和加载是非常有序的,所以我认为将存储转发到不可缓存的存储是不可能的。除非存储是通过与 UC 负载相同的物理页面的 WB 映射完成的正在访问。)
负载从RS(保留站)调度并通过AGU(地址生成单元)到达在分配阶段为相应的ROB(重新排序缓冲区)条目分配的负载缓冲区条目。当加载缓冲区条目被分配时,它用当时最新的 SBID(存储缓冲区 ID)着色。彩色表示存储缓冲区中最近存储的条目号(又名 ID)被插入到加载缓冲区条目中。 Store Buffer包括SAB(Store Address Buffer)和SDB(Store Data Buffer);每个存储在两者中都有一个条目(因为每个存储是 2 微指令,通常是微熔合的)并且它们都有相同的索引(条目号又名。SBID)。
我认为一旦地址有效,条目中的有效位就会被设置,这意味着它们已准备好发送(并在数据最终写回 ROB 时被清除)。
还有一个推测性内存消歧预测器,它可能参与有效位的设置,以指示它预计不会与它着色的 SBID 和尾指针存储之间的任何存储混淆在存储缓冲区中(在 SAB 中存储地址,在 SDB 中存储数据)。如果它被预测为别名,或者实际上是别名(即它在存储缓冲区中搜索地址并使用 SAB 中的位掩码来确定条目是否可以满足它(位掩码说明字节主管的特权级别/非-主管),并使用操作码中的隐含大小来获取存储操作存储到的地址范围。如果可以满足,则从 SDB 条目中读取),它进行推测性存储到加载转发使用SDB中的数据并将数据插入到load buffer中,在LB(Load Buffer)中加载完成,但不退出LB。存储到加载转发确保读取永远不会与对同一位置的旧写入重新排序,因为读取将始终使用存储到加载转发。我认为在对 LFENCE 之后的商店进行预测之前,需要计算 LFENCE 的 SBID 之前的所有商店地址。
如果未预测到别名,则分派负载(并且始终按照相对于其他负载的严格顺序分派负载,除非负载具有非临时命中或针对 USWC(不可缓存的推测写入组合memory type) memory(虽然不像stores,现阶段不知道是不是USWC),load并行到dTLB(data TLB)/L1d(L1 data cache)
在任何时候,当存储地址在 SAB 中完成且任何 SBID 小于或等于(考虑回绕)到相关负载的彩色 SBID 时,它可以使所做的内存消歧预测无效,并且管道被刷新,因为管道现在要么使用存储在它应该与之执行存储到加载转发的存储之前存储的陈旧数据,要么它正在使用来自它的存储的错误存储到加载转发数据实际上与.
没有依赖关系
当数据加载到指定的物理目标寄存器后,数据在ROB中生效。当 ROB 中的数据有效且引退指针指向条目时,负载不再是推测性的并获得高级位。如果设置了指示 SAB 尾指针和彩色 SBID 之间的所有存储已计算其地址的位,则负载可以从 LB 退出(从中删除)。除非它是高级加载指令,在这种情况下,它现在可以执行,因为它是高级的并且已经从 ROB 中退出。
LFENCE is dispatched to the load buffer and only executes (is sent to the L1d cache) when all previous uops have retired from the ROB and when all previous load instructions have retired from the ROB+LB (according to the instruction stream serialising properties it is claimed to have, it is probably retired in a cycle on its own rather than with 1 or 2 other instructions before it in the ROB in same cycle). Load instructions retire when the ROB tells them they can retire (no longer speculative) and the data fetched is valid and the load is no longer memory-speculative. LFENCE dispatches when it is at the tail of the load buffer and ROB (It cannot retire until all read buffers are globally visible. I think this means that it makes sure that any senior load instructions (instructions that execute after retirement from the ROB and when they get marked as senior) such as PREFETCH
have allocated read buffers. Regular loads allocate read buffers and read their data and it becomes valid in the load buffer before they can be retired. Globally visible in this case means all previous read LFBs (Line Fill Buffers) have received globally visible notifications from the ring for the line (which could come before the read response containing the data, or could be packaged into the read response,这可能意味着它必须等待所有读取完成而不是被确认)(当然,已经从MOB(Memory Order Buffer)退休的指令是全局可见的因为他们的数据已经返回,但是高级加载指令可能还没有分配读取缓冲区或者承认它们是全局可见的)(这类似于全局可见存储的定义,其中响应 RFO(Read For Ownership),对 LFB 的全局观察可能会出现在通知中,即核心具有该行的权限(独占访问权)并且其他核心已失效,这将在要写入的行中的实际数据返回到核心之前出现,假设在响应失去在线许可的窥探之前,这将始终被写回)。当 LFENCE 调度时,L1d 缓存将其视为 nop 并完成,在 ROB 中退出,成为高级,即从 LB 中删除,并且加载缓冲区中被阻止调度到 L1d 缓存的 uops 现在被允许被派遣。
负载的全局可见性确实会影响其他核心的缓存一致性状态,我认为这就是为什么 LFENCE
要求负载是全局可见的。内核中的负载未命中会转到 LLC(末级缓存),LLC 有一个监听过滤器,显示只有一个其他内核拥有该线路。如果 1>= 核心拥有该线路,则需要将该核心降级为 S 状态并使其写回修改后的数据。然后可以将写入 LLC 的数据返回到请求内核,并带有 S 状态和全局可见的通知。如果核心中的加载未命中而不是 LLC,则 LLC 可能会立即发送全局可见的通知,同时将请求发送到本地代理以从内存中获取它(或者如果它是多套接字系统,则 LLC 必须等待确认来自家乡代理,在它可以向核心发送全局可观察通知之前不需要侦听其他核心。
我认为senior load是不再推测的等待数据返回生效的load,或者已经有效所以立即退出,而senior load指令是调度的指令从 ROB 退役后。
由于存储加载转发,某些加载指令是否永远不会全局可见?换句话说,如果加载指令从存储缓冲区中获取其值,则它永远不必从缓存中读取。
一般说一个load从L1D缓存读取时是全局可见的,不从L1D读取的应该是全局不可见的。
让我稍微扩展一下这个问题,讨论实现存储负载转发的正确性方面。 (Peter的后半部分回答直接回答了我认为的问题)
存储负载转发改变了负载的延迟,而不是它的可见性。除非由于某些错误推测而被冲掉,否则该商店最终将变得全球可见。如果没有存储负载转发,负载必须等到所有冲突的存储退出。然后负载就可以正常取数据了。
(冲突存储的确切定义取决于 ISA 的内存排序模型。在 x86 中,假设 WB 内存类型允许存储加载转发,程序顺序中较早的任何存储及其目标物理内存位置与加载的内存位置重叠是冲突存储)。
尽管如果系统中存在来自另一个代理的任何并发冲突存储,那实际上可能会更改加载的值,因为外部存储可能在本地存储之后但在本地加载之前生效。通常,存储缓冲区不在一致性域中,因此存储负载转发可能会降低类似情况发生的可能性。这取决于存储负载转发实现的限制;通常无法保证任何特定的加载和存储操作都会发生转发。
存储负载转发也可能导致全局内存顺序,没有它就不可能实现。例如,在x86的强模型中,允许store-load reordering,加上store-load forwarding可以让系统中的每个agent以不同的顺序查看所有的内存操作。
一般来说,考虑一个恰好有两个代理的共享内存系统。令 S1(A, B) 为序列 A 和 B 具有存储负载转发的可能全局内存顺序集,令 S2(A, B) 为序列 A 和 B 不带存储的可能全局内存顺序集-负载转发。 S1(A, B) 和 S2(A, B) 都是所有合法全局内存顺序集合 S3(A, B) 的子集。存储负载转发可以使 S1(A, B) 不是 S2(A, B) 的子集。这意味着如果 S2(A, B) = S3(A, B),则存储负载转发将是非法优化。
存储负载转发可能会改变每个全局内存顺序发生的概率,因为它减少了负载的延迟。
加载的全局可见性概念很棘手,因为加载不会修改内存的全局状态,其他线程不能直接观察到它。
但是一旦乱序/推测执行后尘埃落定,我们就可以知道如果线程将负载存储在某个地方或基于它的分支,负载将获得什么值。线程的这种可观察行为很重要。 (或者我们可以用调试器观察它,and/or 只是推理负载可能看到的值,如果实验很困难。)
至少在像 x86 这样的强序 CPUs 上,所有 CPUs 可以就商店的总顺序达成一致变得全局可见,更新单一连贯+一致缓存+内存状态。在不允许 StoreStore reordering 的 x86 上,此 TSO(总存储顺序)与每个线程的程序顺序一致。 (即总顺序是每个线程的程序顺序的一些交错)。 SPARC TSO 也是这种强烈有序的。
(正确观察自己店铺相对于其他店铺的全局顺序需要mfence
或类似的:否则store-forwarding意味着你可以正确地看到自己的店铺在它们对其他核心可见之前离开。x86 TSO 基本上是程序顺序加存储转发。)
(对于绕过缓存的存储,全局可见性是指它们从私有写组合缓冲区刷新到 DRAM 中。英特尔行填充缓冲区或任何等效的私有写组合机制,其中存储数据仍然对其他人不可见CPUs 实际上是我们重新排序目的的存储缓冲区的一部分。)
在弱排序的 ISA 上,线程 A 和 B 可能不同意线程 C 和 D 完成的存储 X 和 Y 的顺序,即使读取线程使用获取加载来确保它们自己的加载是没有重新订购。即可能根本 商店的全局顺序,更不用说它与程序顺序不同了。
IBM POWER ISA 很弱,C++11 内存模型(
(一种可能的机制是让其他逻辑线程甚至在它们提交给 L1d 之前就从存储缓冲区中侦听非推测存储,只将尚未退休的存储保留为逻辑线程的私有。这可以减少交互线程延迟略微。x86 不能这样做,因为它会破坏强内存模型;当两个线程在内核上处于活动状态时,Intel 的 HT 静态分区存储缓冲区。但是正如@BeeOnRope 评论的那样, 的抽象模型允许重新排序可能是一种更好的推理正确性的方法。仅仅因为你想不出一种硬件机制来导致重新排序并不意味着它不会发生。)
没有 POWER 弱的弱排序 ISA(实际上 and/or 在纸面上)仍然在每个内核的本地存储缓冲区中重新排序,如果不使用障碍或释放存储, 尽管。在许多 CPU 上,所有商店都有一个全局顺序,但这不是程序顺序的一些交错。 OoO CPUs 必须跟踪内存顺序,因此单个线程不需要屏障来按顺序查看自己的存储,但是允许存储从存储缓冲区提交到程序顺序之外的 L1d 肯定会提高吞吐量(尤其是如果同一行有多个存储挂起,但程序顺序会从每个存储之间的集合关联缓存中逐出该行。例如,讨厌的直方图访问模式。)
让我们做一个关于负载数据从何而来的思想实验
以上仍然只是关于商店知名度,而不是负载。 我们能否将每个加载看到的值解释为在某个时刻从全局 memory/cache 读取(忽略任何加载排序规则)?
如果是这样,那么所有加载结果都可以通过将所有线程的所有存储和加载放入某种组合顺序来解释,读取和写入一致的全局内存状态.
事实证明不,我们不能,存储缓冲区打破了这个:部分存储到加载转发给了我们一个反例(例如在x86上).窄存储后跟宽负载可以在存储变得全局可见之前将来自存储缓冲区的数据与来自 L1d 缓存的数据合并。 真正的 x86 CPUs 实际上是这样做的,我们有真实的实验来证明它。
如果您只看完整的存储转发,其中加载仅从存储缓冲区中的一个存储中获取数据,您可能会争辩说加载被存储缓冲区延迟了。即负载出现在全局总加载-存储顺序中,紧接在使该值全局可见的存储之后。
(这个全局总加载-存储顺序并不是创建替代内存排序模型的尝试;它无法描述 x86 的实际加载排序规则。)
部分存储转发暴露了加载数据并不总是来自全局一致缓存域的事实。
如果来自另一个核心的存储更改了周围的字节,原子范围的加载可能会读取一个不存在的值,并且永远不会 将 存在,在全局相干状态。
请参阅我在
有些人(e.g. Linus Torvalds) describe this by saying the store buffer isn't coherent。 (Linus 正在回复其他独立发明了相同无效锁定想法的人。)
另一个涉及存储缓冲区和一致性的问答:lock or
)以确保您在重新加载时不会只看到自己的商店。
提议的定义:负载在读取其数据时变得全局可见。通常来自 L1d,但存储缓冲区或 MMIO 或不可缓存的内存是其他可能的来源。
此定义与 x86 手册一致,其中指出负载不会与其他负载一起重新排序。即 它们从本地核心的内存视图加载(按程序顺序)。
加载本身可以变得全局可见,而不管任何其他线程是否可以从该地址加载该值。
尽管 完全不谈论可缓存加载的“全局可见性”可能更有意义,因为它们正在从[=]中提取数据 86=] 某个地方,没有做任何有明显效果的事情。只有不可缓存的加载(例如来自 MMIO 区域)才应被视为可见的副作用。
(在 x86 上,不可缓存的存储和加载是非常有序的,所以我认为将存储转发到不可缓存的存储是不可能的。除非存储是通过与 UC 负载相同的物理页面的 WB 映射完成的正在访问。)
负载从RS(保留站)调度并通过AGU(地址生成单元)到达在分配阶段为相应的ROB(重新排序缓冲区)条目分配的负载缓冲区条目。当加载缓冲区条目被分配时,它用当时最新的 SBID(存储缓冲区 ID)着色。彩色表示存储缓冲区中最近存储的条目号(又名 ID)被插入到加载缓冲区条目中。 Store Buffer包括SAB(Store Address Buffer)和SDB(Store Data Buffer);每个存储在两者中都有一个条目(因为每个存储是 2 微指令,通常是微熔合的)并且它们都有相同的索引(条目号又名。SBID)。
我认为一旦地址有效,条目中的有效位就会被设置,这意味着它们已准备好发送(并在数据最终写回 ROB 时被清除)。
还有一个推测性内存消歧预测器,它可能参与有效位的设置,以指示它预计不会与它着色的 SBID 和尾指针存储之间的任何存储混淆在存储缓冲区中(在 SAB 中存储地址,在 SDB 中存储数据)。如果它被预测为别名,或者实际上是别名(即它在存储缓冲区中搜索地址并使用 SAB 中的位掩码来确定条目是否可以满足它(位掩码说明字节主管的特权级别/非-主管),并使用操作码中的隐含大小来获取存储操作存储到的地址范围。如果可以满足,则从 SDB 条目中读取),它进行推测性存储到加载转发使用SDB中的数据并将数据插入到load buffer中,在LB(Load Buffer)中加载完成,但不退出LB。存储到加载转发确保读取永远不会与对同一位置的旧写入重新排序,因为读取将始终使用存储到加载转发。我认为在对 LFENCE 之后的商店进行预测之前,需要计算 LFENCE 的 SBID 之前的所有商店地址。
如果未预测到别名,则分派负载(并且始终按照相对于其他负载的严格顺序分派负载,除非负载具有非临时命中或针对 USWC(不可缓存的推测写入组合memory type) memory(虽然不像stores,现阶段不知道是不是USWC),load并行到dTLB(data TLB)/L1d(L1 data cache)
在任何时候,当存储地址在 SAB 中完成且任何 SBID 小于或等于(考虑回绕)到相关负载的彩色 SBID 时,它可以使所做的内存消歧预测无效,并且管道被刷新,因为管道现在要么使用存储在它应该与之执行存储到加载转发的存储之前存储的陈旧数据,要么它正在使用来自它的存储的错误存储到加载转发数据实际上与.
没有依赖关系当数据加载到指定的物理目标寄存器后,数据在ROB中生效。当 ROB 中的数据有效且引退指针指向条目时,负载不再是推测性的并获得高级位。如果设置了指示 SAB 尾指针和彩色 SBID 之间的所有存储已计算其地址的位,则负载可以从 LB 退出(从中删除)。除非它是高级加载指令,在这种情况下,它现在可以执行,因为它是高级的并且已经从 ROB 中退出。
LFENCE is dispatched to the load buffer and only executes (is sent to the L1d cache) when all previous uops have retired from the ROB and when all previous load instructions have retired from the ROB+LB (according to the instruction stream serialising properties it is claimed to have, it is probably retired in a cycle on its own rather than with 1 or 2 other instructions before it in the ROB in same cycle). Load instructions retire when the ROB tells them they can retire (no longer speculative) and the data fetched is valid and the load is no longer memory-speculative. LFENCE dispatches when it is at the tail of the load buffer and ROB (It cannot retire until all read buffers are globally visible. I think this means that it makes sure that any senior load instructions (instructions that execute after retirement from the ROB and when they get marked as senior) such as PREFETCH
have allocated read buffers. Regular loads allocate read buffers and read their data and it becomes valid in the load buffer before they can be retired. Globally visible in this case means all previous read LFBs (Line Fill Buffers) have received globally visible notifications from the ring for the line (which could come before the read response containing the data, or could be packaged into the read response,这可能意味着它必须等待所有读取完成而不是被确认)(当然,已经从MOB(Memory Order Buffer)退休的指令是全局可见的因为他们的数据已经返回,但是高级加载指令可能还没有分配读取缓冲区或者承认它们是全局可见的)(这类似于全局可见存储的定义,其中响应 RFO(Read For Ownership),对 LFB 的全局观察可能会出现在通知中,即核心具有该行的权限(独占访问权)并且其他核心已失效,这将在要写入的行中的实际数据返回到核心之前出现,假设在响应失去在线许可的窥探之前,这将始终被写回)。当 LFENCE 调度时,L1d 缓存将其视为 nop 并完成,在 ROB 中退出,成为高级,即从 LB 中删除,并且加载缓冲区中被阻止调度到 L1d 缓存的 uops 现在被允许被派遣。
负载的全局可见性确实会影响其他核心的缓存一致性状态,我认为这就是为什么 LFENCE
要求负载是全局可见的。内核中的负载未命中会转到 LLC(末级缓存),LLC 有一个监听过滤器,显示只有一个其他内核拥有该线路。如果 1>= 核心拥有该线路,则需要将该核心降级为 S 状态并使其写回修改后的数据。然后可以将写入 LLC 的数据返回到请求内核,并带有 S 状态和全局可见的通知。如果核心中的加载未命中而不是 LLC,则 LLC 可能会立即发送全局可见的通知,同时将请求发送到本地代理以从内存中获取它(或者如果它是多套接字系统,则 LLC 必须等待确认来自家乡代理,在它可以向核心发送全局可观察通知之前不需要侦听其他核心。
我认为senior load是不再推测的等待数据返回生效的load,或者已经有效所以立即退出,而senior load指令是调度的指令从 ROB 退役后。