Assembly 为什么刷新由其他逻辑处理器导致的内存顺序冲突的管道?

Assembly 为什么刷新由其他逻辑处理器导致的内存顺序冲突的管道?,assembly,x86,cpu-architecture,memory-barriers,speculative-execution,Assembly,X86,Cpu Architecture,Memory Barriers,Speculative Execution,as: 当来自另一个处理器的嗅探请求与管道中数据操作的源匹配时,将发生内存排序(MO)机器清除。在这种情况下,管道在进行中的加载和存储失效之前被清除 但是我不明白为什么会这样。不同逻辑处理器上的加载和存储之间没有同步顺序。 处理器可以假装在所有当前的飞行数据操作提交后发生了窥探 还描述了该问题 每当CPU核心检测到“内存排序冲突”时,就会触发内存排序机器清除。基本上,这意味着一些当前挂起的指令试图访问我们刚刚发现其他CPU内核同时写入的内存。由于这些指令仍被标记为挂起,而“此内存刚刚写入”事件意

as:

当来自另一个处理器的嗅探请求与管道中数据操作的源匹配时,将发生内存排序(MO)机器清除。在这种情况下,管道在进行中的加载和存储失效之前被清除

但是我不明白为什么会这样。不同逻辑处理器上的加载和存储之间没有同步顺序。
处理器可以假装在所有当前的飞行数据操作提交后发生了窥探

还描述了该问题

每当CPU核心检测到“内存排序冲突”时,就会触发内存排序机器清除。基本上,这意味着一些当前挂起的指令试图访问我们刚刚发现其他CPU内核同时写入的内存。由于这些指令仍被标记为挂起,而“此内存刚刚写入”事件意味着其他某个内核成功完成写入,因此挂起的指令以及所有依赖于其结果的指令都是不正确的:当我们开始执行这些指令时,我们使用的内存内容版本现在已经过时。所以我们需要抛开所有的工作,重新来过。这是机器,明白了

但这对我来说毫无意义,CPU不需要重新执行加载队列中的加载,因为没有非锁定加载/存储的总顺序

我发现一个问题是允许重新排序装载:

;foo is 0
mov eax, [foo]    ;inst 1
mov ebx, [foo]    ;inst 2
mov ecx, [foo]    ;inst 3
如果执行顺序是1 3 2,那么像
mov[foo]这样的存储将导致

eax = 0
ebx = 1
ecx = 0
这确实违反了内存排序规则

但是负载不能随负载重新排序,那么当来自另一个内核的嗅探请求与任何正在运行的负载源匹配时,为什么英特尔的CPU会刷新管道呢?

这种行为防止了什么错误情况?

尽管x86内存排序模型不允许对WC以外的任何内存类型的加载以程序顺序进行全局观察,但该实现实际上允许加载以顺序完成。在所有以前的加载完成之前,暂停发出加载请求的成本非常高。考虑下面的例子:

load X
load Y
load Z
------           ------
core1            core2
------           ------
load rdx, [X]    store [Y], 1
load rbx, [Y]    store [X], 2
add  rdx, rbx
call printf
假设缓存层次结构中不存在行x,必须从内存中提取。但是,Y和Z都存在于一级缓存中。维护x86负载排序要求的一种方法是在负载X获得数据之前不发出负载Y和X。但是,这将暂停所有依赖于Y和Z的指令,从而导致潜在的巨大性能损失

文献中已经提出并广泛研究了多种解决方案。Intel在其所有处理器中实现的一种方法是允许无序发布加载,然后检查是否发生内存顺序冲突,在这种情况下,将重新发布违反的加载,并重播其所有相关指令。但只有在满足以下条件时,才会发生这种违反行为:

  • 加载已完成,而程序顺序中的前一个加载仍在等待其数据,并且这两个加载的内存类型需要排序
  • 另一个物理或逻辑内核修改了后一个加载读取的行,并且在前一个加载获取数据之前发出加载的逻辑内核已检测到此更改
当这两种情况都发生时,逻辑核会检测到内存顺序冲突。考虑下面的例子:

load X
load Y
load Z
------           ------
core1            core2
------           ------
load rdx, [X]    store [Y], 1
load rbx, [Y]    store [X], 2
add  rdx, rbx
call printf
假设初始状态为:

  • [十] =[Y]=0
  • 包含Y的缓存线已存在于core1的L1D中。但是X不存在于core1的私有缓存中
  • X线以可修改的相干状态出现在core2的L1D中,Y线以可共享状态出现在core2的L1D中
根据x86强排序模型,唯一可能的法律结果是0、1和3。特别是,结果2是不合法的

可能发生以下一系列事件:

  • Core2为两条生产线发布RFO。第X行的RFO将很快完成,但第Y行的RFO必须一直到L3,以使core1专用缓存中的行无效。请注意,core2只能按顺序提交存储,因此存储到第X行将等待存储到第Y行的提交
  • Core1向L1D发出两个负载。从Y行的加载很快完成,但从X行的加载需要从core2的私有缓存中获取该行。请注意,此时Y的值为零
  • 行Y从core1的私有缓存中失效,其在core2中的状态更改为可修改的一致性状态
  • Core2现在按顺序提交两个存储
  • 第X行从core2转发到core1
  • Core1从缓存线X加载core2存储的值,即2
  • Core1打印X和Y的总和,即0+2=2。这是非法的结果。本质上,core1加载了一个过时值Y
为了保持加载顺序,core1的加载缓冲区必须对驻留在其私有缓存中的行进行所有无效检测。当它检测到行Y已无效,而在程序顺序中无效行的已完成加载之前存在挂起的加载时,将发生内存顺序冲突,必须重新发布加载,然后才能获取最新的值。请注意,如果行Y在失效之前和从X加载完成之前已从core1的私有缓存中移出,则它可能无法首先嗅到行Y的失效。因此,也需要有一个机制来处理这种情况

如果core1从未使用加载的一个或两个值,则可能发生加载顺序冲突,