【问题标题】:Is there an advantage of specifying "-mfpu=neon-vfpv3" over "-mfpu=neon" for ARMs with separate pipelines?为具有单独管道的 ARM 指定“-mfpu=neon-vfpv3”而不是“-mfpu=neon”是否有优势?
【发布时间】:2017-12-12 08:54:09
【问题描述】:

我的 Zynq-7000 ARM Cortex-A9 处理器同时具有 NEON 和 VFPv3 扩展,并且 Zynq-7000-TRM 表示处理器配置为具有“用于 VFPv3 和高级 SIMD 指令的独立管道” em>。

到目前为止,我使用 Linaro GCC 6.3-2017.05 和 -mfpu=neon 选项编译了我的程序,以利用 SIMD 指令。但是在编译器也有非SIMD操作要发出的情况下,使用-mfpu=neon-vfpv3会有区别吗? GCC 的指令选择和调度器是否会为这两个版本发出指令,以便它可以利用这两个流水线来提高 CPU 的利用率?

【问题讨论】:

  • 您还需要 -ffast-math 进行自动矢量化,因为 ARMv7 NEON 不支持非规范化,因此不完全符合 IEEE。 (或类似的东西;您需要 -ffast-math 进行自动矢量化,但您可以在没有 -ffast-math 的情况下使用 NEON 内在函数)。
  • @PeterCordes 是的,它甚至用-funsafe-math-optimizations 进行了矢量化。但我想知道对于非矢量化代码,或者同时包含矢量化和非矢量化变体的代码,是否可以通过利用这两个管道来提高性能。
  • 我只知道 x86 CPU 的那种微架构细节,不知道 ARM。这么好的问题,这就是我投票的原因。希望有人会回答。它有点类似于 x86 -march=sse+387,它可以生成一些笨重的代码,但它们使用不同的架构寄存器。 VFP and NEON use the same registers,所以对好的代码生成有更多的希望。
  • @PeterCordes 这“需要 -ffast-math 进行自动矢量化,因为 ARMv7 NEON 不支持非规范化,因此不完全符合 IEEE”今天也成立吗? armv8 64 位也适用吗?
  • @Danijel:IIRC,AArch64 SIMD 支持 denomrals aka subnormals。我忘记了 ARMv7 是否有控制位,但 32 位模式下的 ARMv8 可能具有符合 IEEE 标准的 SIMD。

标签: gcc assembly arm neon armv7


【解决方案1】:

从技术上讲,是的。

现实,不。

NEON 在 ARMv7 上是可选的。

被许可方可以从以下配置中选择一种:

  • 仅限 VFP
  • NEON 加 VFP

与 NEON 不同,ARMv7 上有不同的 VFP 版本,Cortex-A8 上的 VFP-lite 是最臭名昭著的版本,因为没有流水线,因此非常慢。

因此,通过编译器选项指定 CPU 配置和架构版本在技术上是有意义的,这样编译器就可以为该特定架构/配置生成最优化的机器代码。

然而,实际上,如今的编译器忽略了大多数这些构建选项,甚至还忽略了指令。

而且将 VFP 和 NEON 指令分配给不同的流水线也无济于事,因为它们都共享寄存器组。

通过使用尽可能多的寄存器来提升 NEON 的性能,所带来的好处远不止让 VFP 并行运行。

这让我很困惑,为什么以及如何这么多人如此信任免费编译器。

目前最好的 ARM 编译器是价值 6000 美元以上的 DS-5 Ultimate Edition 附带的 ARM 编译器。他们的支持非常好,但我不确定它是否能证明价格合理。

【讨论】:

  • 根据to this,Cortex-A9 是“部分失序”。这是否仍然意味着它需要所有架构寄存器来进行 NEON 指令的软件流水线化?因为如果不是,那么根据问题,如果 VFP 在那个 CPU 上并不可怕,可能会有一些空闲带宽(和物理寄存器文件空间)混合到一些 VFP 中。或者这没有意义? (不过,我同意我不会对 gcc 做得好过于乐观。我更感兴趣的是最优 asm 是否可以利用。)
  • @PeterCordes 考虑到我自己执行的测试结果,我认为 A9 不会乱序执行 NEON 指令。甚至 Galaxy-S7 上的 Exynos 8890 似乎也没有正确利用乱序引擎。我很快就会在我的博客上发布这些测试,您将是第一个收到通知的人。这将是一个神话终结者的地狱。
  • 它是否至少会进行寄存器重命名,这样您就可以在没有错误依赖的情况下重用寄存器? (即avoid WAW and WAR hazards)。只是在这里猜测,但这可能就是他们所说的“部分无序”。按顺序重命名(Tomasulo 算法)不需要昂贵的调度程序,只需要 RAT(寄存器分配表)和管道中的重命名阶段。 (还有更简单但功能较弱的重命名方案,例如记分牌)。
  • 在整数核心上,很可能是的,但从我目前看到的情况来看,我什至怀疑大集群 NEON 执行无序,至少在特定的三星定制上设计。
  • 嗯,我没有仔细考虑我之前的评论。我不认为,按顺序执行不会从寄存器重命名中受益,不足以证明它的合理性。如果指令按顺序开始,如果某些指令延迟较高,它们仍然可以乱序写回,因此 WAW 是一种可能的危险,但不是 WAR。 (我认为我们可以假设每条指令在下一条写回之前读取其操作数)。单独的 WAW 不太可能:大多数代码不会写入他们从未读取过的寄存器,并且按顺序执行会阻止写入在指令卡住等待其输入之前开始。这就是 reg 重命名所能做的。
【解决方案2】:

