核心A将值x写入storebuffer,等待无效的ack,然后将x刷新到缓存。它只等待一个ack或等待所有的ack?它如何知道所有CPU中有多少ack?
答案 0 :(得分:3)
我不清楚“无效的ack”是什么意思,但我们假设你的意思是来自另一个核心的窥探/无效,该核心要求拥有同一条线。
在这种情况下,存储缓冲区中的存储通常可以自由地忽略来自其他核心的此类无效,因为存储缓冲区中的存储尚未全局可见。只有在他们退休后的某个时刻承诺L1时,商店才会变得全局可见。此时 1 如果缓存控制器尚未在缓存中,则缓存控制器将发出关联线路的RFO(请求所有权)。在这一点上,商店变得全局可见。 L1缓存控制器不需要知道有多少其他失效在飞行中,因为它们是由系统中的某些更高级别组件调解的,作为MESI协议的一部分,当它们在E状态下获得该线路时,它们保证他们是独家拥有者。
简而言之,来自其他核心的失效对存储缓冲区 2 中的存储几乎没有影响,因为它们基于RFO请求在单个点处变为全局可见。是加载已经执行该区域更可能是由另一个核心上的无效活动做出的,特别是在x86这样的强平台上,它不允许可见的负载加载重新排序。例如,x86上的所谓MOB负责跟踪失效是否可能违反排序规则。
或许你所谈论的“ack”是其他内核对写入内核获取或升级线路所有权的请求的响应,以便它可以写入它:即,在另一个内核中复制线路副本CPU等等。
这通常称为发出RFO,当成功将线路保留在请求核心的E状态时。
大多数CPU都是分层的,各种不同的代理协同工作以确保一致性。实际上,这意味着CPU不需要等待来自N CPU系统上其他N-1核心的N-1“acks”,而只需要等待来自更高级别组件的单个回复。负责发送和收集其他CPU的响应。
一个例子可能是具有私有L1和L2以及共享L3的单插槽多核CPU。核心可能会将其RFO发送到L3,这可能会向所有核心发送无效请求,等待其响应,然后向请求核心确认RFO请求。或者,L3可以存储一些位,这些位指示哪些核可能具有该行的副本,然后它只需要将请求发送到那些核(在这种情况下L3所采取的角色有时被称为窥探)文件管理器)。
由于代理之间的所有通信都通过L3,因此可以保持任何一致性。在多插槽系统的情况下,事情变得更复杂:本地核心上的L3可能再次获得请求并可能将其传递到另一个套接字以在那里执行相同类型的失效。同样可能存在监听过滤器的概念,或者可能存在其他概念,行为甚至可以配置!
例如,在英特尔的Broadwell Xeon架构中,有fully four different configurable snoop modes:
Broadwell提供四种不同的窥探模式,重新引入Home Snoop与目录和机会Snoop广播(HS与DIR + OSB)以前可以在Ivy Bridge上使用,以及三种窥探模式 可以在Haswell,Early Snoop,Home Snoop和Cluster on Die上使用 模式(COD)。表5列出了内存带宽和延迟权衡 每种不同的模式都会有所不同。大多数工作量都会 找到Home Snoop with Directory和Opportunistic Snoop Broadcast 将是最好的选择。
......具有不同的性能权衡:
其余文档详细介绍了各种模式的工作原理。
所以我想简短的回答是“它很复杂,取决于详细的设计,甚至可能是用户可配置的设置”。
1 或者可能在某个早期点,因为优化的实现可能会在商店缓冲区中“向前看”,并为即将到来的商店发布RFO(所谓的“RFO预取”),甚至在它们成为最资深的商店。
2 然而,无效可能会使第一个脚注中提到的RFO预取变得复杂,因为这意味着有一个窗口可以被另一个核心“偷回”,从而浪费了RFO预取工作。一个复杂的实现可能有一个预测器,可以根据是否发生这种情况来改变RFO预取的攻击性。