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

循环优化。寄存器重命名如何打破依赖关系?什么是执行端口容量?

柴彬
2023-03-14

我正在分析Agner Fog的optimization\u assembly中的一个循环示例。我指的是12.9章。代码是:(我简化了一点)

L1: 
    vmulpd ymm1, ymm2, [rsi+rax] 
    vaddpd ymm1, ymm1, [rdi+rax] 
    vmovupd [rdi+rax], ymm1
    add rax, 32  
    jl L1   

我有一些问题:

>

  • 作者说,不存在循环携带的依赖关系。我不明白为什么会这样。(我跳过了add rax,32的情况(它确实是循环进行的,但只有一个循环))。但是,毕竟,在上一次迭代尚未完成之前,下一次迭代无法修改ymm1寄存器。也许注册重命名在这里起作用?

    让我们假设有一个循环携带的依赖项<代码>vaddpd ymm1,ymm1,[rdi rax]-

    让第一个的延迟为3,第二个的延迟为7。

    (其实没有这种依赖性,但我想问一个假设性的问题)

    现在,如何确定总延迟。我是否应该添加延迟,结果将是10?我不知道。

    有两个256位读取操作,每个操作使用一个读取端口进行两个连续的时钟周期,表中显示为1。使用两个读取端口(端口2和3),我们将在两个时钟周期内获得两个256位读取的吞吐量。其中一个读取端口将在第二个时钟周期内进行写入地址计算。256位写入占用写入端口(端口4)两个时钟周期。限制因素将是以最大容量使用两个读端口和写端口的读写操作。

    端口的容量到底是多少?如何确定它们,例如IvyBridge(我的CPU)。

  • 共有1个答案

    邹书
    2023-03-14

    >

  • 是的,寄存器重命名的全部目的是在指令写入寄存器而不依赖旧值时打破依赖链。mov或AVX指令的只写目标操作数的目的地是这样的。此外,像xor eax, eax这样的归零习惯用法被识别为独立于旧值,即使它们似乎将旧值作为输入。

    另请参见为什么mulss在Haswell上只需要3个周期,这与Agner的指令表不同?(使用多个累加器展开FP循环)了解寄存器重命名的更详细描述,以及使用多个循环同时运行的依赖链进行的一些性能实验。

    如果不重命名,vmulpd无法写入ymm1,直到vmovupd读取其操作数(读后写危险),但它不必等待vmovupd完成。查看计算机体系结构教科书,了解顺序管道和其他内容。我不确定是否存在任何没有注册重命名的无序CPU。

    更新:早期的OoO CPU使用记分板来执行一些有限的无序执行,而无需重命名寄存器,但在发现和利用指令级并行性方面的能力要有限得多。

    IvB上的两个负载端口中的每个端口的容量为每个时钟一个128b负载。以及每个时钟生成一个地址。

    理论上,SnB/IvB可以维持每个时钟2x128b加载和1x128b存储的吞吐量,但只能通过使用256b指令。它们每个时钟只能生成两个地址,但256b加载或存储每2个数据搬迁周期只需要一个地址计算。参见Agner Fog的微拱指南

    Haswell在端口7上添加了一个专用的存储AGU,它只处理简单的寻址模式,并将数据路径扩展到256b。一个周期可以完成总加载存储96字节的峰值。(但一些未知的瓶颈限制了持续的吞吐量低于此值。在Skylake客户端上,Intel报告的吞吐量约为84字节/周期,与我的测试结果相符。)

    (根据英特尔优化指南的最新更新,据报道,IceLake客户端可以维持每个周期存储2倍64B加载1倍64B,或存储2倍32B。)

    另请注意,您的索引寻址模式不会微融合,因此融合域uop吞吐量也是一个问题。

  •  类似资料:
    • 问题内容: 我是一个长期的python开发人员。我正在尝试Go,将现有的python应用程序转换为Go。它是模块化的,对我来说真的很好用。 在Go中创建相同的结构后,我似乎陷入了周期性的导入错误,这比我想要的要多得多。从未在python中出现任何导入问题。我什至不必使用导入别名。所以我可能有一些在python中不明显的周期性导入。我实际上发现那个奇怪。 无论如何,我迷路了,试图在Go中修复这些问题

    • 问题内容: 我最近一直在使用nodejs,并且仍然要处理模块系统,因此很抱歉这是一个明显的问题。我想要大致如下的代码: a.js (主文件与节点一起运行) b.js 我的问题似乎是我无法从ClassB实例中访问ClassA实例。 有没有正确/更好的方法来构造模块来实现我想要的?是否有更好的方式在模块之间共享变量? 问题答案: 尽管node.js确实允许循环依赖,但正如您所发现的那样,它可能很杂乱,

    • 我最近一直在使用nodejs,并且仍然在掌握模块系统,所以如果这是一个明显的问题,请原谅。我想要大致如下的代码: a.js(主文件与节点一起运行) b.js 我的问题似乎是我无法从ClassB的实例中访问ClassA的实例。 有没有正确/更好的方法来构建模块以实现我想要的?有没有更好的方法在模块之间共享变量?

    • 问题内容: 在我的系统中,我在浏览器中加载了许多“类”,在开发过程中,每个类都有单独的文件,并串联在一起进行生产。加载它们时,它们在全局对象(这里)上初始化一个属性,如以下示例所示: 我考虑使用James Burke的建议,而不是使用自己的全局对象,而是考虑使每个类都具有自己的AMD模块: 问题在于,以前在Employee和Company之间没有声明时间依赖关系:您可以按所需的顺序放置声明,但是现

    • 在基准测试时,我测量到的吞吐量比我计算的低得多,我将其缩小到LZCNT指令(它也发生在TZCNT中),如以下基准测试所示: 和: 我是在4770K上运行的,所以LZCNT和TZCNT不是作为BSR/BSF执行的。 这是怎么回事?

    • 在学习gradle时,我似乎是Java的构建工具。但我不明白依赖到底是什么。Gradle中的依赖项部分到底是什么意思?它有什么用途?