ARM's Cortex-A9 NEON/VFP manual (Cortex™ -A9 霓虹灯™ 媒体处理 Engine)在第 3.2 节编写最佳 VFP 和高级 SIMD 代码中说:

以下指南可以显着提高 VFP 和 Advanced 的性能 SIMD 代码:尽可能避免

  • ...

  • 混合仅高级 SIMD 指令与仅 VFP 指令。

它说它可以与 ARM 或 Thumb 指令(即标量整数代码)并行执行 NEON 和 VFP 指令,“同时加载和存储除外”。

不是 100% 清楚它们是否意味着完全避免让它们在飞行中,或者它们是否意味着避免在 VFP 和 NEON 指令之间存在数据依赖关系。很容易想象后者因为不适用于前者的原因而变得不好(例如,不同域中的执行单元之间可能没有绕过转发)。


同一文档中的周期时序表明,VFP 标量指令在流水线中花费的时间比 NEON 指令长(即使延迟看起来相同),因此可能使用 VFP 对不进行矢量化的代码来说是一种胜利,即使是-ffast-math。或者,如果我没看错的话,NEON 的 MUL 延迟较低,因此可能是长依赖链的胜利。

Cortex-A9,如果它具有 VFP,则具有完全流水线的 VFP FPU。例如

  • VADD/VSUB .F (Sn) 或 .D (Dn) ((VFP):1c 吞吐量。第 1 周期需要输入,第 4 周期准备好结果。(那么 4c 延迟?)

  • VADD/VSUB Dn (NEON):1c 吞吐量。周期 2 需要输入,周期 5 准备好结果(周期 6 回写)。 (所以是 4c 还是 5c 延迟?取决于消耗结果的内容)。

  • VADD/VSUB Qn (NEON):(每 1 个)2c 吞吐量。在第 2 周期和第 3 周期需要输入,在第 5 周期和第 6 周期准备好结果。(写回 1c 比这晚)(那么是 4c 还是 5c 延迟?)。

  • VMUL .F Sd,Sn,Sm (VFP):1c 吞吐量,第 1 周期需要输入,第 5 周期准备好结果。(所以 5c 延迟?)

  • 没有列出具有双精度的 VMUL (VFP),仅列出了 VNMUL(2c 吞吐量)。

  • VMUL (NEON):与 VADD/VSUB 相同的时序。也许不处理非规范化允许捷径?如果我没看错的话,它实际上比 VFP 延迟更低,除了需要更早发出的指令。

还有用于乘法累加的特殊结果转发。请参阅 PDF。

【讨论】:

  • vmulvmla/vmls 指令似乎有某种切换开销。几周前有一个关于这个的问题。我自己进行了一些测试,似乎是这样。不过,我从来没有在任何文档中读过这样的内容。
【解决方案3】:

答案将取决于 gcc 的版本,未来可能会发生变化。 current code in cortex-a9.md 将 NEON/VFP 描述为一个组合单元。这条线是,

(define_cpu_unit "ca9_issue_vfp_neon, cortex_a9_ls" "cortex_a9")

使用 cmets,

;; The Cortex-A9 core is modelled as a dual issue pipeline that has
;; the following components.
;; 1. 1 Load Store Pipeline.
;; 2. P0 / main pipeline for data processing instructions.
;; 3. P1 / Dual pipeline for Data processing instructions.
;; 4. MAC pipeline for multiply as well as multiply
;;    and accumulate instructions.
;; 5. 1 VFP and an optional Neon unit.
;; The Load/Store, VFP and Neon issue pipeline are multiplexed.
;; The P0 / main pipeline and M1 stage of the MAC pipeline are
;;   multiplexed.
;; The P1 / dual pipeline and M2 stage of the MAC pipeline are
;;   multiplexed.
;; There are only 4 integer register read ports and hence at any point of
;; time we can't have issue down the E1 and the E2 ports unless
;; of course there are bypass paths that get exercised.
;; Both P0 and P1 have 2 stages E1 and E2.
;; Data processing instructions issue to E1 or E2 depending on
;; whether they have an early shift or not.

ca9_issue_vfp_neon 单元用于描述 NEON 和 VFP 指令。所以调度器在计算成本时不会知道指令可以流水线化。但是,它可能会同时发出两者,幸运的是,它们会被流水线化。

在“arm.c”中,NEON 用于传输数据的情况很多。如果您的代码具有许多结构的浮点,编译器可能会混合使用 NEON 和 VFP 代码,其中 NEON 用于移动数据。

exynos 这样的机器有一些自定义调优,比如使用 neon 进行字符串操作,因为它在 arm.c 中没有调优描述,因此您的 Zync CPU 无法获得这些操作。

另外,如果您不指定-mfpu=neon-vfpv3,任何带有“vfpv3”指令的内联汇编器都将无效。


根据 GCC 版本,情况会有所不同。但是,您可以在“cortex-a9.md”中查找 CPU 描述,以查看编译器是否可以以不同的方式调度指令。此外,“arm.c”文件执行指令成本计算;如果此处未实现 NEON 成本,则编译器将永远不会发出指令。

在与更简单的 ARMv5 DSP 指令作斗争后,即使这可以工作,您也会发现只有 1-2% 的指令会发生变化。在数兆字节的图像中,由于其他人给出的原因(共享寄存器、浮点上的“C”语义等),这样的选项只会更改几百个操作码。

但是,如果-mfpu=neon-vfpv3 确实描述了您的 CPU,您为什么不将它用于嵌入式应用程序?通用选项旨在生成可以在不止一种类型的设备上运行的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 2013-09-18
    • 1970-01-01
    • 2020-09-12
    • 2011-05-11
    • 1970-01-01
    相关资源
    最近更新 更多