"存储缓冲区转发"在英特尔开发人员手册中的含义是什么?

jac*_*bsa 12 concurrency assembly intel cpu-architecture memory-model

英特尔64和IA-32架构软件开发人员手册说,大约由单一处理器的行动("在P6更多最近的处理器系列内存排序和"第8.2.2节)重新排序如下:

读取可以使用较旧的写入到不同位置进行重新排序,但不能使用较旧的写入到同一位置.

接下来讨论与早期处理器相比放松的点时,它说:

存储缓冲区转发,当读取将写入传递到同一存储器位置时.

据我所知,"存储缓冲区转发"并未在任何地方精确定义(也不是"通过").读取将写入传递到同一位置是什么意思,因为上面说它不能通过写入同一位置来重新排序?

Han*_*ant 10

我猜这个挂起是"存储缓冲区"的概念.起点是处理器核心速度与内存速度之间的巨大差异.现代核心可以在一纳秒内轻松执行十几个指令.但RAM芯片可能需要150纳秒才能提供存储在内存中的值.这是一个巨大的不匹配,现代处理器充满了解决这个问题的技巧.

读取是更难解决的问题,当需要等待内存子系统提供值时,处理器将停止并且不执行任何代码.处理器中的一个重要子单元是预取器.它试图预测程序将加载哪些内存位置.因此它可以告诉内存子系统提前读取它们.因此,物理读取比程序中的逻辑加载更快发生.

写入更容易,处理器有缓冲区.将它们建模为软件中的队列.因此,执行引擎可以快速地将存储指令转储到队列中,并且不会陷入困境,等待物理写入发生.这是存储缓冲区.因此,对内存的物理写入比程序中的逻辑存储要晚得多.

当程序使用多个线程并且它们访问相同的内存位置时,麻烦就开始了.这些线程将在不同的核心上运行.这方面的许多问题,排序变得非常重要.显然,预取器执行的早期读取会使其读取过时值.而存储缓冲区执行的后期写入使其更糟糕.解决它需要线程之间的同步.这是非常昂贵的,处理器很容易停滞几十纳秒,等待内存子系统赶上.而不是线程使您的程序更快,他们实际上可以使它更慢.

处理器可以提供帮助,存储缓冲区转发就是这样一种技巧.当存储仍在缓冲区中并且尚未执行时,一个线程中的逻辑读取可以传递由另一个线程启动的物理写入.如果程序中没有同步,则总是会导致线程读取过时的值.存储缓冲区转发的作用是查看缓冲区中的挂起存储,并找到与读取地址匹配的最新写入.这样可以及时"转发"商店,使其看起来像是早于它执行.线程获得实际值; 最终会在记忆中结束的那一个.读取不再通过写入.

实际上编写一个利用存储缓冲区转发的程序是不可取的.从非常不合时宜的时间来看,这样的程序将非常非常糟糕地移植.英特尔处理器具有强大的内存模型,并提供订购保证.但是你现在不能忽视移动设备上流行的那种处理器.通过提供这样的保证,消耗更少的电力.

而且该功能实际上可能非常有害,它会隐藏代码中的同步错误.它们是诊断最糟糕的错误.在过去的30年里,微处理器取得了惊人的成功.然而,他们并没有更容易编程.


Rad*_*adu 10

命名有点尴尬."转发"发生在核心/逻辑处理器内部,如下所示.如果您首先进行存储,它将转到存储缓冲区以异步刷新到内存.如果在将值刷新到缓存/内存之前对相同处理器上的相同位置执行后续LOAD,则将"转发"存储缓冲区中的值,您将获得刚刚存储的值.读取是"传递"写入,它发生在从存储缓冲区到存储器(尚未发生)的实际写入之前.

如果您只是关心排序规则,那么该声明实际上并没有多说 - 这个转发是他们内部做的一个细节,以保证(在处理器上)读取不会重新排序与旧写入到同一位置(部分你引用的规则).

尽管这里有一些其他答案,但是(至少就订购保证而言)处理器/核心之间没有存储缓冲区转发/窥探,因为8.2.3.5"允许处理器内转发"示例手册显示.