assembly 英特尔硬件上的存储缓冲区大小?什么是存储缓冲区?

wztqucjr  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(178)

Intel optimization manual讨论了处理器的许多部分中存在的存储缓冲区的数量,但似乎没有讨论存储缓冲区的大小。这是公共信息还是存储缓冲区的大小作为微体系结构细节保留?
我正在调查的处理器主要是Broadwell和Skylake,但有关其他处理器的信息也会很好。
另外,存储缓冲区的确切作用是什么?

bvn4nwqk

bvn4nwqk1#

相关内容:what is a store buffer?和**Can a speculatively executed CPU branch contain opcodes that access RAM?**中对缓冲区概念的初学者友好(但详细)介绍,我强烈建议您阅读这篇文章,了解CPU体系结构背景,了解我们为什么需要它们以及它们的作用(将执行与提交到L1 d/高速缓存未命中分离,并允许推测性执行存储,而不会在一致性高速缓存中显示推测)。
How do the store buffer and Line Fill Buffer interact with each other?也很好地描述了执行存储指令的步骤,以及它最终如何提交到L1 d缓存。

存储缓冲区作为一个整体由多个条目组成

每个内核都有自己的存储缓冲区1,可以将执行和退出从提交到L1 d缓存中分离出来。即使是有序CPU也可以受益于存储缓冲区,避免在缓存未命中存储时停止,因为与加载不同,它们必须 * 最终 * 变为可见。(没有实际的CPU使用顺序一致性内存模型,因此至少允许StoreLoad重新排序,即使在x86和SPARC-TSO中也是如此)。
对于推测性/乱序CPU,它还可以在检测到异常或旧指令中的其他错误推测后回滚存储,而推测性存储永远不会全局可见。这显然是正确性的关键!(您不能回滚其他内核,因此您不能让它们看到您的存储数据,直到知道它是非推测性的。)
当两个逻辑内核都处于活动状态(超线程)时,英特尔将存储缓冲区分为两个分区;每个逻辑核心获得一半。来自一个逻辑核心的加载仅窥探其自身的存储缓冲器2的一半。What will be used for data exchange between threads are executing on one Core with HT?
存储缓冲区按照程序顺序,尽可能快地将来自 * 失效 * 存储指令的数据提交到L1 d(为了尊重x86的强有序内存模型3)。要求存储在引退时提交将不必要地延迟缓存未命中存储的引退。仍在存储缓冲区中的引退存储肯定会发生,并且不能回滚,因此,它们实际上会影响中断延迟。(中断在技术上并不需要进行序列化,但IRQ处理程序所做的任何存储都不会变得可见,直到现有的挂起存储被清空。而且iret正在进行序列化,因此,即使在最好的情况下,存储缓冲区也会在返回之前清空。)
这是一个常见的(?)误解必须显式刷新数据才能让其他线程看到它。内存屏障不会 * 导致 * 存储缓冲区被刷新,满屏障会让当前内核 * 等待 * 直到存储缓冲区耗尽自身,在允许任何后续加载发生之前(即读取L1 d)。原子RMW操作必须等待存储缓冲器耗尽,然后才能锁定高速缓存行,并对该行进行加载和存储,而不允许其离开MESI修改的状态,从而阻止系统中的任何其他代理在原子操作期间观察它。
实现x86的强有序内存模型,同时在微体系结构上仍允许早期/无序加载(以及稍后检查当体系结构允许发生加载时数据是否仍然有效),加载缓冲器+存储缓冲器条目共同形成存储器顺序缓冲器(MOB)。(如果当允许加载发生时高速缓存行 * 不 * 仍然存在,这是内存顺序推测错误。)此结构可能是mfencelock艾德指令可以设置障碍的地方,该障碍阻止StoreLoad重新排序,但不会阻止乱序执行。(尽管mfence on Skylake does block OoO exec of independent ALU instructions是实现细节。)
movnt缓存旁路存储(如movntps)也会通过存储缓冲区,因此它们可以被视为推测性的,就像OoO exec CPU中的其他东西一样。但它们直接提交到LFB(行填充缓冲区),也就是写组合缓冲区,而不是L1 d缓存。

英特尔CPU上的存储指令解码为存储地址微操作和存储数据微操作(微融合为一个融合域微操作)。存储地址微操作只将地址(可能还有存储宽度)写入存储缓冲区,因此稍后的加载可以设置存储-〉加载转发或检测到它们没有重叠。存储数据微操作写入数据。

Store-address和store-data可以按任一顺序执行,以先准备好的为准:将微操作从前端写入到后端的ROB和RS中的分配/重命名级还在发出时为加载或存储微操作分配加载或存储缓冲器。或者停止直到有一个可用。由于分配和提交按顺序发生,这可能意味着更老的/更年轻的很容易跟踪,因为它可以只是一个循环缓冲区,不必担心旧的长-活动条目在环绕后仍在使用。(除非缓存旁路/弱序NT存储可以这样做?它们可以无序提交到LFB(行填充缓冲区)。与正常存储不同,它们直接提交到LFB以进行离核传输,而不是提交到L1 d。)
但条目的大小是多少呢?

存储缓冲区大小以条目而非位为单位。

窄存储不会在存储缓冲区中“使用更少的空间”,它们仍然只使用1个条目。

