繁体   English   中英

并发存储以一致的顺序显示

[英]Concurrent stores seen in a consistent order

英特尔架构软件开发人员手册, 2012年8月,第1卷。 3A节。 8.2.2:

除了执行存储的处理器以外,其他任何处理器都以一致的顺序看到任何两个存储。

但这可以吗?

我问的原因是:考虑具有HyperThreading的双核Intel i7处理器。 根据手册的卷。 在图2-8的图1中,i7的逻辑处理器0和1共享一个L1 / L2缓存,但是其逻辑处理器2和3共享一个不同的L1 / L2缓存-而所有逻辑处理器共享一个L3缓存。 假设不共享L1 / L2高速缓存的逻辑处理器0和2在大约同一时间写入同一存储器位置,并且当前写入的深度不超过L2。 逻辑处理器1和3(它们是“执行存储的处理器之外的处理器”)难道看不到“两个存储顺序不一致”吗?

为了实现一致性,逻辑处理器0和2不能发布SFENCE指令,逻辑处理器1和3不能发布LFENCE指令吗? 尽管如此,《 手册》似乎还是有其他想法,并且它在此事上的见解并不只是印刷错误。 看起来是故意的。 我糊涂了。

UPDATE

根据@Benoit的回答,存在以下问题:L1和L2的唯一目的是加快负载。 加快存储速度的是L3。 那正确吗?

英特尔CPU(像所有普通的SMP系统一样)使用MESI (的变体)来确保缓存的加载/存储的缓存一致性。 也就是说,所有内核都通过其缓存看到相同的内存视图。

内核只能在执行“读取所有权”(RFO)之后使该行进入“独占”状态(其他任何缓存都不具有可以满足负载的有效行副本),才能写入该行。 相关:原子RMW操作通过在操作期间将其锁定在“修改”状态来防止其他内核对目标高速缓存行执行任何操作

要测试这种重新排序,您需要另外两个线程,它们都读取两个存储( 以相反的顺序 )。 您提出的方案有一个核心(reader2) 另一个核心(reader1)读取writer1存储的同一行的新值之后 ,从内存(或L3或它自己的私有L2 / L1)中读取旧值。 这是不可能的 :要使reader1看到writer1的存储,writer1必须已经完成了一个RFO,该RFO使缓存行的所有其他副本无效。 不允许直接从DRAM读取而没有(有效地)监听任何回写缓存。 Wikipedia的MESI文章提供了图表。)

当存储(从内核内部的存储缓冲区)提交到L1d高速缓存时,该存储将同时对所有其他内核全局可见。 在此之前,只有本地核心可以“看到”它(通过存储缓冲区中的存储->负载转发)。

在一个将数据从一个核心传播到另一个核心的唯一方法是通过全局高速缓存一致性域的系统上,MESI高速缓存一致性仅保证存在一个全局存储顺序,所有线程都可以达成一致。 x86强大的内存排序规则使此全局存储顺序成为程序顺序的某种交错,我们称其为“总存储顺序”内存模型。

x86的强大内存模型不允许LoadLoad重新排序,因此负载按程序顺序从缓存中获取其数据,而读取器线程中没有任何屏障指令。 1

在从一致性缓存中获取数据之前,实际加载监听本地存储缓冲区。 这就是为什么您引用的一致顺序规则排除了其中一个存储由执行加载的同一核心完成的情况的原因。 有关加载数据真正来自何处的更多信息,请参见全局不可见加载说明 但是,当加载地址不与任何最近的存储区重叠时,我上面说的适用:加载顺序是从共享的全局一致缓存域中采样的顺序。


一致的订单规则是一个很弱的要求。 许多非x86 ISA并不能保证它在纸面上,但是很少有实际的(非x86)CPU设计具有一种机制,通过该机制,一个内核可以看到另一内核的数据,然后才能对所有内核全局可见。 带有SMT的IBM POWER就是这样一个例子: 其他线程是否总是以相同的顺序看到对不同线程中不同位置的两次原子写操作? 解释了一个物理核心内逻辑核心之间的转发如何导致它。 (这与您所建议的类似,但是在存储缓冲区而不是L2中)。

具有超线程功能的x86微体系结构(或Ryzen中的AMD SMT)通过在一个物理内核上的逻辑内核之间静态划分存储缓冲区来满足该要求。 在具有HT的一个Core上执行的线程之间的数据交换将使用什么? 因此,即使在一个物理核心内,存储区也必须提交给L1d(并在全局范围内可见),然后另一个逻辑核心才能加载新数据。

