Android NDK开发详解之架构和 CPU中的Neon 支持
- 构建
- 全局启用 Neon
- 为每个模块启用 Neon
- 为每个源文件启用 Neon
- 对 x86 提供跨平台支持
- 示例代码
使用原生代码时,硬件很重要。NDK 提供各种 ABI 供您选择,可让您确保针对正确的架构和 CPU 进行编译。
本部分介绍了在构建时如何面向特定的架构和 CPU,如何使用 ARM Neon 扩展指令集,以及在运行时如何使用 CPU 功能库查询可选功能。
NDK 支持 ARM 高级 SIMD(通常称为 Neon),一种适用于 ARMv7 和 ARMv8 的可选扩展指令集。Neon 提供标量/矢量指令和寄存器(与 FPU 共享),与 x86 中的 MMX/SSE/3DNow! 类似。
几乎所有基于 ARMv7 的 Android 设备都支持 Neon,包括搭载 API 级别 21 或更高级别的所有设备。NDK 默认启用 Neon。
所有基于 ARMv8 的 Android 设备都支持 Neon。
NDK 支持模块编译,甚至可以编译支持 Neon 的特定源文件。您可以在 C 和 C++ 代码中使用 Neon 内建函数来充分利用高级 SIMD 扩展指令集。针对 Armv8-A 的 Neon 程序员指南详细介绍了 Neon 内建函数和 Neon 编程的概况。
构建
注意:对于 NDK r21 及更高版本,默认情况下,系统会为所有 API 级别启用 Neon。如果您需要停用 Neon 以支持非 Neon 设备(很少见),请用相反的值完成下述设置。另外,对于不支持 Neon 的 CPU,可使用 Play 商店管理中心来排除相应 CPU,以防您的应用安装到这些设备上。
全局启用 Neon
ndk-build
ndk-build 不支持全局启用 Neon。要为整个 ndk-build 应用启用 Neon,请对应用中的每个模块逐一执行启用步骤。
CMake
调用 CMake 时传递 -DANDROID_ARM_NEON=ON。如果使用 Android Studio/Gradle 进行构建,请在 build.gradle 中设置以下选项:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_ARM_NEON=ON"
}
}
}
}
为每个模块启用 Neon
ndk-build
要使用 NEON 在 ndk-build 模块中构建所有源文件,请将以下内容添加到 Android.mk 的模块定义中:
LOCAL_ARM_NEON := true
CMake
要使用 NEON 在 CMake 目标中构建所有源文件,请将以下内容添加到 CMakeLists.txt 中:
if(ANDROID_ABI STREQUAL armeabi-v7a)
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS -mfpu=neon)
endif()
其中 ${TARGET} 替换为您的库名称。
如果您要构建仅包含 Neon 代码的静态库或共享库,那么构建支持 Neon 的所有源文件将十分有用。
为每个源文件启用 Neon
ndk-build
为 LOCAL_SRC_FILES 变量列出源文件时,可以选择使用 .neon 后缀表示要构建支持 Neon 的单个文件。例如,以下示例会构建一个支持 Neon 的文件 (foo.c),以及另一个不支持 Neon 的文件 (bar.c):
LOCAL_SRC_FILES := foo.c.neon bar.c
您可结合使用 .neon 后缀与 .arm 后缀,后者指定用于非 Neon 指令的 32 位 ARM 指令集(而非 Thumb2)。在这种情况下,.arm 必须在 .neon 之前。例如:foo.c.arm.neon 可行,但 foo.c.neon.arm 不可行。
CMake
要使用 Neon 构建特定的源文件,请将以下内容添加到 CMakeLists.txt 中:
if(ANDROID_ABI STREQUAL armeabi-v7a)
set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -mfpu=neon)
endif()
运行时检测
几乎所有基于 ARMv7 的 Android 设备都支持 Neon,包括搭载 API 级别 21 或更高级别的所有设备。NDK 默认启用 Neon。为实现最大兼容性,32 位代码可执行运行时检测,以确认 Neon 代码能够在目标设备上运行。应用可以使用 CPU 功能中提及的任一选项执行此检查。
另外,您也可以在 Google Play 管理中心中过滤掉不兼容的设备。还可以使用管理中心查看这会影响到多少设备。
对 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:自动移植解决方案、提示与技巧)。
示例代码
hello-neon 示例举例说明了如何同时使用 cpufeatures 库和 Neon 内建函数。此示例实现了 C 版本的微小 FIR 过滤器循环基准,并针对支持 Neon 的设备实现了经 Neon 优化的基准。