android - 为多种架构生成优化的 NDK 代码?

标签 android c gcc java-native-interface android-ndk

我有一些用于 Android 的 C 代码,可以进行大量低级数字运算。我想知道我应该使用哪些设置(例如,对于我的 Android.mk 和 Application.mk)文件,以便生成的代码可以在所有当前的 Android 设备上运行,而且还可以利用针对特定芯片组的优化。我正在寻找好的默认 Android.mk 和 Application.mk 设置来使用,我想避免在我的 C 代码中乱扔#ifdef 分支。

例如,我知道 ARMv7 具有浮点指令,并且一些 ARMv7 芯片支持 NEON 指令,而默认的 ARM 不支持这些指令。是否可以设置标志以便我可以使用 NEON 构建 ARMv7、没有 NEON 的 ARMv7 和默认的 ARM 构建?我知道如何做后两个,但不是全部 3。我对我使用的设置持谨慎态度,因为我认为当前的默认设置是最安全的设置以及其他选项有什么风险。

对于 GCC 特定的优化,我使用以下标志:

LOCAL_CFLAGS=-ffast-math -O3 -funroll-loops

我已经检查了所有这 3 个加速我的代码。还有其他常见的我可以添加吗?

我的另一个技巧是在 Android.mk 中添加“LOCAL_ARM_MODE := arm”,以加快较新的 arm 芯片的速度(尽管我对这到底是做什么以及在旧芯片上会发生什么感到困惑)。

最佳答案

ARM 处理器有 2 个它们支持的通用指令集:“ARM”和“Thumb”。尽管两者都有不同的风格,但 ARM 指令是 32 位的,而 Thumb 指令是 16 位的。两者的主要区别在于 ARM 指令在一条指令中可以做的事情比 Thumb 做的更多。例如,一条 ARM 指令可以将一个寄存器添加到另一个寄存器,同时对第二个寄存器执行左移。在 Thumb 中,一条指令必须进行移位,然后第二条指令将进行加法。

ARM 指令没有两倍好,但在某些情况下它们可以更快。在手卷 ARM 组件中尤其如此,可以以新颖的方式对其进行调整,以充分利用“免费换类”。拇指指令有其自身的优势和大小:它们消耗的电池更少。

无论如何,这就是 LOCAL_ARM_MODE 所做的 - 这意味着您将代码编译为 ARM 指令而不是 Thumb 指令。编译到 Thumb 是 NDK 中的默认设置,因为它倾向于创建更小的二进制文件,并且对于大多数代码来说速度差异并不明显。编译器不能总是利用 ARM 可以提供的额外“魅力”,因此无论如何您最终都需要或多或少相同数量的指令。

您从编译到 ARM 或 Thumb 的 C/C++ 代码中看到的结果将是相同的(除了 compiler bugs )。

这本身就兼容当今可用的所有 Android 手机的新旧 ARM 处理器。这是因为默认情况下,NDK 编译为支持 ARMv5TE 指令集的基于 ARM 的 CPU 的“应用程序二进制接口(interface)”。这个 ABI 被称为“armeabi”,可以通过输入 APP_ABI := armeabi 在 Application.mk 中显式设置。 .

较新的处理器还支持称为 armeabi-v7a 的 Android 特定 ABI ,它扩展了 armeabi 以添加 Thumb-2 instruction set以及称为 VFPv3-D16 的硬件浮点指令集。 armeabi-v7a 兼容的 CPU 还可以选择支持 NEON 指令集,您必须在运行时检查它并提供代码路径,以确定它何时可用,何时不可用。 NDK/samples 目录中有一个执行此操作的示例(hello-neon)。在引擎盖下,Thumb-2 更“类似于 ARM”,因为它的指令可以在一条指令中执行更多操作,同时还具有占用更少空间的优势。

为了编译包含 armeabi 和 armeabi-v7a 库的“胖二进制文件”,您需要在 Application.mk 中添加以下内容:

APP_ABI := armeabi armeabi-v7a

安装 .apk 文件后,Android 包管理器会为设备安装最佳库。因此,在较旧的平台上,它将安装 armeabi 库,在较新的设备上安装 armeabi-v7a 库。

如果你想在运行时测试 CPU 特性,那么你可以使用 NDK 函数 uint64_t android_getCpuFeatures()获得处理器支持的功能。这将返回 ANDROID_CPU_ARM_FEATURE_ARMv7 的位标志在 v7a 处理器上,ANDROID_CPU_ARM_FEATURE_VFPv3如果支持硬件浮点和ANDROID_CPU_ARM_FEATURE_NEON如果支持高级 SIMD 指令。如果没有 VFPv3,ARM 就无法拥有 NEON。

总之:默认情况下,您的程序是最兼容的。由于使用 ARM 指令,使用 LOCAL_ARM_MODE 可能会以牺牲电池生命周期为代价使事情变得稍微快一些 - 它与默认设置一样兼容。通过添加 APP_ABI := armeabi armeabi-v7a行,您将在较新的设备上提高性能,与旧设备保持兼容,但您的 .apk 文件会更大(由于有 2 个库)。为了使用 NEON 指令,您需要编写在运行时检测 CPU 功能的特殊代码,这仅适用于可以运行 armeabi-v7a 的较新设备。

关于android - 为多种架构生成优化的 NDK 代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5089783/

相关文章:

c - 使用 dlsym() 在静态链接库中查找变量

c - 这解析为什么?

android - React Native Image 不显示,我该如何解决?

android - 在 Google Play 应用内结算中消费已取消的购买

android canvas onDraw 计时

c - 从 C# 的背景学习 C

android - 如何将 SQLite 数据库大小限制为 2MB

C 查找某个单词的所有实例

c - C 程序中使用的适当数据类型

c++ - libuvc 程序无法编译