Memory Order Machine Clear performance event is described by the vTune documentation为:
但是我不明白为什么会这样。在不同逻辑处理器上的加载和存储之间没有同步顺序。
处理器可以假装在所有当前运行中的数据操作都提交后进行监听。
这个问题也被描述here
但这对我来说没有任何意义,CPU不需要重新执行“加载队列”中的加载,因为没有针对非锁定加载/存储的总订单。
我可以看到一个问题,即允许对负载进行重新排序:
;foo is 0
mov eax, [foo] ;inst 1
mov ebx, [foo] ;inst 2
mov ecx, [foo] ;inst 3
如果执行顺序为1 3 2,则
mov [foo], 1
之类的存储在3到2之间将导致eax = 0
ebx = 1
ecx = 0
这确实违反了内存排序规则。
但是负载不能随负载重新排序,那么当来自另一个内核的监听请求与任何进行中的负载的来源相匹配时,为什么英特尔的CPU会刷新管道?
此行为可以防止什么错误情况?
最佳答案
尽管x86内存排序模型不允许对WC以外的任何其他内存类型的加载在程序顺序之外进行全局观察,但该实现实际上允许加载按顺序完成。在所有先前的负载都已完成之前,暂停发出负载请求会非常昂贵。考虑以下示例:
load X
load Y
load Z
假定第x行不存在于缓存层次结构中,而必须从内存中获取。但是,Y和Z都存在于L1高速缓存中。满足x86负载排序要求的一种方法是在负载X获得数据之前不发出负载Y和X。但是,这将使所有依赖Y和Z的指令停顿,从而可能会严重打击性能。
在文献中已经提出并广泛研究了多种解决方案。英特尔已在其所有处理器中实现的功能是允许按顺序发出负载,然后检查是否发生了内存排序冲突,在这种情况下,将重新发出违反的负载,并重播其所有相关指令。但是,只有在满足以下条件时,才会发生这种违规:
当这两种情况同时发生时,逻辑核心将检测到内存排序冲突。考虑以下示例:
------ ------
core1 core2
------ ------
load rdx, [X] store [Y], 1
load rbx, [Y] store [X], 2
add rdx, rbx
call printf
假设初始状态为:
根据x86强排序模型,唯一可能的合法结果是0、1和3。特别是,结果2是不合法的。
可能会发生以下事件序列:
为了维持加载的顺序,core1的加载缓冲区必须将所有失效监听到驻留在其专用缓存中的行。当它检测到Y行已经无效时,在程序顺序中从无效行开始的未完成加载之前有未完成的加载时,就会发生内存排序冲突,必须重新发出该加载,之后它才能获得最新的值。请注意,如果在使其无效和从X的加载完成之前,已将行Y从core1的专用缓存中逐出,则它可能首先无法监听行Y的无效。因此,还需要一种机制来处理这种情况。
如果core1从不使用加载的值中的一个或两个,则可能会发生加载顺序冲突,但永远无法观察到。类似地,如果core2存储到行X和Y的值相同,则可能会发生负载排序冲突,但无法观察到。但是,即使在这些情况下,core1仍将不必要地重新发出违反的负载并重播其所有依赖项。
关于assembly - 为什么要刷新其他逻辑处理器引起的内存顺序违规的管道?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55563077/