Intel optimization manual讨论了处理器许多部分中存在的存储缓冲区的数量,但似乎没有讨论存储缓冲区的大小。是公共信息,还是存储缓冲区的大小保留为微体系结构细节?
我正在研究的处理器主要是Broadwell和Skylake,但是关于其他处理器的信息也将很好。
另外,存储缓冲区到底能做什么?
答案 0 :(得分:8)
整个存储缓冲区由多个条目组成。
每个核心都有自己的存储缓冲区 1 ,以将执行和退出与提交到L1d缓存的过程分离。即使是有序的CPU也可以从存储缓冲区中受益,避免在高速缓存未命中的存储中停顿,因为与负载不同,它们最终必须变得可见。 (没有实际的CPU使用顺序一致性内存模型,因此,即使在x86和SPARC-TSO中,至少也允许StoreLoad重新排序。)
对于推测性/乱序CPU,还可以在检测到较旧指令中的异常或其他错误推测后回滚存储,而不必在全局范围内查看推测性存储。这显然对于正确性至关重要! (您不能回滚其他内核,因此,除非已知它们是非推测性的,否则您不能让它们看到您的商店数据。)
当两个逻辑核心都处于活动状态(超线程)时,Intel将存储缓冲区分为两个;每个逻辑核心得到一半。从一个逻辑核心加载仅监听其自身一半的存储缓冲区 2 。 What will be used for data exchange between threads are executing on one Core with HT?
存储缓冲区按程序顺序将已退休存储指令中的数据尽快提交到L1d(以尊重x86的强排序内存模型 3 )。要求存储提交他们退休时的 会不必要地使高速缓存未命中的存储停止退休。仍在存储缓冲区中的退休存储肯定会发生并且无法回滚,因此它们实际上会损害中断延迟。 (从技术上讲,不需要中断就可以进行序列化,但是由IRQ处理程序完成的任何存储区都必须等到现有的挂起存储区耗尽后才能看到。iret
在进行序列化,因此即使在最佳情况下,存储缓冲区也是如此返回之前会耗尽。)
这是一个常见的误解,即必须显式刷新数据才能使数据对其他线程可见。内存屏障不会导致要清空存储缓冲区,完全屏障会使当前核心等待直到存储缓冲区耗尽,然后才允许任何以后发生的负载(即读取L1d)。原子RMW操作必须等待存储缓冲区耗尽后才能锁定高速缓存行,并在不使其保持MESI Modified状态的情况下进行加载和存储到该行,从而阻止系统中的任何其他代理在观察期间原子操作。
要实现x86的有序内存模型,同时仍微体系结构允许早期/无序加载(并在体系结构允许发生加载时稍后检查数据是否仍然有效),则加载缓冲区+存储缓冲区条目共同形成内存顺序缓冲区(MOB)。 (如果允许加载时仍然没有高速缓存行 ,则可能是内存顺序的错误推测。)这种结构大概位于mfence
和{{1} } ed指令可以设置一个障碍,以阻止StoreLoad重新排序而不阻止乱序执行。 (尽管mfence
on Skylake does block OoO exec of independent ALU instructions,作为实现细节。)
lock
绕过缓存的存储区(例如movnt
)也要经过存储缓冲区,因此它们可以像OoO exec CPU中的其他所有东西一样被视为推测性的。但是它们直接提交给LFB(行填充缓冲区)(又名写合并缓冲区),而不是L1d缓存。
英特尔CPU上的存储指令解码为存储地址和存储数据oups (微融合为一个融合域uop)。存储地址uop只是将地址(可能还有存储宽度)写入存储缓冲区,因此以后的加载可以设置存储->加载转发或检测到它们没有重叠。存储数据uop写入数据。
存储地址和存储数据可以按任意顺序执行,以先准备好的顺序为准:分配/重命名阶段将ouop从前端写入到ROB和后端的RS中,也分配负载或存储用于加载的缓冲区或在发行时存储uop 。或拖延直至可用。由于分配和提交是按顺序进行的,这可能意味着较老/较年轻的人很容易跟踪,因为它可以只是循环缓冲区,而不必担心旧的长寿命条目在回绕后仍在使用。 (除非绕过缓存/无序的NT存储可以做到这一点?它们可以不按顺序提交给LFB(行填充缓冲区)。与普通存储不同,它们直接提交给LFB进行内核外传输,而不是L1d )
但是条目的大小是多少?
狭窄的存储区不会在存储缓冲区中“使用较少的空间”,它们仍然只使用1个条目。
Skylake的存储缓冲区有56个条目(wikichip),高于Haswell / Broadwell的42个条目和SnB / IvB的36个条目(David Kanter's HSW writeup on RealWorldTech has diagrams)。您可以找到编号Kanter在RWT,Wikichip的图表或其他各种来源中撰写的文章中,最早期的x86 uarches。
SKL / BDW / HSW还具有72个加载缓冲区条目,SnB / IvB具有64个。这是未执行或正在等待数据从外部缓存到达的正在进行中的加载指令的数量。
每个 条目的大小(以位为单位)是一种实现细节,对优化软件的方式几乎没有影响。同样,我们不知道uop的大小(在前端,在ROB中,在RS中),TLB实施细节或许多其他内容,但是我们确实知道有多少ROB和RS条目,以及各个uarch中有多少个不同类型的TLB条目。
Intel不会发布其CPU设计的电路图,而且这些尺寸通常也不为人所知,因此我们甚至无法满足我们对设计细节/权衡取舍的好奇。
可以(可能是?)在提交之前在存储缓冲区中合并合并到同一高速缓存行的背对背窄存储,因此在L1d高速缓存的写端口上只需花费一个周期即可提交多个存储
我们肯定知道某些非x86 CPU可以这样做,并且我们有一些证据/理由相信Intel CPU确实可以做到这一点。但这是有限的。请参阅以以下评论开头的讨论:Are write-combining buffers used for normal writes to WB memory regions on Intel?
Unexpectedly poor and weirdly bimodal performance for store loop on Intel Skylake也可能是相关的。
我们可以肯定地知道像Alpha 21264这样的弱排序ISA确实在其存储缓冲区中存储了合并,因为the manual documents it及其在每个周期可以提交和/或从L1d读取内容的限制。还有PowerPC RS64-II和RS64-III,其文档中的评论较少:Are there any modern CPUs where a cached byte store is actually slower than a word store?
人们发表了关于如何在TSO内存模型(例如x86)中存储合并的论文(更具侵略性)。 Non-Speculative Store Coalescing in Total Store Order
如果将其数据复制到同一行,则Coalescing可以允许在其数据提交到L1d之前释放存储缓冲区条目(大概仅在退出之后)。仅当没有其他行的存储将它们分开时,才会发生这种情况,否则它将导致存储以程序顺序的方式提交(成为全局可见的),从而违反了内存模型。但是我们认为这可能发生在同一行的任何两个存储中,甚至是第一个和最后一个字节。
(这可能意味着每个SB条目都有64字节的数据,除非合并与正常SB条目不同。但是Skylake-AVX512几乎可以肯定具有64字节的SB条目,因为单个存储区可以那么宽。值得一提的是,据报道,SKL和SKX具有基本相同的内核,只是缺少第二个512位FMA单元和可能的高256位物理寄存器文件,因此SKL上的存储缓冲区条目几乎可以确定有64个字节的空间即使以前的CPU都没有,但是实际上我们认为很多早期的CPU 有都有空间将任何相邻存储合并到同一行。)
术语:我一直在使用“ coalescing”来谈论在存储缓冲区中的合并,而不是“写合并”来谈论(希望)在LFB中合并的NT存储没有RFO的全行写入。或将具有相同功能的区域存储到WC内存区域。
这种区别/约定只是我所做的。根据评论中的讨论,这可能不是标准的计算机体系结构术语。
英特尔的手册(尤其是优化手册)由不同的作者撰写多年,并且在术语上也不一致。尤其要注意优化手册的大部分内容如果说到Pentium4。关于Sandybridge和Haswell的新部分是可靠的,但是较旧的部分可能仅提供过时的建议,而该建议仅与P4相关(例如inc与add 1),或者某些优化规则的微体系结构解释可能令人困惑/错误。特别是第3.6.10节“写合并”。由于内存排序规则,关于使用LFB组合存储同时等待行到达高速缓存未命中的存储到WB存储器的第一个要点似乎并不合理。请参阅上面我和BeeOnRope之间的讨论,以及此处的评论。
脚注1:
用于合并内部缓存的写回(或直写)缓存的写合并缓存将具有不同的名称。例如推土机系列使用16k直写式L1d高速缓存和一个4k的小写回缓冲区。 (有关详细信息和更多详细信息,请参见Why do L1 and L2 Cache waste space saving the same data?。有关在Bulldozer系列CPU上放慢到超过4k的重写数组微基准,请参见Cache size estimation on your system?。)
脚注2 :某些POWER CPU允许其他SMT线程在存储缓冲区中监听已退休的存储:这可能导致不同的线程不同意其他线程的存储全局顺序。 Will two atomic writes to different locations in different threads always be seen in the same order by other threads?
脚注3 :具有较弱内存模型的非x86 CPU可以按任何顺序提交已淘汰的存储,从而可以更积极地将多个存储合并到同一行,并使不丢失缓存的存储不会停止提交其他商店。