Android Neon支持
什么是Neon?
ARM NEON是Cortex-A系列处理器的128位SIMD(单指令多数据)扩展架构,用于加速多媒体处理(如视频编解码、图像渲染)。特点有:
- 16个128位寄存器(Q0-Q15),支持整数、浮点运算
- 性能提升:视频编解码加速60%-150%,部分算法加速5-8倍
- 应用场景:Android、Ubuntu、Skia图形库等
Cortex-A系列处理器自ARMv7架构引入并在ARMv8架构中默认继承,主要服务于移动设备、智能电视等场景的多媒体处理需求。
技术规格与性能特点
NEON通过单指令并行处理多组数据,支持整数、浮点以及多项式运算,广泛应用于视频编解码、图像处理以及3D图形渲染等领域。核心特点包括:
- 寄存器结构:包含16个128位寄存器(Q0-Q15),可拆分为32个64位寄存器(D0-D31),支持8-64位整型及浮点数据类型的高效处理
- **性能提升:**实际应用中可实现视频解码性能提升60%-150%,在Skia图形库、FFmpeg等开源项目中特定算法加速达5-8倍
- **开发支持:**提供OpenMAX DL加速库、矢量化编译器与汇编接口,支持C语言内部函数、编译器自动向量化及手工汇编优化方式
由于本文主要是介绍Android中对NEON的支持,所以知道该技术是什么,能干什么,有什么特点,什么时候选择即可,如果要了解Arm技术详细细节,请参考官方文档 ArmV8 ArmV7。
实际性能表现
NEON在移动设备上的性能表现经过多项测试验证:
- 基准测试:相比ARMv5性能提升3倍,为ARMv6 SIMD性能的2倍
- 开发者实测:NEON汇编代码在RGB24到BGR24转换上比纯C语言实现快17倍
- 系统集成:被集成至Android、Ubuntu等系统的高负载场景中,显著提升多媒体处理效率
- 能效比:在移动设备上表现出优于x86平台SIMD技术的能效比,特别适合电池供电设备
与其他SIMD技术对比
| 特性 | NEON (ARM) | SSE (Intel) | AVX (Intel) |
|---|---|---|---|
| 架构 | 128位SIMD | 128/256位SIMD | 256/512位SIMD |
| 寄存器数量 | 16个128位寄存器 | 8个128位寄存器 | 16个256位寄存器 |
| 主要应用 | 移动设备多媒体 | 桌面多媒体 | 高性能计算 |
| 能效比 | 高 | 中等 | 较低 |
| 开发难度 | 中等 | 中等 | 高 |
| NEON与Intel的SSE/AVX类似,但针对ARM架构优化,在移动设备上具有更好的能效比和集成度 |
开发者与专业评价
- 生态系统:已被许多领先企业广泛采用,构成完整的NEON生态系统,包括博通、三星、TI等厂商
- 用户体验:显著增强视频播放、游戏处理、照片编辑和语音识别等多媒体体验
- 专业评测:被认为是多媒体应用领域最为优越的处理器之一,简化了软件在不同平台之间的移植
- 开发工具:为ARM开发者提供了强大的并行计算能力,可以显著提高图像处理、音频处理和信号处理等应用的性能
总结
NEON处理器在移动设备上表现出色,特别是在多媒体处理方面:
- 优势:高性能SIMD计算、优秀的能效比、完善的开发工具链
- 局限:适用场景主要限于多媒体和信号处理,通用计算能力有限
- 适用场景:视频编解码、图像处理、3D图形渲染、音频处理等多媒体应用
对于移动设备开发者,合理利用NEON技术可以显著提升应用性能,特别是在多媒体处理领域。对于普通用户,搭载NEON技术的设备能提供更流畅的多媒体体验和更长的电池续航。
Android支持
前面我们用较大的篇幅介绍了Neon是什么,能干什么,那么我们看看Android对Neon的支持。
所有机遇ARMv8(“arm64”)的Android设备都支持Neon。几乎所有基于ARMv7(“32位”)的Andorid设备都支持Neon,包括搭载API级别21或者更高级别的所有设备。NDK默认会为这两个Arm ABI启用Neon。
为了实现最大兼容性,32位代码可执行运行时检测,已确认Neon代码能够在目标设备上运行。应用可以使用CPU功能(官方介绍需要科学上网,下面会将官方介绍中的CPU功能贴上)中提及的任一选项执行此检查。
开发者不应该在C/C++代码中编写显式Neon内建函数。Clang 的可移植矢量类型(下面会有介绍)将自动使用 Neon 指令。Clang 的 Neon 内在函数实际上只是可移植类型的一个不可移植封装容器,因此编写 Neon 内在函数并不会使您的代码比使用可移植类型更快,只会降低代码的可移植性。
构建
注意:对于 NDK r21 及更高版本,默认情况下,系统会为所有 API 级别启用 Neon。如果您需要停用 Neon 以支持非 Neon 设备(很少见),请用相反的值完成下述设置。另外,对于不支持 Neon 的 CPU,可使用 Play 商店管理中心来排除相应 CPU,以防您的应用安装到这些设备上。
全局停用 Neon
要停用 NEON 在 ndk-build 模块中构建所有源文件,请将以下内容添加到 Android.mk 的模块定义中:
LOCAL_ARM_NEON := false
如需在 CMake 目标中构建所有源文件(不使用 Neon),请将以下内容添加到 CMakeLists.txt 中:
if(ANDROID_ABI STREQUAL armeabi-v7a)set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS -mfpu=vfpv3-d16)
endif()
其中 ${TARGET} 替换为您的库名称。
对 x86 提供跨平台支持
NDK 支持使用第三方 NEON_2_SSE.h 将您现有的 ARM SIMD (Neon) 内建函数跨平台编译到 x86 SSE 代码中。要详细了解此内容,请参阅 From ARM NEON to Intel SSE-the automatic porting solution, tips and tricks(从 ARM NEON 到 Intel SSE:自动移植解决方案、提示与技巧)。
示例代码
矢量化示例演示了如何使用各种矢量化工具来实现矩阵相乘,并比较了它们的性能。
Clang 的可移植矢量类型
Clang 的可移植矢量类型是Clang 编译器支持的一种跨平台 SIMD 向量类型,旨在提供与底层硬件无关的向量操作接口。以下是关键信息:
核心特性
- 自动映射到Neon 指令:在Android NDK中,Clang 的可移植矢量类型会自动使用ARM
NEON指令集优化代码,无需显式调用Neon 内在函数。 - 与GNU C SIMD 向量扩展兼容:Clang 支持匹配GNU
C的SIMD向量类型,例如通过__builtin_convertvector实现类型转换检测。
代码示例
#include <immintrin.h> // 包含SIMD头文件
using vec4f = __m128; // 定义4个float的SIMD向量类型
vec4f a = _mm_set1_ps(3.0f); // 初始化向量
vec4f b = _mm_add_ps(a, a); // 向量加法
与Neon内在函数的区别
- 可移植性:使用可移植矢量类型可避免硬编码Neon指令,提升代码跨平台兼容性。
- 性能差异:Neon内在函数可能提供更直接的硬件控制,但会牺牲可移植性。
编译器支持
- Clang 16+:支持C++20标准中的SIMD向量类型(如std::vectorizable)。
- LLVM IR:编译时会将可移植类型转换为对应目标平台的SIMD指令。
CPU功能
ABI:使用预处理器的预定义宏
通常,在构建时使用 #ifdef 及以下各项确定 ABI 最为方便:对于 32 位 ARM,使用 __arm__
对于 64 位 ARM,使用 __aarch64__
对于 32 位 X86,使用 __i386__
对于 64 位 X86,使用 __x86_64__
请注意:32 位 X86 称为 __i386__,而不是 __x86__,这可能与您预想的有所不同!CPU 核心计数:使用 libc 的 sysconf(3)
[sysconf(3)](https://man7.org/linux/man-pages/man3/sysconf.3.html) 既可以查询 _SC_NPROCESSORS_CONF(系统中的 CPU 核心数),又可以查询 _SC_NPROCESSORS_ONLN(当前可供使用的 CPU 核心数)。功能:使用 libc 的 [getauxval(3)](https://man7.org/linux/man-pages/man3/getauxval.3.html)
在 API 级别 18 及更高版本中,Android 的 C 库开始支持 getauxval(3)。AT_HWCAP 和 AT_HWCAP2 参数会返回列出特定 CPU 功能的位掩码。请参阅 NDK 中的各种 hwcap.h 头文件以获取要进行比较的常量,如用于 arm64 SHA512 指令的 HWCAP_SHA512,或用于 arm Thumb 整数除法指令的 HWCAP_IDIVT。Google cpu_features 库
AT_HWCAP 的一个问题是有时设备会出错。例如,一些旧设备宣称拥有整数除法指令,但实际上并没有。[Google 的 cpu_features](https://github.com/google/cpu_features) 库凭借其对特定 SoC 的了解(通过解析 /proc/cpuinfo 掌握相应的 SoC),解决了此类问题。维护此库是为了供 Google 的第一方应用团队使用,并且此库中包含针对这些团队实际遇到的所有问题设备的解决方法。NDK cpufeatures 库(已弃用)
NDK 仍然提供了一个名为 cpufeatures 的已废弃库,以便与已经使用此库的应用实现源代码兼容。与更新且更完善的 [
](https://github.com/google/cpu_features) 库不同,此旧库没有针对很多特定 SoC 设置权宜解决方法。
