我正在从事一个非常关键的性能项目,其中每个时钟周期在我最重要的内循环中都很重要。我正在考虑重构代码以隐藏指令延迟,但我想知道现代 CPU 的乱序执行硬件在多大程度上已经为我做到了这一点。考虑以下(简单的、假设的)示例:

// Increment three counters.  These instructions should all execute in
// parallel with latency of one cycle.  Assume the previous register values
// have been computed a long time ago and are ready to use by the time
// these are decoded.
add RAX, 1;
add RBX, 2;
add RCX, 3;

// Multiply takes at least three cycles.  Again, assume both inputs are
// ready by the time we get here.
imul RDX, RDI;

// Use the result of the imul immediately in a long dependency chain.
mov RDX, [RDX];
cmp RDX, 1;
jae LBlahBlahBlah;

我的问题是以下哪一项适用:
  • 现代主流乱序硬件将在三个 imul 指令之前重新排序 add,即使 add 指令以编程方式出现在 imul 之前,并且在解码时它们的所有输入依赖项都可用。 imul 具有比 add 指令更长的延迟,并且在依赖链中立即使用,因此这是最佳的。
  • 乱序执行仅在由于缺少输入依赖性而无法执行以编程方式进行的较早指令在解码时发生。不能指望硬件“向前看”来动态优化这样的事情。
  • 最佳答案

    您的第二种解释是正确的,乱序执行背后的想法是确保长依赖链或其他长时间运行的指令(如内存访问)不会阻塞独立操作(如与长时间运行无关的两个寄存器之间的加法)指令)并允许它们并行执行。但是,指令是按顺序提取和解码的。处理器无法提前查看程序,确定一条指令是独立的指令并在检索其他指令之前运行它。这就是编译器应该优化的地方。

    在您的示例中,指令是按顺序获取和解码的,首先是 add RAX, 1 ,然后是 add RBX, 2 ,然后是 add RCX, 3 ,然后是 imul RDX, RDI (尽管如果处理器是 super 处理器,您可以获取和解码多个指令,但这是一个单独的概念)。每个都将依次分配到适当的保留站,但是,如果只有一个单元来执行加法,那么某些加法可能会与 imul 同时执行;这非常依赖于架构。

    如果时间要求的细节如此严格,那么您将需要对现代高速架构格外小心,因为它们具有大量复杂的结构来提高性能。但是,根据运行的代码,这些机制可能会导致显着的延迟。分支预测和缓存只是发生未命中或错误预测(或正确使用时很好的吞吐量改进)时的两个延迟来源。最好的办法是获得一个周期精确的处理器模拟器,以确保您的代码满足要求(或者您可以潜在地使用实际硬件)。

    另请注意,如果您使用的是现代架构,我假设您可能正在运行操作系统,这是一个会破坏您试图获得的超高性能的软件级别。

    关于performance - 硬件乱序 : How "smart" is it?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23531492/

    10-15 06:33