写点什么

大前端 CPU 优化技术 --NEON 技术

作者:江湖修行
  • 2024-02-02
    北京
  • 本文字数:3440 字

    阅读完需:约 11 分钟

大前端CPU优化技术--NEON技术

前言

在上一篇中我们讲了 SIMD 技术的基础和前世今生,可以结合上一篇文章一起看大前端CPU优化技术--SIMD技术。今天我们全局性地讲解下 NEON 技术。


目前主流的移动设备以 ARM v7 和 v8 版本架构占据了绝大多数的江山,随着近几年 64 位手机的普及和各大应用市场的强推下,64 位的 v8 呈崛起之势。


ARM 在 ARMv5 架构开始引入 VFP(vector-floating-point) 指令扩展,可以通过使用短向量指令来加速浮点计算。


armv6 架构中已经提出了一些 simd 的指令,可将多个 16bit,8bit 的数据加载到 32bit 寄存器中,但是并没有单独的执行单元也没有单独的流水线。指令名字就是在之后加 16 或 8 的后缀。


armv7 开始引入了 advanced SIMD,定义了自己的向量寄存器,32*64bit register file,自己的流水线执行单元。这些 SIMD 的扩展被称为 NEON。NEON


在 32-bit 内核的处理器上,如 Cortex-A 系列,如果不采用 SIMD 则会将大量时间花费在处理 8-bit 或 16-bit 的数据上,但是处理器本身的 ALU、寄存器、数据深度又是主要为了 32-bit 的运算而设计的。因此 NEON 应运而生。


NEON 就是一种基于 SIMD 思想的 ARM 技术,相比于 ARMv6 或之前的架构,NEON 结合了 64-bit 和 128-bit 的 SIMD 指令集,提供 128-bit 宽的向量运算(vector operations)。


ARM NEON 技术本质上是一种高级的单指令多数据(SIMD)架构扩展,这种扩展仅在 ARM Cortex-A 和 Cortex-R 系列处理器中使用。ARM NEON 单元默认包含在 Cortex-A7 和 Cortex-A15 处理器中,但在其他 ARMv7 Cortex-A 系列处理器中是可选的,某些实现 ARMv7–A 或 ARMv7–R 架构配置文件的 Cortex-A 系列处理器可能不包含 NEON 单元。

NEON 演进史

NEON 技术是依靠向量指令来加速计算,而鉴于 NEON 技术比 VFP(vector-floating-point)提供的向量技术加速效果体验更优秀,从 ARMv7 架构开始使用 VFP 向量指令加速的模式被弃用。


在 ARMv7 中,NEON 与 VFP 指令集具有以下关系:


  • 具有 NEON 单元但没有 VFP 单元的处理器无法在硬件中执行浮点运算。

  • 由于 NEON SIMD 操作更有效地执行向量计算,因此从 ARMv7 的引入开始,VFP 单元中的向量模式操作已被弃用。因此,VFP 单元有时也称为浮点单元(FPU)。

  • VFP 可以提供完全兼容 IEEE-754 的浮点运算,ARMv7 NEON 单元中的单精度运算不完全符合 IEEE-754

  • NEON 不能取代 VFP。VFP 提供了一些在 NEON 指令集中没有等效实现的专用指令。

  • 半精度指令仅适用于包含半精度扩展的 NEON 和 VFP 系统。

  • 在 ARMv8 中,VFP 已被 NEON 取代,以上问题如 NEON 并不完全符合 IEEE 754 标准,并且有一些指令 VFP 支持而 NEON 不支持的问题已在 ARMv8 中得到解决。


再加上 NEON 本身也仅在部分处理器上才支持,所以必须首先确认处理器是否支持 NEON 和 VFP。可以在编译和运行的时候进行检查。需要注意的是 neon 可以和 vfp 同时使用,但由于寄存器是公用的。 ARMv7 有 32 个 NEON D 寄存器,如下图所示

编译/运行时检查

编译期可在 ARM 编译器工具链(armcc)v4.0 及更高版本或 GCC 中,检查预定义宏  ARM_NEON 或者  __arm_neon 是否开启。


运行时检测 NEON 单元需要依赖操作系统的能力,由于 /proc/cpuinfo 输出是基于文本的,因此通常首选查看辅助向量 /proc/self/auxv,其包含二进制格式的内核 hwcap,可以轻松地在 /proc/self/auxv 文件中搜索 AT_HWCAP 记录,以检查 HWCAP_NEON 位(4096)。

NEON 架构

熟悉 ARMv7-A 架构的应该知道 ARMv7 架构的内核是一个 32 位的系统,使用 32 位的寄存器。但是 NEON 单元使用的是 64 位或者 128 位的寄存器。这里的原因就是 NEON 单元使用独立的寄存器文件。不过,NEON 单元还是完全集成到处理器中的,可以和处理器共享整型操作单元、循环控制和缓存资源,相比于使用硬件加速器,大大降低了面积和功耗成本。而且由于 NEON 单元和应用程序使用相同的地址空间,可以使用更简单的编程模型。


ARM NEON 技术的核心是 NEON 单元,主要由四个模块组成,分别是 NEON 寄存器文件、整型执行流水线、单精度浮点执行流水线和数据加载和重排流水线。


The components of the unit are:


  • Neon register file

  • Neon integer execute pipeline

  • Neon single-precision floating-point execute pipeline

  • Neon load/store and permute pipeline

NEON 寄存器

