【问题标题】:Is Haswell dual path execution CPU?Haswell是双路径执行CPU吗?
【发布时间】:2023-11-07 14:58:01
【问题描述】:

Haswell 现在有 2 个分支机构 - 如下所示:http://arstechnica.com/gadgets/2013/05/a-look-at-haswell/2/

是不是说Haswell是双路执行CPU?

就:http://ditec.um.es/~jlaragon/papers/aragon_ICS02.pdf

这是否意味着 Haswell 只能在 Integer ALU & Shift(端口 6)上执行 2-nd 分支,而不能在其他端口上的任何其他 ALU 上执行?

【问题讨论】:

  • 我不认为这个问题太不清楚以至于应该关闭它。它充满了误解(就像这个用户之前的一些问题),但还没有到无法回答的地步。我确实不得不猜测最后一段中的额外问题应该是什么。不过,如果它像我在回答中所做的那样包含论文摘要,那将是一个更好的问题,因为如果该链接断开,该问题将变得无法回答且毫无意义。

标签: x86 x86-64 intel cpu-architecture branch-prediction


【解决方案1】:

不,Haswell 仍然只沿着分支的预测侧进行推测。

port0 上的分支单元只能执行预测的未采用分支,从Agner Fog's instruction tables 可以看到。这加快了执行比较和分支的大链,其中大多数都没有被采用。这在编译器生成的代码中并不罕见。

请参阅 David Kanter 的 Haswell 文章,特别是 the page about execution units。如果 Haswell 已经介绍了您链接的那篇论文中描述的功能,那么 Kanter 的文章就会提到它,英特尔的优化手册和 Agner Fog 的 microarch pdf 也会提到它。 (请参阅 标签 wiki 以获取指向该链接的链接以及更多信息)。

port6 上的整数/分支单元的一大优势是它不与任何向量执行端口共享。所以一个循环可以有 3 个向量 ALU 微指令和一个分支,并且每个循环仍然运行一次迭代。大卫坎特的文章也说了同样的话。


这是否意味着 Haswell 只能在 Integer ALU & Shift(端口 6)上执行 2-nd 分支,而不能在其他端口上的任何其他 ALU 上执行?

如果该论文中的想法得到实施,它将影响整个管道,而不仅仅是执行分支的端口!

From the paper:

双路径指令 处理(DPIP)被提出作为一种简单的机制, 获取、解码和重命名但不执行指令 来自低置信度预测分支的替代路径 在执行预测路径的同时。

所以实际上备用路径不涉及执行单元。这应该是显而易见的......

【讨论】:

  • 谢谢! IE。 Branch[Port-6] 仅用于“一个循环可以有 3 个向量 ALU 微指令和一个分支,并且每个循环仍然运行一次迭代。”?还是 Branch[Port-6] 允许 2 个超线程线程在其他分支上运行?
  • @Alex:超线程与此无关。乱序内核每个时钟只能引退一个预测采用的分支。不过,分支预测在管道中发生得更早。此外,3 向量 ALU 微指令只是一个示例用例。端口 6 可以运行简单的 ALU 操作,例如 add,因此它们的吞吐量在 Haswell 上为每时钟 4 次,而在 IvB/SnB 上为每时钟 3 次。
【解决方案2】:

您不需要同时执行这两条路径 - 鉴于通常平均每 5 条指令就有一个分支,这将很困难,因为您很快就会得到指数级数量的路径。即使你只是在难以预测的分支上出现这样的分歧,你仍然可能最终得到大量并行路径。

添加第二个分支单元的原因要简单得多 - 在无序机器中,即使计算单个预测的“主”执行路径,您最终仍会得到大量运行中的分支.请注意,预测是在管道的开头完成的,因此它与每个分支的实际执行和解析解耦。在实践中,前端会给机器提供分支,OOO机器需要解决依赖关系并尽可能快地执行它们(因为你想尽早解决预测,如果你错了就恢复) .我猜设计人员发现需要额外的执行带宽,因为可能存在多个分支(甚至可能在程序顺序上不连续)同时准备好它们的源代码并突然需要一次执行所有的情况。因此,关于“第二欧盟高分支代码”的评论。

除了分支相互冲突之外,您可以看到执行端口 0 还承载着许多其他类型的操作,因此您也可能有一个准备好执行的分支,但由于其他非分支操作而停滞不前。因此,关于端口 0 冲突的其他评论(理论上,他们可能只是将分支执行单元移动到另一个端口,但这会增加其他冲突,并且不会解决分支与分支冲突)。

【讨论】:

  • Pre-Haswell CPU 在端口 5 上有分支单元,因此例如 FP-heavy 代码可以用 FP mul 使端口 0/1 饱和并添加 uops 并在 p5 上运行循环开销(希望大多数情况下) .
  • 关于尽早发现错误预测的有趣点。我主要考虑的是分支繁重代码的分支吞吐量,而不是延迟。我不确定前端是否每个时钟可以处理一个以上的预测分支。 uop 缓存缓存跟踪,所以它是可能的。但如果不是,这就解释了为什么 port0 只处理预测未采用的分支:无论如何,前端每个时钟只能维持一个采用的分支。或者,另一个原因可能是确保预测的循环分支永远不会窃取 p0 并降低向量 ALU 吞吐量。
  • @PeterCordes,你所说的“处理”是什么意思,预测还是恢复?我不确定前端可以或应该恢复多个,但并非所有执行的分支都会导致错误预测。如果是关于预测 - 前端和后端可能具有解耦带宽 - 您可以预测每个周期 1 个分支,但仍然会在后端出现局部拥塞(例如 - switch(x) 将有任意数量的分支(案例) 准备好在生成 x 后执行),无论前端将它们输入 OOO 机器需要多长时间。
  • 我的意思是前端可以发出一组最多 4 条微指令,在同一个周期中带有两个预测的分支。这意味着 RIP 在同一个周期中有两个额外的变化。 IIRC,一个预测采取的分支结束一个问题组。例如6 uop 循环最多每 2 个时钟运行一次迭代,而不是每 1.5 次迭代。 (因为它发出 ABCD EF / ABCD EF。不是 ABCD EFAB / CDEF)。就像你提到的,我也猜到分支预测器每个周期可能只能生成一个预测。
  • 我不确定分支预测何时发生。如果 predict-taken 和 predict-not-taken uop 可以位于 loopback buffer 中而无需重新预测,则应该可以维持发出 4 uop look 并在 body 中使用未采用的分支和在结束。如果没有,那么未采用分支的额外执行能力可能最适用于您提到的情况,其中x 直到多个分支发布后才准备好。仅这种确切的情况就足以证明额外的分支单元是合理的。