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

无序执行,如何解决真正的依赖关系?

田焕
2023-03-14

我在读OOOE(无序执行)以及如何解决虚假依赖关系(通过使用重命名)。

但我的问题是,我们如何解决真正的依赖关系(RAW-写后读)?

例如:

R1=R2+R3 #1
R1=R4+R5 #2
R9=R1 #3

如果CPU选择在#1之前运行#2,则重命名在此处没有帮助。

共有1个答案

储嘉悦
2023-03-14

没有办法真正避免它们,这就是为什么RAW危险被称为真正的依赖项。指令必须等待其输入准备好才能执行。(使用OoO exec,通常CPU会将最旧的就绪优先指令/uops分派到执行单元,例如在Intel CPU上。)

真正的依赖关系并不是让它们消失的意义上的“解决”,而是计算的本质,是将相同数字上的多个计算粘在一起形成一个算法的方式。其他危害(WAR和WAW)只是实现细节,将相同的体系结构寄存器用于不同的内容。

有时,您可以将算法构建为具有较短的依赖链,一旦事情已经被固定到机器代码中,CPU几乎只需要尊重它们,充其量是无序执行来重叠独立的dep链。

对于负载,理论上有值预测,但实际上没有真正的CPU在这样做。预测失误的代价很高,就像分支机构一样。这就是为什么您只想考虑高延迟的东西,比如缓存中丢失的负载,否则收益不会超过成本。(即便如此,也没有做到这一点,因为即使对于负载,收益也不会超过成本,包括构建预测器的功率/面积成本。)正如Paul Clayton指出的,分支预测是一种价值预测(预测负载所基于的条件)。使用OoO exec可以一次执行的指令越多,就越容易因预测失误而丢失,但真正的CPU确实会预测/推测内存消除歧义(加载是否将早期存储重新加载到未知地址),并且(在像x86这样具有强顺序内存模型的CPU上)推测早期加载将被允许;以及众所周知的控制依赖情况(分支预测推测执行)。

唯一能直接帮助依赖链的是保持较低的指令延迟。e、 g.在您的示例中,#3只是一个寄存器副本,现代x86 CPU可以在零延迟(mov消除)的情况下完成,因此依赖于R9的另一条指令不必等待超过#2的额外周期来生成结果,因为它是在寄存器重命名期间处理的,而不是由执行单元以正常方式读取输入并生成输出。

显然,绕过从执行单元的输出到相同或其他单元的输入的转发对于保持低延迟至关重要,就像在有序的经典RISC管道中一样。

或者更传统地,通过改进执行单元,例如AMD Bulldozer系列对大多数SIMD整数指令具有2周期延迟,但对于AMD的下一个设计Zen,这改进为1周期。(标量整数的东西,例如add在任何正常的高性能CPU上总是1个周期。)

具有足够大窗口大小的OoO exec允许您并行重叠多个dep链(如在本实验中,当然软件应该旨在具有足够的指令级并行性(ILP)以供CPU查找和利用。(请参阅为什么mulss在Haswell上只需要3个周期,不同于Agner的指令表?(使用多个累加器展开FP循环),例如通过将点积求和为多个累加器来做到这一点。)

如果是由编译器静态完成的,这对于顺序CPU也很有用,其中“软件管道”之类的技术很难重叠多个循环迭代的执行,因为硬件无法为您找到这种并行性。或者对于窗口大小有限的OoO exec CPU,对于每个迭代中具有长但不带循环的依赖链的循环。

只要您在延迟/依赖链以外的东西上遇到瓶颈,真正的依赖就不是问题。例如,前端瓶颈,理想情况下在管道宽度上达到最大值,和/或所有相关的后端执行单元每个周期都很忙,这意味着即使管道是独立的,您也无法通过管道获得更多工作。

当然,在很多代码中都有足够的依赖性,包括通过内存的依赖性,无法达到理想的情况。

同时多线程(SMT)有助于保持后端有工作要做,通过让一个物理核的前端读取多个指令流,充当多个逻辑核,提高吞吐量。这有效地创建了线程级并行之外的ILP,如果软件可以有效地扩展到更多线程,这将非常有用,从而公开足够的TLP以保持所有逻辑核心繁忙。

相关:

  • 现代微处理器90分钟指南
  • 每个汇编指令需要多少CPU周期?-这不是它在超标量OoO exec CPU上的工作方式;延迟、吞吐量或前端瓶颈可能是相关因素
  • 在预测现代超标量处理器上操作的延迟时,需要考虑哪些因素?如何手动计算它们
 类似资料:
  • 我现在开始学习Java和Spring Boot,并且在集成测试中遇到了一些依赖注入问题。我在src/main/java/com/rfd/domain/service下有一个名为TransactionService的类,它被标记为@Service,它有另一个依赖项,其中一个是Spring Boot创建的存储库。当我启动应用程序时,它会正确启动,因此我假设依赖项正在正确解析。这是总结的类: 现在,我在

  • 当我尝试添加新项目并修改我的gradle(添加依赖项)时,我在同步gradle后收到了这条消息: 无法解析“”的依赖项:app@debugAndroidTest/compileClasspath“:无法下载kotlin-stdlib-1.4.31.jar(org.jetbrains.kotlin:kotlin stdlib:1.4.31) 显示详细信息 受影响的模块:应用程序 我无法单击“显示详细

  • 很高兴有一个更新的Android Studio 3.0。但是我在Android Studio 3.0中遇到了一个问题,我刚刚在Android Studio 3.0中创建了一个新项目。然后我犯了一些错误 我通过将依赖项更改为最新版本并解决问题来解决这些问题。 但是,当我添加了facebook帐户工具包sdk的依赖项时。脸谱网。android:帐户工具包sdk:4 我收到以下错误-: 错误:无法解析“

  • 詹金斯1.500版有问题。我正在尝试建立一个依赖于我的另一个项目的项目。错误是:

  • 我对ivy没有解析我的一些依赖关系有问题。以下是我如何重现这个问题的: 我在eclipse中有一个空的java项目。我已经在我的项目中添加了ivy.xml: 这工作正常,ivy能够解决和下载口水。 如果我将修订版更改为6.3.0.Final(http://mvnrepository.com/artifact/org.drools/drools-core/6.3.0.Final),它将不起作用,我看

  • 问题内容: 我在ivaven.xml中添加了一个依赖项(让我们将其命名为A),它在maven Central中具有一个pom文件。Ivy使用ibiblio解决了Maven依赖关系。添加到ivy.xml的依赖项(A)具有传递的依赖项(B)。到目前为止,到目前为止很好。常春藤无法解决传递性依赖项(B)的依赖项(C)。 我在ivy.xml中定义了A,如下所示: 在B的pom文件中,在编译和测试范围中都定