当前位置: 首页 > 知识库问答 >
问题:

为什么退休后RFO不中断内存排序?

陈刚洁
2023-03-14

我原以为我了解L1D write miss是如何处理的,但仔细想想却让我感到困惑。

以下是汇编语言片段:

;rdi contains some valid 64-bytes aligned pointer
;rsi contains some data
mov [rdi], rsi
mov [rdi + 0x40], rsi        
mov [rdi + 0x20], rsi

假设[rdi][rdi 0x40]行在l1d中不处于独占或修改状态。然后我可以想象以下操作序列:

>

  • mov[rdi],rsi退休。
  • mov[rdi],rsi尝试将数据写入l1d。RFO启动,数据放入WC缓冲区。
  • mov[rdi 0x40], rsi退休(mov[rdi], rsi已经退休,所以有可能)
  • mov[rdi 0x40],rsi为连续的缓存行发起RFO,数据放入WC缓冲区。
  • mov[rdi 0x20], rsi退休(mov[rdi 0x40], rsi已经退休,因此有可能)
  • mov[rdi 0x20],rsi注意到[rdi]的RFO正在进行中。数据被放入WC缓冲区。

    轰<代码>[rdi]RFO恰好在[rdi 0x40]RFO之前完成,因此现在可以将mov[rdi]、rsimov[rdi 0x20]、rsi的数据提交到缓存。它破坏了内存排序。

    如何处理这种情况以保持正确的内存顺序?

  • 共有1个答案

    公西季
    2023-03-14

    启动RFO可以与将存储数据放入LFB分开;例如,为尚未位于存储缓冲区头部的条目提前启动RFO可以允许存储的内存级并行性。您已经证明,要做到这一点,存储数据不能总是移动到LFB(行填充缓冲区,也用于NT/WC存储)。

    如果RFO只能通过将存储数据从存储缓冲区(SB)移动到LFB中来实现,那么是的,您只能对SB的头部进行RFO,而不能同时对任何分级条目进行RFO。(一家“分级”商店是指其UOP已退出ROB,即成为非投机性商店)。但如果您没有这个要求,您可以更早地进行RFO,甚至是推测性的,但您可能不想这样做1

    (根据@BeeOnRope关于同一行的多个缓存未命中存储如何提交到LFB,然后另一行的另一个LFB的发现,这可能是多个RFO飞行的机制,而不仅仅是SB头。我们必须检查ABA存储模式是否限制内存级别并行性。如果是这样,那么启动RFO可能与从SB移动数据相同到LFB,释放SB条目。但请注意,在这些待定RFO完成并提交LFB的存储之前,SB的新负责人仍然无法提交。)

    在存储未命中时,存储缓冲区条目保存存储数据,直到RFO完成,并直接提交到L1d(将行从独占状态翻转到修改状态)。存储缓冲区头部的顺序提交确保了强排序。

    正如@HadiBrais在回答写组合缓冲区位于何处时所写的那样?x86

    我的理解是,对于可缓存存储,只有RFO请求保存在LFB中,但要存储的数据在存储缓冲区中等待,直到目标行被提取到为其分配的LFB条目中。英特尔优化手册第2.4.5.2节的以下语句支持这一点:

    L1 DCache可以从分配到退役期间维持多达64个负载微操作。从分配到存储值提交到缓存,或在非时态存储的情况下写入行填充缓冲区(LFB),它最多可以维护36个存储操作。

    这对于考虑性能调优非常好,但可能不是MDS漏洞,这些漏洞可能会推测性地使用从LFB或其他地方读取的错误加载的陈旧数据

    任何存储合并或其他技巧都必须尊重内存模型。

    我们知道CPU不能违反它们的内存模型,并且推测回滚不是promise像L1d这样的全局可见状态的选项,也不是一般的分级存储的选项,因为UOP已经从ROB中消失了。就本地OoO exec而言,它们已经发生了,这只是其他内核何时可以看到它们的问题。此外,我们知道LFB本身并不是全局可见的。(有迹象表明,LFB受到来自该核心的负载的窥探,如存储缓冲区,但据MESI所述,它们更像是存储缓冲区的扩展。)

    @BeeOnRope做了更多的实验,发现一些证据表明,像AAABBCCCC这样的一系列商店可以排入三个LFB,用于A、B、C行。RWT线程的实验证明了该理论预测的4倍性能差异。

    这意味着CPU可以跟踪LFB之间的顺序,尽管当然仍然不在单个LFB内。像AAABBCCCCA(或ABA)这样的序列将无法提交超过最终的A存储,因为“当前头部”LFB用于C行,并且已经有一个LFB等待A行到达。第4行(D)可以打开一个新的LFB,但添加到已经打开的LFB等待不是头部的RFO是不可以的。请参阅@Bee在评论中的总结。

    所有这些仅针对Intel CPU AFAIK进行测试。

    (本节未根据@BeeOnRope的新发现更新)。

    也没有确凿的证据表明现代Intel或AMD CPU上的存储缓冲区中存在任何类型的存储合并/合并,或者在等待缓存线到达时使用WC缓冲区(Intel上的LFB)来保存存储数据。请参阅评论中的讨论,在最近的英特尔上,拆分行/页存储是否需要两个存储缓冲区条目?。我们不能排除在存储缓冲区的提交端附近的一些次要形式。

    我们知道,一些弱有序的RISC微架构肯定会在提交之前合并存储,尤其是创建一个完整的4字节或8字节的缓存ECC颗粒写入以避免RMW周期。但是英特尔CPU对缓存行中的狭窄或未对齐存储没有任何惩罚。

    有一段时间,BeeOnRope和我认为有一些证据表明商店合并了,但我们改变了主意。Intel硬件上存储缓冲区的大小?存储缓冲区究竟是什么?有更多详细信息(以及指向旧讨论的链接)。

    (最新消息:现在终于有了门店合并的证据,并解释了一种有意义的机制。)

    脚注1:RFO消耗共享带宽,并从其他核心窃取线路,从而降低速度。如果RFO太早,在你真正投入之前,你可能会再次失去这条线。LFB也需要用于加载,您不想让其挨饿(因为等待加载结果时执行会暂停)。加载与存储有着根本的不同,并且通常具有优先顺序。

    因此,至少等待门店毕业是一个不错的计划,而且可能只会对head之前的最后几个门店缓冲区条目启动RFO。(在启动RFO之前,您需要检查L1d是否已经拥有该行,这至少需要标记的缓存读取端口,虽然不是数据。我可能猜存储缓冲区一次检查一个条目,并将一个条目标记为可能不需要RFO。)还请注意,1个SB条目可能是未对齐的缓存拆分存储,并接触2条缓存线,最多需要2个RFO。。。

    脚注2:存储缓冲区条目是按程序顺序分配的(在缓冲区的尾部),因为指令/uops被发布到乱序后端并为它们分配了后端资源。(例如,用于写入寄存器的uops的物理寄存器,用于可能误判的条件分支uops的分支顺序缓冲区条目。)另请参阅Intel硬件上的存储缓冲区大小?存储缓冲区到底是什么?。按顺序分配和提交保证存储的程序顺序可见性。存储缓冲区将全局可见的提交与存储地址和存储数据uops(写入存储缓冲区条目)的乱序推测执行隔离开来,并且通常将执行与等待缓存未命中存储分离,直到存储缓冲区填满。

    PS Intel将存储缓冲区加载缓冲区统称为内存顺序缓冲区(MOB),因为它们需要相互了解才能跟踪推测的早期加载。这与您的问题无关,仅适用于推测性早期加载和检测内存顺序错误推测以及中断管道的情况。

    对于停用的存储指令(更具体地说,它们的“毕业”存储缓冲区条目),它只是必须按程序顺序提交到L1d的存储缓冲区。

     类似资料:
    • 我想优雅地关闭一个线程。然而,一旦关闭被启动,线程应该在结束通常的操作后执行一些关闭操作。 两个线程都使用Hibernate和/或等待,并处理中断异常,它们还在一个循环中处理任务,只需要几毫秒。所以我期望while循环结束,因为Thread.currentThread()。isInterrupted()变为“true”。 问题是,对于我的代码,有时我会得到日志“SHUTDOWN”,有时不会。此外,

    • 为什么会这样?最后,还有其他类似的功能我应该知道是不允许的。

    • 问题内容: 我正在启动一个具有第三方XSD的新项目。我的Java应用程序需要生成符合此XSD的XML消息,并读取符合此XSD的传入XML消息。过去,我为此使用了Apache XMLBeans(http://xmlbeans.apache.org/)。看来XMLBeans已经退休了。现已淘汰的XMLBeans有什么好的替代品?我在其他项目上使用过XStream,但是我不记得XStream能够从XSD

    • 我有应用程序以守护程序模式运行。 我有一个视图,它从数据库中获取重要的queryset,并通过计算queryset的结果另外分配数组,然后返回这个数组。我没有使用线程本地存储、全局变量或任何类似的东西。 问题是,我的应用程序占用的内存与我为mod_wsgi设置的线程数相对应。 我做了一个小实验,在mod_wsgi中设置了不同数量的线程,然后通过curl检查wsgi进程的内存可以爬升多远来点击我的视

    • 我已经编写了一个程序,它监视一个目录,并在用户添加文件时发出警报,该文件的特定格式为用户名。文件它工作正常,但当我在收到新文件被添加的警报时按ok,程序退出,我希望它保持运行。 下面我写的代码将作为该应用程序中另一个PYQT应用程序的子进程运行。因此,我不会执行main(),而只是实例化SendMyFiles对象。

    • 我有以下政策: 我是这样执行政策的: 问题是,当一个动作在开路上执行时,我在断路器回调中没有得到命中。 我希望通过策略放置一个API调用,要处理的异常类型为。政策定义有问题吗?为什么不叫断路器后备?