写合并缓冲区是如何物理连接的?我看过一些块图,说明了一些变体:
- 在L1缓存和内存控制器之间
- 在CPU的存储缓存和内存控制器之间
- 在CPU的AGU和/或存储单元之间
它是否与微架构有关?
写合并缓冲区是如何物理连接的?我看过一些块图,说明了一些变体:
它是否与微架构有关?
(2) 在可缓存存储器上分配了一个填充缓冲区到L1缓存中,目标行不处于允许修改的一致性状态。我的理解是,对于可缓存存储器,只有RFO请求被保存在LFB中,但要存储的数据会等待在存储器缓冲区中,直到为其分配的LFB条目中获取目标行。这得到了英特尔优化手册第2.4.5.2节中以下陈述的支持:
L1 DCache可以在从分配到退役期间维护最多64个加载微操作。它可以在从分配到将存储值提交到缓存或在非临时存储的情况下写入线填充缓冲区(LFB)的36个存储操作。
这表明,如果目标行不在L1D中,则可缓存存储器不会提交到LFB。换句话说,在目标行写入LFB,然后在LFB中修改该行,或者在目标行写入L1D,然后在L1D中修改该行之前,存储必须在存储器缓冲区中等待。
(3) 在L1高速缓存中,无论该行是否在缓存或其一致性状态如何,都会为不可缓存的写组合存储器分配填充缓冲区。对于相同缓存行的WC存储可以合并和折叠(在程序顺序之前,同一位置的多次写入将使程序顺序中的最后一个存储覆盖先前存储),在单个LFB中进行。在当前分配给LFB的请求中,没有维护排序。因此,如果有两个WCB正在使用,则无论与程序顺序的存储顺序如何,都不能保证哪个将首先被驱逐。这就是为什么即使所有存储都按顺序退役提交,WC存储也可能变得无序全局可见的原因(尽管WC协议允许WC存储以无序方式提交)。此外,WCB不被监视,因此只有当它们到达内存控制器时才变得全局可见。更多信息请参见Intel手册V3的第11.3.1节。
有一些AMD处理器使用与非临时存储的填充缓冲区分离的缓冲区。在实现WCB的第一代P6和P4中也有许多专用于WC内存类型(不能用于其他内存类型)的WCB缓冲区。在早期版本的P4中,有4个这样的缓冲区。对于支持超线程的P4版本,在启用超线程并且两个逻辑核心都在运行时,WCB会在两个逻辑核心之间静态分配。然而,现代Intel微架构竞争性地共享所有LFB,但我认为至少为每个逻辑核心保留一个可用的以防止饥饿。
(4) L1D_PEND_MISS.FB_FULL
的文档表明UC存储器也分配在相同的LFB中(无论该行是否在高速缓存中或其一致性状态如何)。与可缓存存储不同,但类似于WC,UC存储器不会合并在LFB中。
(5) 我已经通过实验观察到来自IN
和OUT
指令的请求也分配在LFB中。更多信息,请参见:使用环形总线拓扑的英特尔CPU如何解码和处理端口I/O操作。
附加信息:
填充缓冲区由高速缓存控制器管理,该控制器连接到其他层级的高速缓存控制器(或在LLC的情况下连接到内存控制器)。当请求命中高速缓存时,不会分配填充缓冲区。因此,在高速缓存中命中的存储请求直接在高速缓存中执行,而在高速缓存中命中的加载请求直接从高速缓存中服务。当一行被驱逐出高速缓存时,不会分配填充缓冲区。被驱逐的行被写入它们自己的缓冲区(称为写回缓冲区或驱逐缓冲区)。这是Intel的一项专利,讨论了用于I/O写入的写组合技术。我之前提到根据一篇文章,有些AMD处理器使用与非临时存储的填充缓冲区分离的缓冲区。引用该文章中的内容:
“在旧的AMD处理器上”这部分让我很好奇。新的AMD处理器是否有所改变?在我看来,所有新的AMD处理器,包括最近的Family 17h处理器(Zen),都是如此。WikiChip对Zen微架构的文章包括两个提到WC缓冲区的图:this和this。在第一个图中,不清楚WCB的使用方式。然而,在第二个图中,可以明确地看出所示的WCB确实专门用于NT写入(WCB与L1数据缓存之间没有连接)。第二个图的来源似乎是这些幻灯片1。我认为第一个图是由WikiChip制作的(这解释了为什么WCB被放置在一个不确定的位置)。事实上,WikiChip文章并未提及任何关于WCB的内容。但仍然可以通过查看AMD Family 17h处理器的软件优化指南手册和负责Family 17h处理器的加载和存储队列的专利中的第7个图来确认所示的WCB仅用于NT写入。AMD优化手册指出,现代AMD处理器每个核心有4个WCB。我认为这适用于K8和所有后续处理器。不幸的是,关于扮演Intel填充缓冲区角色的AMD缓冲区没有提及。在旧版AMD处理器(K8和Family 10h)上,非临时存储使用一组四个“写结合寄存器”,这些寄存器独立于用于L1数据缓存未命中的八个缓冲区。
1 迈克尔·克拉克,AMD的一种新型高性能x86核心设计, 2016年。
在现代英特尔CPU中,写合并是由LFB(线填充缓冲器)完成的,也用于其他从L1<->L2的未决传输。自Nehalem以来,每个核心都有10个这样的缓冲器。(L2和L3之间的传输使用不同的缓冲区,称为“超级队列”)。
这就是为什么英特尔建议在进行NT存储时避免过多的其他流量,以避免由需求加载分配LFBs引起的部分填充LFBs的早期刷新。https://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers
LFB的“内部”与L1d、存储缓冲区和加载端口相连。
LFB的“外部”可以与L2通信,或者(可能需要L2的帮助)通过环形总线/网格连接到内存控制器或L3以进行NT预取。对于L3和内存,离核心是没有太大区别的;只是在核心之间的环形/网格互连上发送不同类型的消息;在英特尔CPU中,内存控制器只是环形总线上的另一个停靠点(在“系统代理”中),就像其他带有其L3切片的核心一样。@BeeOnRope建议 L1 LFB并没有真正直接连接到环形总线,而那些不将数据放入L2的请求可能仍然通过L2超级队列缓冲区传递到环形总线/网格。这似乎很有可能,因此每个核心只需要在环形总线上具有一个存在点,并且在L2和L1之间的仲裁在核心内部进行。
NT存储数据直接从存储缓冲区进入LFB,同时探测L1d以查看是否需要先清除该行。
普通存储数据在从L1d中驱逐出来时进入LFB,无论是为了为新分配的行腾出空间还是响应其他核心的RFO请求以读取该行。
普通加载(和存储)如果在L1d中未命中,则需要缓存获取该行数据,这也会分配一个LFB来跟踪传入的行(和向L2的请求)。当数据到达时,它会直接发送到等待数据的加载缓冲区中,并同时放置在L1d中。(在CPU架构术语中,请参见"早期重启"和"关键字优先":缓存未命中只会阻塞,直到所需数据到达,其余的缓存行会"在后台"到达。)您(以及英特尔的CPU架构师)绝对不希望L2命中延迟包括将数据放置在L1d中并再次取回。
NT从WC内存中加载(movntdqa
),直接从LFB读取;数据根本不进入缓存。 LFB已经连接到用于早期重启正常加载的加载端口,因此SSE4能够在不需要额外硅成本的情况下添加movntdqa
。它是特殊的,因为一次未命中只会直接从内存中填充一个LFB,绕过L3 / L2 / L1。但是,NT存储器已经需要LFB能够与内存控制器通信。L1缓存中有许多缓冲区。
该专利给出了以下缓冲区类型:
现在有6种缓冲区:
MTRR包括默认类型,其中MTRR未映射范围。 MTRR是通过解决任何冲突或默认值而产生的最终类型。首先,将默认值解析为UC并与任何UC MTRR具有相同的等级,然后将任何冲突的MTRR组合成一个最终的MTRR。然后将此MTRR与PAT和E位进行比较,并且具有最高优先级的那个成为最终的内存类型,尽管在某些情况下,它们是不合法的组合,会导致创建不同的类型。没有UC-MTRR。
缓存类型(时间)的描述:
缓存类型描述(非临时性):
WB
(请参见完整讨论)。 L1缓存中的写入命中在某些实现中可以将写入与L1中的行合并,并强制PLRU以便下次将其驱逐(作为WB),或者写入命中会导致一个驱逐,然后分配一个写组合专用缓冲区,就像有一个未命中一样,这将在释放条件下使用WCiL(F)
写回USWC。写入未命中会分配一个专用的写组合缓冲区,并在取消分配时将其写回内存为USWC,但如果该未命中导致L2命中,则写组合缓冲区将立即写入L2或在取消分配条件下写入L2,这要么导致从L2立即被驱逐,要么强制PLRU位以便它是下一个驱逐。对该行的进一步读取/写入将继续由缓冲区满足,直到取消分配为止。 NT写入是弱序的。 L1 / L2中没有M / E状态的写入命中仍可能导致WiL
使当前和其他插座上的所有其他核心无效,以获得E状态,否则,它只会使该行无效,并且当最终进行USWC存储时,LLC会检查是否需要使当前或远程插座上的任何其他核心无效。WCiLF
),则Cbo向所有具有副本的核心发送IDI无效(由于某种原因,Cbo发送的作为TOR IPQ逻辑队列中出站请求的一部分的invalidate IDI opcode未记录)并且始终发送QPI InvItoE
,无论是否存在LLC缺失,根据SAD交错规则将其正确发送到主代理。只有在筛选器中的所有核心都响应了无效操作并且主代理也响应之后,才能进行存储;在它们响应之后,Cbo会从L2发送WrPull_GO_I
(表示全局观察通知和使缓存行无效的写入拉取)中的数据,并将数据发送到主机。如果LLC缓存中存在部分USWC存储WCiL
,则发生相同的情况,但是如果该行现在已在LLC片段中被修改(从SnpInv
发送而不是仅在一个核心中存在的无效操作,我猜它确实会这样做,而不仅仅是像对于WCiLF
那样发送普通的无效操作),或者一直在LLC中被修改,则Cbo在执行USWC存储的写使能位写回WcWrPtl
之前,对主代理执行WBMtoI
/WbMtoIPtl
。PATs基于虚拟地址操作,因此可能会发生别名,即同一物理页面可以具有多个不同的缓存策略。据推测,WP写入和UC读/写别名也具有相同的行为,但我不确定。一个RFO意图从存储缓冲区开始,如果它在L1d高速缓存中命中M或E状态,则执行写入并结束RFO。如果该行处于I状态,则分配LFB,并将RFO传播到L2,在那里可以满足它,如果它以M或E状态存在(当M行被写回到L2时,它在L3方面成为M状态)。 如果它是I状态/不存在,则在SQ中进行分配,并将RFO或ItoM数据包传播到处理地址范围的相应LLC切片Cbo。然后,Cbo切片使用探测过滤器使其他核心无效,这涉及向核心发送无效请求(或SnpInv进行探测无效(如果它仅存在于一个核心中-因为Cbo不知道是否已修改数据,因此也会获取数据)。 Cbo等待直到它收到来自核心的无效化确认(以及数据如有修改)。Cbo然后向请求核心的SQ表示它现在具有独占访问权。由于Cbo可能必须从内存控制器中提取数据,因此它很可能早期确认,表明数据不存在于任何其他核心中。 SQ将此信息传播到L1d高速缓存,这导致在LFB中设置全局观察位,并且高级存储器现在可以从SAB / SDB中退出以释放其条目。当数据最终到达时,它被传播到LFB,其中它与无效位合并,然后根据该地址的解除分配条件或由于LFB资源限制将其写入高速缓存。
如果L1中存在一个WB行但处于S状态,则在写入该行之前,它可能会或可能不会分配LFB以合并存储。如果在L1中无效/不存在,则将分配LFB以合并存储。然后,如果该行存在于L2中但处于S状态,则向LLC片发送WiL
数据包(仅需要使其他核心失效)。然后通知请求核心的SQ现在可以将其转换为E状态。此信息被传播到L1d缓存中,其中LFB现在可以合并到缓存中,以避免针对LFB资源约束的释放条件发生。
ItoM
被用于替代RFO,当我们假设整行都将被写入时,它就不需要已经在行中的数据副本,如果在其他状态(S、E、M)下,它已经有了数据。理论上的StoI
即WiL
与RFO相同,除了I外,所有状态都是一样的,在ItoM
和RFO之间的区别在于LLC不需要向核心发送数据进行ItoM
。这个名称强调了状态的变化。我不知道它如何知道整行将要被存储..也许L1d高速缓存可以一次性压缩一堆连续的老年存储器存储在MOB中,同时分配一个LFB,因为在分配后立即发送RFO(然后一旦RFO到达就全部退休)。我想这还有一些时间,使得存储器可以到达LFB(L2查找),然后才生成操作码。这也可能被rep stos
使用
PrefRFO
由核心发送以预取到LLC。
L1i明显缺少填充缓冲区,这意味着填充缓冲区的主要好处是提供一个位置来存储和合并存储,并使得存储缓冲区条目更快地释放。由于L1i不执行任何存储操作,因此这不是必需的。我认为它仍然具有读取LFBs的功能,以便在或之前填充缓存时提供未命中数据,但是后续读取不会加速,因为我认为缓冲区是PIPT类型的,它们的标记与缓存并行扫描。读取LFBs还将压缩读取指向LFB的内容,并防止多次查找,同时通过跟踪LFBs MSHRs中的当前未命中来防止缓存阻塞,因此高度可能存在这种功能。
ItoM
被rep movsb/stosb
和NT存储使用。据我所知,它不用于任何临时存储(也就是不用于64字节的zmm
存储或组合的ymm
存储)。 - Noah