存储指令是否会在高速缓存未命中时阻止后续指令?

Do store instructions block subsequent instructions on a cache miss?

假设我们有一个具有两个内核(C0 和 C1)的处理器和一个从地址 k 开始的高速缓存行,该地址最初由 C0 拥有。如果 C1 在第 k 行的 8 字节槽上发出一条存储指令,是否会影响在 C1 上执行的后续指令的吞吐量?

intel优化手册有如下一段话

When an instruction writes data to a memory location [...], the processor ensures that it has the line containing this memory location is in its L1d cache [...]. If the cache line is not there, it fetches from the next levels using a RFO request [...] RFO and storing the data happens after instruction retirement. Therefore, the store latency usually does not affect the store instruction itself

参考以下代码,

// core c0
foo();
line(k)->at(i)->store(kConstant, std::memory_order_release);
bar();
baz();

英特尔手册中的引述让我假设在上面的代码中,代码的执行看起来好像存储本质上是空操作,并且不会影响 foo()bar() 的开始。相反,对于以下代码,

// core c0
foo();
bar(line(k)->at(i)->load(std::memory_order_acquire));
baz();

foo() 结束和 bar() 开始之间的延迟会受到负载的影响,因为以下代码将负载结果作为依赖项。


这个问题主要与英特尔处理器(Broadwell 系列或更新的处理器)如何处理上述情况有关。另外,特别是对于那些看起来像上面的 C++ 代码如何编译为这些处理器的汇编。

一般来说,对于后续代码不会很快读取的存储,存储不会直接延迟任何现代乱序处理器上的后续代码,包括英特尔。

例如:

foo()
*x = y;
bar()

如果 foo() 不修改 xy,并且 bar 不从 *x 加载,则商店是独立的,可能甚至在 foo() 完成之前(甚至在它开始之前)就开始执行,并且 bar() 可能在存储提交到缓存之前执行,并且 bar() 甚至可能在 foo() 时执行是运行宁等

虽然 直接 影响很小,但这并不意味着没有间接影响,实际上存储可能会支配执行时间。

如果存储在缓存中未命中,它可能会在满足缓存未命中时占用核外资源。它还通常防止后续存储耗尽,这可能是一个瓶颈:如果存储缓冲区填满,前端将完全阻塞并且新指令不再进入调度程序。

最后一切还是要看周边代码的细节,照例。如果该序列重复 运行,并且 foo()bar() 很短,则与存储相关的未命中可能会占据 运行 时间。毕竟,缓冲不能掩盖无限开店的成本。在某些时候,您会受到商店内在吞吐量的限制。