Write-Combine缓冲区是如何物理连接的?我已经看到了说明许多变体的方框图:
在L1和内存控制器之间
在CPU的存储缓冲区和内存控制器之间
在CPU的AGU和/或存储单元之间
它是依赖于微架构的吗?
1> Hadi Brais..:
写缓冲区可以在不同处理器中具有不同目的或不同用途.此答案可能不适用于未明确提及的处理器.我想强调术语"写缓冲区"在不同的上下文中可能意味着不同的东西.这个答案仅适用于Intel和AMD处理器.
英特尔处理器上的写入组合缓冲器
每个缓存可能伴有零个或多个行填充缓冲区(也称为填充缓冲区).L2处的填充缓冲区的集合称为超级队列或超级队列(超级队列中的每个条目都是填充缓冲区).如果缓存在逻辑核心或物理核心之间共享,则相关的填充缓冲区也在核心之间共享.每个填充缓冲区可以包含一个缓存行和描述缓存行(如果它已被占用)的附加信息,包括缓存行的地址,内存类型和一组有效位,其中位数取决于粒度跟踪缓存行的各个字节.在早期的处理器(例如Pentium II)中,只有一个填充缓冲区能够进行写入组合(和写入折叠).使用较新的处理器,行缓冲器和能够写入梳理的总数稳步增加.最近的英特尔处理器在每个L1数据高速缓存中包含10个填充缓冲区,所有这些都可以组合写入(不要与特定的写入组合(WC)存储器类型混淆).制作一个能够进行写入梳理的填充缓冲区需要额外的硬件(不仅可以实现写入组合,还可以保持强排序存储器类型的存储顺序),因此这种功能不是免费的.
行填充缓冲区用于多种场景:
填充缓冲区分配在缓存中的加载(请求或预取)或存储未命中.如果没有可用的填充缓冲区,则加载和存储请求将继续堆积在加载和存储缓冲区中,这可能最终导致前端停顿.在加载请求的情况下,分配的填充缓冲区用于临时保存来自存储器层次结构的较低级别的请求行,直到它们可被写入高速缓存数据阵列.但是,即使该行尚未写入高速缓存数据阵列,仍然可以将所请求的高速缓存行部分提供给目标寄存器.请求高速缓存行的加载/存储请求本身(可以存在对同一行的多个请求)存储在单独的硬件结构中.在存储请求的情况下,要存储的数据(可能小于高速缓存行的大小)保存在行填充缓冲区中.缓存本身每个缓存行只有一个有效位,因此缓存行的所有字节必须有效,否则它们都不是有效的.但是在填充缓冲区中,缓存行的每个字节都可以有一个有效位.这意味着在所有字节都有效之前,无法在缓存上执行存储操作.这可能需要等待从存储器层次结构的其余部分接收目标高速缓存行.在此之前,可以窥探行缓冲区以进一步加载请求.当它发生时,由存储请求改变的字节与目标高速缓存行组合,然后该行可以写入高速缓存.在整个操作期间,线路必须处于修改/拥有状态(或者更确切地说,在某些中间状态,取决于协议)以保持一致性.填充缓冲区可降低未命中对整体性能的有效性能影响.
填充缓冲区可用于将多个存储请求的字节组合和/或折叠到同一行,但仅限于目标存储器区域的存储器类型允许的情况.此类行为可能会对非相干代理(例如I/O设备)可见的写入顺序产生影响.用作写入组合缓冲区的行填充缓冲区可以以许多不同的方式刷新,例如执行MOVNTDQA
时L1D_PEND_MISS.FB_FULL
,或序列化指令.
某些类型的内存请求不允许缓存(非临时请求),但仍然可以使用行缓冲区来执行请求以提高性能.可以在内存控制器和分配的行填充缓冲区之间绕过所有级别的高速缓存和缓冲区.还有一些AMD的处理器使用的是来自于非临时存储填充缓冲器独立的缓冲区.P6中还有许多WCB缓冲区(第一个实现WCB),P4专用于WC内存类型(不能用于其他内存类型).在P4的早期版本中,有4个这样的缓冲区.对于支持超线程的P4版本,当启用超线程且两个逻辑核心都在运行时,WCB将在两个逻辑核心之间进行静态分区.然而,现代英特尔微体系结构竞争性地共享所有LFB,但保留至少一个可用于每个逻辑核心以防止饥饿.
填充缓冲区由高速缓存控制器管理,高速缓存控制器连接到其他级别的其他高速缓存控制器(或LLC的情况下的存储器控制器).当请求在缓存中命中时,不会分配填充缓冲区.因此,在高速缓存中直接执行在高速缓存中命中的存储请求,并且从高速缓存直接服务在高速缓存中命中的加载请求.当从缓存中逐出一行时,不分配填充缓冲区.被驱逐的行被写入自己的缓冲区(称为写回缓冲区或逐出缓冲区).以下是英特尔的一项专利,该专利讨论了针对I/O写入的写入梳理.
我已经运行的实验,这是非常相似的,我所描述的位置,以确定即使有多个负载在同一线路上的单一LFB是否被分配.事实证明确实如此.对回写L1D高速缓存中未命中的行的第一次加载获得为其分配的LFB.阻止所有后续加载到同一缓存行,并在其相应的加载缓冲区条目中写入块代码,以指示它们正在等待该LFB中保存的相同请求.当数据到达时,L1D高速缓存向加载缓冲区发送唤醒信号,并且当至少一个加载端口可用时,所有在该行上等待的条目被唤醒(未阻塞)并被调度发布到L1D高速缓存. .显然,内存调度程序必须在未阻塞的负载和刚刚从RS调度的负载之间进行选择.如果在所有等待负载得到服务机会之前,由于某种原因线路被驱逐,那么它们将再次被阻塞,并且将再次为该线路分配LFB.我没有测试商店的情况,但我认为无论操作是什么,都会为一条线分配一个LFB.LFB中的请求类型可以从预取到需求负载升级到推测RFO,以在需要时提供RFO.我还从经验中发现,在冲洗管道时,不会删除从错误预测路径上的uops发出的推测性请求.它们可能会降级为预取请求.我不确定.
AMD处理器上的写入组合缓冲器
我之前根据一篇文章提到过,有些AMD处理器使用的缓冲区与非临时存储区的填充缓冲区分开.我引述文章:
在较旧的AMD处理器(K8和系列10h)上,非临时存储使用一组四个"写入组合寄存器",它们独立于用于L1数据高速缓存未命中的八个缓冲区.
"老款AMD处理器"部分让我很好奇.这是在新款AMD处理器上有所改变吗?在我看来,在包括最新的17h系列处理器(Zen)在内的所有新款AMD处理器上都是如此.关于Zen mircoarchitecture 的WikiChip 文章包括两个提到WC缓冲区的数字:这个和这个.在第一个图中,不清楚如何使用WCB.但是,在第二个中,显然所示的WCB确实专门用于NT写入(WCB和L1数据高速缓存之间没有连接).第二个数字的来源似乎是这些幻灯片1.我认为第一个数字是由WikiChip制作的(这解释了为什么WCB处于不确定的位置).事实上,WikiChip的文章没有说明WCB的任何内容.但尽管如此,我们可以确认出仅用于NT的WCBS通过查看图7从编写软件优化指南AMD系列处理器17小时手册和专利的加载和存储队列家庭17H处理器.AMD优化手册指出现代AMD处理器中每个核心有4个WCB.我认为这适用于K8和所有后来的处理器.不幸的是,没有任何关于扮演英特尔填充缓冲区角色的AMD缓冲区的说法.
(1)迈克尔克拉克,2016年AMD高性能x86核心设计.
2> Peter Cordes..:
在现代Intel CPU中,写入组合由LFB(行填充缓冲区)完成,也用于来自L1 <- > L2的其他未决传输.每个核心都有10个(自Nehalem以来).(L2和L3之间的传输使用不同的缓冲区,称为"超级队列").
这就是为什么英特尔建议在进行NT存储时避免过多的其他流量,以避免因分配LFB的需求负载导致部分填充的LFB的早期冲洗.
https://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers
LFB的"内部"具有到L1d,存储缓冲区和加载端口的连接.
LFB的"外部"可以与L2通信或(可能在L2的帮助下)通过环形总线/网格到内存控制器,或L3用于NT预取.对于L3和内存来说,离开核心可能并没有太大的不同; 只是在核心之间的环/网状互连上发送不同类型的消息; 在英特尔CPU中,内存控制器只是环形总线上的另一个停靠点(在"系统代理"中),就像其他核心的L3一样. @ BobOnRope建议 L1 LFB并不真正直接连接到环形总线,并且那些不将数据放入L2的请求可能仍然通过L2超级缓冲区到达环形总线/网格.这似乎很可能,因此每个核心只需要在环形总线上存在一个点并在L2和L1之间进行仲裁发生在核心内部.
NT存储数据直接从存储缓冲区进入LFB,并且探测L1d以查看它是否需要首先驱逐该行.
当正常存储数据从L1d逐出时,正常存储数据进入LFB,或者为分配新线路或者响应来自想要读取该线路的另一个核心的RFO腾出空间.
在L1d中丢失的正常负载(和存储)需要高速缓存来获取该行,该行还分配LFB以跟踪进入的线路(以及对L2的请求).当数据到达时,它会直接发送到等待它的加载缓冲区,与将其放入L1d并行.(在CPU体系结构术语中,请参阅"早期重启"和"关键字优先":缓存未命中仅阻塞,直到所需数据到达,其余的缓存行"在后台"到达.)您(以及CPU架构师在英特尔)绝对不希望L2命中延迟包括将数据放入L1d并再次将其恢复.
来自WC内存(movntdqa
)的NT加载直接从LFB读取 ; 数据永远不会进入缓存.LFB已经连接到加载端口以便提前重启正常负载,因此movntdqa
我认为SSE4能够在没有大量额外成本的情况下添加.特别之处在于,未命中只会直接从内存中填充LFB,绕过L3/L2/L1.NT商店已经需要LFB才能与内存控制器通信.