Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于在x86上缓存命中存储之前执行缓存未命中加载时的指令顺序_X86_Cpu Architecture_Memory Model - Fatal编程技术网

关于在x86上缓存命中存储之前执行缓存未命中加载时的指令顺序

关于在x86上缓存命中存储之前执行缓存未命中加载时的指令顺序,x86,cpu-architecture,memory-model,X86,Cpu Architecture,Memory Model,给出如下所示的小程序(手工制作,从顺序一致性/TSO的角度来看,看起来是一样的),并假设它是由一个超标量无序的x86 cpu运行的: Load A <-- A in main memory Load B <-- B is in L2 Store C, 123 <-- C is L1 Load A术语:“指令窗口”通常意味着无序执行窗口,CPU可以通过该窗口找到ILP。i、 e.ROB或RS尺寸。看 一个周期内可以通过管道的指令数的术语是管道宽度。e、 Skylake是4宽的超

给出如下所示的小程序(手工制作,从顺序一致性/TSO的角度来看,看起来是一样的),并假设它是由一个超标量无序的x86 cpu运行的:

Load A <-- A in main memory
Load B <-- B is in L2
Store C, 123 <-- C is L1
Load A术语:“指令窗口”通常意味着无序执行窗口,CPU可以通过该窗口找到ILP。i、 e.ROB或RS尺寸。看

一个周期内可以通过管道的指令数的术语是管道宽度。e、 Skylake是4宽的超标量。(其管道的一部分,如解码、uop缓存获取和退役,比4个uop宽,但发布/重命名是最窄的一点。)


术语:“等待在存储缓冲区中提交”存储数据+地址在存储区执行时写入存储缓冲区。它在退役后的任何时间点(已知为非推测性的时间点)从存储缓冲区提交到L1d

(在程序顺序中,维护无存储重新排序的TSO内存模型。存储缓冲区允许存储在此核心内无序执行,但仍按顺序提交L1d(并变得全局可见)。执行存储=将地址+数据写入存储缓冲区。

而且


前端不相关。3个连续的指令很可能在同一个16字节的获取块中获取,并且可能在与一个组相同的周期中进行预解码和解码。和(同时或相反)作为3个或4个UOP组的一部分发布到无序后端。IDK为什么你认为这会导致任何潜在的问题

前端(从获取到发布/重命名)按程序顺序处理指令。同时处理不会将后面的指令放在前面的指令之前,而是将它们放在同一时间。更重要的是,它保留了程序顺序的信息;这不会丢失或丢弃,因为它对依赖于上一条指令的指令很重要1

大多数管道级之间都有队列,因此(例如在英特尔Sandybridge上)作为最多6条指令组的一部分进行预解码的指令可能不会作为最多4条指令组的一部分(或使用宏融合的更多指令)到达解码器。有关获取,请参阅,有关解码,请参阅下一页。(以及uop缓存。)


执行(将UOP从无序调度程序发送到执行端口)是排序的关键所在无序调度程序必须避免破坏单线程代码。2

通常,发布/重命名要比执行早得多,除非您在前端遇到瓶颈。因此,通常没有理由期望一起发布的UOP将一起执行。(为了便于讨论,让我们假设您显示的两个加载确实在同一个周期中被调度以执行,而不管它们是如何通过前端到达的。)

但是无论如何,在这里同时启动加载和存储是没有问题的。uop计划程序不知道L1d中的加载是否命中。它在一个周期内只向加载执行单元发送2个加载uop,并向这些端口发送一个存储地址+存储数据uop

  • [加载顺序]
  • 这是棘手的部分。

    正如我在关于的回答和评论中所解释的那样,现代x86 CPU将推测性地使用Load B的L2命中结果作为后续指令,即使内存模型要求此加载发生在Load A之后

    但是,如果在加载A完成之前没有其他内核写入缓存线B,那么就没有什么区别了。内存顺序缓冲区负责检测先前加载完成之前加载的缓存线的失效,并执行内存顺序错误推测管道刷新(回滚到失效状态)在极少数情况下,允许负载重新排序可能会改变结果

  • 为什么商店要等货呢
  • 不会,除非存储地址取决于加载值。uop调度程序将在执行单元的输入就绪时将存储地址和存储数据uop分派给执行单元

    以程序顺序加载后,存储缓冲区将使加载后的全局内存顺序更远。存储缓冲区在存储区失效之前不会将存储数据提交到L1d(使其全局可见)。因为是在装载之后,他们也会退役

    退出是为了允许精确的异常,并确保以前的指令没有发生异常或是预测失误的分支。退出是为了确保指令退出后是非推测性的。)

    因此,是的,这种机制确实确保了在两个加载都从内存中获取数据之前(通过L1d缓存,它为所有内核提供了一致的内存视图),存储不能提交到L1d。因此,这可以防止LoadStore重新排序(早期加载和后期存储)

    我不确定是否有弱排序的OoO CPU进行LoadStore重新排序。当缓存未命中加载出现在缓存命中存储之前时,可以在顺序CPU上运行,并且CPU使用记分板来避免暂停,直到加载数据实际从寄存器读取(如果它仍然没有准备好)。(LoadStore是一个奇怪的商店:另见杰夫·普雷辛的)。也许一些OoO exec CPU还可以跟踪退休后的缓存未命中存储,但数据还没有到达。x86不会这样做,因为它会违反TSO内存模型


    脚注1:有一些体系结构(通常是VLIW),其中同时指令束以软件可见的方式成为体系结构的一部分。因此,如果软件不能用指令填满所有3个插槽,那么