从一个逻辑核心中的已退休但尚未提交的存储转发到同一物理核心上的其他逻辑核心,可能会更简单。

(x86的TSO内存模型的其他要求,如按程序顺序出现的加载和存储,要困难得多。现代的x86 CPU执行不规则,但使用“内存顺序缓冲区”来维持这种错觉,并使存储按程序顺序提交给L1d。负载可以推测性地早于“应有”获取值,然后再进行检查,这就是为什么英特尔CPU具有“内存顺序错误推测”流水线的原因: 生产者与消费者共享的延迟和吞吐量成本是多少?超级兄弟姐妹与非超级兄弟姐妹之间的内存位置?

作为@BeeOnRope指出, HT和维护没有LoadLoad重新排序的幻觉之间的相互作用 :通常在一个CPU可以当另一个核心触及的高速缓存行后的实际负载阅读检测,但它允许建筑之前已经阅读:加载端口可以跟踪对该高速缓存行的失效。 但是使用HT,加载端口还必须监听其他超线程提交给L1d缓存的存储,因为它们不会使该行无效。 (其他机制也是可能的,但是如果CPU设计人员想要“常规”负载的高性能,则必须解决这个问题。)


脚注1 :在弱排序的ISA上,您将使用负载排序屏障来控制每个读取器中的2个负载从全局一致的缓存域中获取数据的顺序。

编写者线程每个都只做一个存储,因此隔离栅毫无意义。 由于所有内核共享一个统一的缓存域,因此篱笆只需要控制内核中的本地重新排序。 每个内核中的存储缓冲区已经尝试使存储在全局范围内尽快可见(同时遵守ISA的排序规则),因此,障碍只会使CPU等待进行后续操作。

x86 lfence基本上没有内存排序用例,而sfence仅对NT存储有用。 当一个线程正在写东西然后读取另一位置时,只有mfence对于“正常”的东西mfence用。 http://preshing.com/20120515/memory-reordering-caught-in-the-act/ 因此,它会阻止StoreLoad重新排序和跨障碍进行存储转发。


根据@Benoit的回答,存在以下问题:L1和L2的唯一目的是加快负载。 加快存储速度的是L3。 那正确吗?

不,L1d和L2是回写式高速缓存: 英特尔®酷睿i7处理器使用哪种高速缓存映射技术? 重复存储到同一行可以被L1d吸收。

但是英特尔使用包容性的L3缓存,那么一个内核中的L1d如何拥有唯一的副本? L3实际上是包含标签的 ,这是L3标签所需的全部功能,它充当探听过滤器(而不是向每个内核广播RFO请求)。 脏行中的实际数据是每个内核内部高速缓存专用的,但是L3知道哪个内核具有该行的当前数据(因此,当另一个内核想要读取另一个内核在Modified中的行时,向哪里发送请求州)。 干净的缓存行(处于“共享”状态)包含L3的数据,但是写入缓存行不会直写到L3。

我相信Intel文档所说的是x86芯片的机制将确保其他处理器始终看到一致的写入顺序。

因此,其他处理器在读取该内存位置时只会看到以下结果之一:

  • 两次写入之前的值(即两次写入之前都进行读取)

  • 处理器0写入后的值(即好像处理器2先写入,然后处理器0覆盖)

  • 处理器2写入后的值(即好像处理器0先写入然后处理器2改写了)

处理器1在写处理器0之后将看不到该值,但与此同时,处理器3在写处理器2之后将看到该值(反之亦然)。

请记住,由于允许处理器内重新排序(请参阅第8.2.3.5节),因此处理器的0和2可能会有所不同。

哎呀,这是一个棘手的问题! 但我会尝试...

写入不超过L2

基本上这是不可能的,因为Intel使用了包含性缓存。 除非您通过CR0 / MTRR禁用它们来阻止缓存,否则任何写入L1的数据也将在L2和L3中发生。

话虽这么说,我猜想这里有仲裁机制:处理器发出写入数据的请求,仲裁器从每个请求队列的未决请求中选择授予哪个请求。 选定的请求将广播到侦听器,然后广播到缓存。 我想这将防止争执,强制执行处理器(而不是执行请求的处理器)看到的一致顺序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM