【问题标题】:Cortex A9 NEON vs VFP usage confusionCortex A9 NEON 与 VFP 使用混淆
【发布时间】:2011-11-08 08:32:12
【问题描述】:

我正在尝试为 Cortex A9 ARM 处理器(更具体地说是 OMAP4)构建一个库,但对于在浮点上下文中何时使用 NEON 和 VFP 有点困惑操作和 SIMD。需要注意的是,我知道 2 个硬件协处理器单元之间的区别(也概述了 here on SO),我只是对它们的正确使用有一些误解。

与此相关,我正在使用以下编译标志:

GCC
-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
ARMCC
--cpu=Cortex-A9 --apcs=/softfp
--cpu=Cortex-A9 --fpu=VFPv3 --apcs=/softfp

我已经阅读了 ARM 文档、大量 wiki(like this one)、论坛和博客文章,似乎每个人都同意使用 NEON 比使用 VFP 更好 或者至少混合 NEON(例如,使用内部函数在 SIMD 中实现一些算法)和 VFP 并不是一个好主意;我还不能 100% 确定这是否适用于整个应用程序\库的上下文或仅适用于代码中的特定位置(函数)。

所以我使用霓虹灯作为我的应用程序的 FPU,因为我也想使用内在函数。结果我遇到了一些麻烦,我对如何在 Cortex A9 上最好地使用这些功能(NEON 与 VFP)的困惑只是进一步加深而不是理清。我有一些代码可以为我的应用程序进行基准测试并使用一些定制的计时器类 其中计算基于双精度浮点。使用 NEON 作为 FPU 会产生完全不合适的结果(尝试打印这些值会导致打印主要是 inf 和 NaN;相同的代码在为 x86 构建时可以顺利工作)。所以我改变了我的计算以使用单精度浮点,因为记录表明 NEON 不处理双精度浮点。我的基准测试仍然没有给出正确的结果(最糟糕的是,现在它在 x86 上不再工作了;我认为这是因为精度下降,但我不确定)。所以我几乎完全迷失了:一方面我想将 NEON 用于 SIMD 功能,并将其用作 FPU 并不能提供正确的结果,另一方面将它与 VFP 混合似乎不是一个好主意。 非常感谢这方面的任何建议!

我在上面提到的 wiki 的文章中找到了在 NEON 的上下文中应该为浮点优化做些什么的总结:

"

  • 仅使用单精度浮点
  • 当您发现瓶颈 FP 函数时,请使用 NEON 内部函数/ASM。你可以比编译器做得更好。
  • 最小化条件分支
  • 启用 RunFast 模式

对于softfp:

  • 内联浮点代码(除非它非常大)
  • 通过指针而不是通过值传递 FP 参数,并在函数调用之间执行整数运算。

"

我不能硬使用浮动 ABI,因为我无法链接到我可用的库。 大多数建议对我来说都是有意义的(除了“runfast 模式”,我不完全理解应该做什么以及此时我可以做得比编译器更好的事实)但我一直得到不一致的结果和我现在什么都不确定。

谁能阐明如何正确使用 Cortex A9/A8 的浮点和 NEON 以及我应该使用哪些编译标志?

【问题讨论】:

  • 也试一试自动矢量化。如果使用 ARM RVCT 编译器,请将 --vectorize 添加到命令行(您可能需要专业的 RVCT 许可证才能尝试此操作,因此请记住这一点)
  • 您的建议与 SIMD 有关。我的问题是关于正确使用 VFP 单元的任一 NEON 的浮点功能。

标签: c++ c floating-point arm neon


【解决方案1】:

...论坛和博客帖子,每个人似乎都同意使用 NEON 比使用 VFP 或至少混合使用 NEON 更好(例如,使用 instrinsics 在 SIMD 中实现一些算法),而 VFP 并不是一个好主意

我不确定这是否正确。根据 ARM Introducing NEON Development Article | NEON registers:

NEON 寄存器组由 32 个 64 位寄存器组成。如果两者 实现了高级 SIMD 和 VFPv3,它们共享这个寄存器 银行。在这种情况下,VFPv3 以 VFPv3-D32 形式实现,即 支持32个双精度浮点寄存器。这 集成简化了上下文切换支持的实现,因为 保存和恢复 VFP 上下文的相同例程也保存和恢复 恢复 NEON 上下文。

NEON 单元可以查看相同的寄存器组:

  • 16 个 128 位四字寄存器,Q0-Q15
  • 32 个 64 位双字寄存器,D0-D31。

NEON D0-D31 寄存器与 VFPv3 D0-D31 寄存器相同 每个 Q0-Q15 寄存器映射到一对 D 寄存器。 图 1.3 显示了共享 NEON 和 VFP 的不同视图 注册银行。所有这些视图都可以随时访问。软件 不必在它们之间显式切换,因为 使用的指令决定了适当的视图。

寄存器不竞争;相反,它们作为注册库的视图共存。 NEON 和 FPU 装备是无法吐出的。


与此相关,我正在使用以下编译标志:

-O3 -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-O3 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp

这就是我的工作;你的旅费可能会改变。它源自从平台和编译器收集的信息的混搭。