Skylake的存储缓冲区有56个条目(wikichip),高于Haswell/Broadwell的42个条目和SnB/IvB(David Kanter's HSW writeup on RealWorldTech has diagrams))的36个条目。你可以在Kanter关于RWT的文章、Wikichip的图表或其他各种来源中找到大多数早期x86微架构的数字。

SKL/BDW/HSW也有72个加载缓冲区条目,SnB/IvB有64个.这是尚未执行或正在等待外部缓存中得数据到达得正在执行得加载指令数.

  • each* 条目的位数是一个实现细节,对优化软件没有任何影响。同样,我们不知道微操作(在前端、ROB、RS中)的位数,也不知道TLB的实现细节,或者其他很多东西,但是我们知道有多少ROB和RS条目,以及在不同的微架构中有多少不同类型的TLB条目。

英特尔不公布其CPU设计的电路图,而且(AFAIK)这些尺寸通常不为人所知,因此我们甚至无法满足我们对设计细节/权衡的好奇心。

存储缓冲区中的写入合并:

对同一缓存线得背对背窄存储在提交之前,可以(可能?)在存储缓冲区中合并,也称为合并,因此,在一级缓存得写矶钓上,提交多个存储可能只需要一个周期.
我们确信一些非x86 CPU会这样做,我们有一些证据/理由怀疑英特尔CPU可能会这样做。但如果真的发生了,那也是有限的。@BeeOnRope和我目前认为英特尔CPU可能 * 不会 * 做任何重大的合并。如果他们做了,最可能的情况是在存储缓冲器的末端的条目(准备提交到L1 d)所有去往同一高速缓存行的数据可以合并到一个缓冲器中,如果我们在等待缓存行的RFO,那么优化提交。请参见Are two store buffer entries needed for split line/page stores on recent Intel?的注解中的讨论。我提出了一些可能的实验,但还没有做。

关于可能的存储缓冲区合并的早期内容:

请参阅以以下评论开头的讨论:写入组合缓冲区是否用于对英特尔上的WB内存区域进行正常写入?
并且Unexpectedly poor and weirdly bimodal performance for store loop on Intel Skylake也可能是相关的。
我们可以肯定的是,一些弱有序的ISA,比如Alpha 21264,确实会在它们的存储缓冲区中存储合并,因为the manual documents it,沿着它在每个周期可以提交和/或从L1 d读取的内容上的限制。还有PowerPC RS64-II和RS64-III,更少的细节,在这里的评论链接的文档中:有没有任何现代CPU的缓存字节存储实际上比字存储慢?
人们已经发表了关于如何在TSO内存模型(如x86)(例如Non-Speculative Store Coalescing in Total Store Order)中进行(更积极的?)存储合并的论文
通过合并,可以在存储缓冲区条目的数据提交到L1 d之前释放该条目(大概只有在撤回之后),如果它的数据复制到同一行的存放区。这只有在没有其他行的存放区分隔它们时才会发生,否则会造成存放区认可(变得全局可见)超出程序顺序,违反了内存模型。但我们认为这可能发生在任何两个存储到同一行,甚至第一个和最后一个字节。
这种想法的一个问题是SB条目分配可能是一个环形缓冲区,就像ROB一样。无序释放条目意味着硬件需要扫描每个条目以找到空闲的条目,然后如果它们被无序重新分配,那么它们就不会按程序顺序进行后续存储。这可能会使分配和存储转发变得更加困难,因此可能不太合理。
正如Are two store buffer entries needed for split line/page stores on recent Intel?中所讨论的,一个SB条目保存一个存储的所有内容是有意义的,即使它跨越了缓存线边界。当提交到L1 d缓存时,缓存线边界在 * 离开 * SB时变得相关。我们知道存储转发可以用于跨缓存线分割的存储。如果它们在存储端口中被分割成多个SB条目,这似乎是不可能的。

**术语:**我一直在使用“合并”来讨论存储缓冲区中的合并,而使用“写入组合”来讨论在(希望)执行没有RFO的完整行写入之前在LFB中合并的NT存储。或者存储到WC内存区域,它们做同样的事情。

这个区别/约定只是我编造的。根据评论中的讨论,这可能不是标准的计算机体系结构术语。

**英特尔手册(尤其是优化手册)由不同的作者编写多年,而且术语也不一致。**对优化手册的大部分内容持保留态度,尤其是在谈到奔腾4时。关于Sandybridge和Haswell的新章节是可靠的,但较旧的部分可能有过时的建议,这些建议仅/主要与P4相关(例如INC对ADD 1),或者对一些优化规则的微体系结构解释可能令人困惑/错误。特别是第3. 6. 10节写入组合。第一个要点是关于使用LFB合并存储,同时等待缓存未命中存储到WB内存的行到达,因为内存排序规则,看起来似乎不太合理。请参见上面链接的我和BeeOnRope之间的讨论,以及这里的评论。
脚注1:

用于缓冲写回的写组合高速缓存(或直写)将有一个不同的名称。例如,Bulldozer系列使用16 k直写L1 d高速缓存,带有一个小的4k回写缓冲区。(请参阅Why do L1 and L2 Cache waste space saving the same data?了解详细信息和更多详细信息的链接。请参阅Cache size estimation on your system?了解在Bulldozer系列CPU上速度降低超过4k的阵列重写微基准测试。)

脚注2:某些POWER CPU允许其他SMT线程监听存储缓冲区中的失效存储:这会导致不同的线程对其他线程的全局存储顺序不一致。2在不同的线程中对不同位置的两个原子写入是否总是被其他线程以相同的顺序看到?
脚注3:具有弱内存模型的非x86 CPU可以按任何顺序提交失效的存储,从而允许更积极地将多个存储合并到同一行,并使高速缓存未命中存储不会停止其他存储的提交。

相关问题