NEON 寄存器主要是用来存放包含相同数据类型元素的向量。在 ARMv7 架构中, 一共有 16 个 128 位寄存器,这个 128 位寄存器也称之为 Q 寄存器,一个 128 位寄存器又可以分为两个 64 位寄存器,即一共有 32 个 64 位寄存器,64 位寄存器又称之为 D 寄存器。在 ARMv8 架构中寄存器的数量相比 ARMv7 架构数量翻倍。Q 寄存器和 D 寄存器对应表如下所示:


注:每一个 Q0-Q15 寄存器映射到一对 D 寄存器。


寄存器之间的映射关系:


  • D<2n> 映射到 Q 的最低有效半部;

  • D<2n+1> 映射到 Q 的最高有效半部;


结合 NEON 支持的数据类型,NEON 寄存器有如下图的几种形态:



NEON 指令执行



上图为 NEON 单元完成加速计算的流程图。其中向量寄存器中的每个元素同步执行计算,以此来加速计算过程。

NEON 指令类型

NEON 指令按照操作数类型可以分为正常指令、宽指令、窄指令、饱和指令、长指令。


  • 正常指令:生成大小相同且类型通常与操作数向量相同到结果向量。

  • 长指令:对双字向量操作数执行运算,生成四字向量结果。所生成的元素一般是操作数元素宽度到两倍,并属于同一类型。用 L 标记,如 VMOVL。

  • 宽指令:一个双字向量操作数和一个四字向量操作数执行运算,生成四字向量结果。用 W 标记,如 VADDW。

  • 窄指令:四字向量操作数执行运算,并生成双字向量结果,所生成的元素一般是操作数元素宽度的一半。用 N 标记,如 VMOVN。

  • 饱和指令:当超过数据类型指定的范围则自动限制在该范围内。用 Q 标记,如 VQSHRUN

NEON 指令调用

ARM 平台提供了四种使用 NEON 技术的方式,分别为 NEON 内嵌函数、NEON 开源库、编译器自动向量化和 NEON 汇编。


NEON 内嵌函数


NEON 内嵌 函数提供了一种编写 NEON 代码的方法,该方法比汇编代码更易于维护,同时仍然可以控制生成的 NEON 指令。


内部函数使用与 D 和 Q NEON 寄存器对应的新数据类型。数据类型支持创建直接映射到 NEON 寄存器的 C 变量。


NEON 内嵌函数调用类似于普通函数调用,通过调用函数接口告知编译器需要优化的代码,编译器在编译阶段直接使用 NEON 指令替换这些内嵌函数而不是执行类似子函数调用的操作。NEON 内嵌函数提供了一种低级的 NEON 指令访问方式,编译器做了一些通常与编写汇编语言相关的繁重工作来达到获取最高性能的目标,例如:


  • 寄存器分配

  • 代码调度或重新排序指令


NEON 内嵌函数的缺点在于无法让编译器准确输出想要的代码,因此在转向 NEON 汇编代码时仍有一些改进的可能性。


自动矢量化


向量化编译器可以将 C 或 C++源代码进行矢量化,以实现对 NEON 硬件的有效使用。这意味着尽管开发者开发可移植的 C 或 C++源码,也可能通过矢量编译器的自动向量化功能享受到 NEON 指令带来的性能提升。GCC 和 ARM 编译器均能通过配置编译选项开启自动向量化,从而使用 NEON 技术优化代码。如果编译器能够确定开发者的意图,矢量化编译器可以以最优的方式优化代码。相较于针对某一特定处理器高度调整的代码,易于人们理解的简单代码更容易向量化。


NEON 开源库


鉴于 NEON 指令的强大优化效果,市场上出现了很多支持 NEON 优化的开源库,比如 Ne10、OpenMAX、ffmpeg、Eigen3 和 Math-neon 等


NEON 汇编


对于性能要求特别高的程序,手工编写汇编代码是更适合的方式。


GNU 汇编器(gas) 和 ARM Compile r 工具链汇编器(armasm)都支持 NEON 指令的汇编。

其他平台上的 SIMD 技术

SIMD 处理不是 ARM 独有的,下图将其与 x86 和 Altivec 进行了比较。


专用 DSP 对比

许多基于 ARM 的 SOC 中还包含 DSP 等协处理硬件,因此可以同时包含 NEON 单元和 DSP。相对于 DSP,NEON 的特点有


  • 扩展了 ARM 处理器流水线

  • 使用 ARM 内核寄存器进行内存寻址- 简易的开发和调试

  • SMP 能力。MPCore 处理器中的每个 ARM 内核都有一个 NEON 单元。

  • 开源社区和 ARM 生态系统都提供了广泛的 NEON 工具支持


DSP 特点


  • 与 ARM 处理器并行运行

  • 与 ARM 处理器集成度较低。在 DSP 和 ARM 处理器之间传输数据可能会有一些缓存清理或刷新开销。

总结

本文主要介绍了 NEON 的基本原理、寄存器、指令调用等基础知识,但 NEON 技术所能探讨的内容远不止于此,后续也将会更深入的研究。欢迎转发、关注、收藏。

微信公众号首发,欢迎关注、转发、收藏,感谢支持。

发布于: 刚刚阅读数: 3
用户头像

江湖修行

关注

还未添加个人签名 2021-12-05 加入

还未添加个人简介

评论

发布
暂无评论
大前端CPU优化技术--NEON技术_性能优化_江湖修行_InfoQ写作社区