gnueabihf 告诉我平台使用硬浮点数,这可以加快程序调用。如果有疑问,请使用softfp,因为它与硬浮点兼容。

BeagleBone Black

$ gcc -v 2>&1 | grep Target          
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
model name  : ARMv7 Processor rev 2 (v7l)
Features    : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 
...

所以 BeagleBone 使用:

-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard

CubieTruck v5

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 5 (v7l)
Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 

所以 CubieTruck 使用:

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

香蕉派专业版

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo
Processor   : ARMv7 Processor rev 4 (v7l)
Features    : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt

所以香蕉派使用:

-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard

树莓派 3

RPI3 的独特之处在于它的 ARMv8,但它运行的是 32 位操作系统。这意味着它实际上是 32 位 ARM Aarch32。 32 位 ARM 与 Aarch32 相比,还有更多,但这将向您展示 Aarch32 标志

此外,RPI3 使用 Broadcom A53 SoC,它具有 NEON 和可选的 CRC32 指令,但缺少可选的 Crypto 扩展。

$ gcc -v 2>&1 | grep Target 
Target: arm-linux-gnueabihf

$ cat /proc/cpuinfo 
model name  : ARMv7 Processor rev 4 (v7l)
Features    : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
...

所以树莓派可以使用:

-march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard

或者可以用(-mtune不知道用什么):

-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard 

ODROID C2

ODROID C2 使用 Amlogic A53 SoC,但它使用 64 位操作系统。 ODROID C2,它具有 NEON 和可选的 CRC32 指令,但缺少可选的 Crypto 扩展(类似于 RPI3 的配置)。

$ gcc -v 2>&1 | grep Target 
Target: aarch64-linux-gnu

$ cat /proc/cpuinfo 
Features    : fp asimd evtstrm crc32

所以 ODROID 使用:

-march=armv8-a+crc -mtune=cortex-a53

在上述秘籍中,我通过查看数据表了解了 ARM 处理器(如 Cortex A9 或 A53)。根据Unix and Linux Stack Exchange 上的这个答案,它解读了/proc/cpuinfo 的输出:

CPU 部件:部件号。 0xd03 表示 Cortex-A53 处理器。

所以我们可以从数据库中查找值。我不知道它是否存在或它的位置。

【讨论】:

    【解决方案2】:

    我认为这个问题应该分成几个,添加一些代码示例并详细说明目标平台和使用的工具链版本。

    但是为了掩盖混乱的一部分: “使用 NEON 作为 FPU”的建议听起来像是一种误解。 NEON 是 SIMD 引擎,VFP 是 FPU。您可以使用 NEON 并行处理最多 4 个单精度值的单精度浮点运算,这(如果可能)有利于提高性能。

    -mfpu=neon 可以看作是-mfpu=neon-vfpv3 的简写。

    更多信息请参见http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html

    【讨论】:

      【解决方案3】:

      我会远离 VFP。就像 Thmub 模式一样:它是为编译器准备的。为它们优化是没有意义的。

      这听起来可能很粗鲁,但我也真的看不出 NEON 内在函数有任何意义。麻烦多于帮助 - 如果有的话。

      只需花两三天时间进行基本的 ARM 组装:您只需要学习很少的循环控制/终止指令。

      然后您就可以开始编写本机 NEON 代码,而不必担心编译器会执行一些错误/警告。

      学习 NEON 指令的要求低于所有这些内在宏。除此之外,结果要好得多。

      完全优化的 NEON 原生代码的运行速度通常是编写良好的内部函数对应代码的两倍以上。

      只需在下面的链接中将 OP 的版本与我的版本进行比较,您就会明白我的意思。

      Optimizing RGBA8888 to RGB565 conversion with NEON

      问候

      【讨论】:

      • 对 NEON 内在函数的不良支持是 GCC 的问题。更好的编译器可以很好地优化它们。但是,我同意,有时用直接 asm 编写比浪费时间找出某些操作码的正确内在名称更容易
      • 另外,VFP 和 SIMD 是不同的东西。例如,使用 NEON for sqrt 会浪费时间并且可能无法获得适当的结果。
      • “这听起来可能很粗鲁,但我也真的看不出 NEON 内在函数有任何意义。这比帮助更麻烦......” - NEON 在实践。 BLAKE2 hash 在 C 中的基线为 35 cpb,在 NEON 下降至 10 cpb。 CAESAR (Competition for Authenticated Encryption: Security, Applicability, and Robustness) 还看到候选密码的加速。另请参阅SUPERCOP ARMv7 w/ NEON 和相关基准。
      • @jww 你误会了。我说的是“NEON Intrinsics”。我完全相信 NEON 的潜力。如果使用 Intrinsics 获得 10,则使用纯汇编将获得 15~20。这就是我的观点。
      • @Jake'Alquimista'LEE 但是您还需要手动展开和软件管道循环(注意尾部!),更不用说分配寄存器和调度(取决于目标)。跨度>
      猜你喜欢
      • 1970-01-01
      • 2011-05-05
      • 2015-10-14
      • 1970-01-01
      • 2011-10-06
      • 2012-03-12
      • 1970-01-01
      • 2015-08-12
      • 1970-01-01
      相关资源
      最近更新 更多