Creating optimized NDK code for multiple architectures?

I have a C code for Android that does a lot of low level crunching. I would like to know what settings I should use (for example, for my Android.mk and Application.mk), so that the generated code runs on all modern Android devices, but also uses optimization for certain chipsets. I'm looking for good default settings for Android.mk and Application.mk, and I want to not clutter my C code with #ifdef branches.

For example, I know that ARMv7 has floating point instructions, and some ARMv7 chips support NEON instructions, and that ARM does not support any of them by default. Is it possible to set flags so that I can build ARMv7 using NEON, ARMv7 without NEON and the default ARM build by default? I know how to do the last two, but not all. 3. I am careful about what settings I use, since I assume that the current default values โ€‹โ€‹are the safest settings and what risks other options may have.

For special GCC optimization, I use the following flags:

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

I checked all 3 of these speeds of my code. Are there any other common ones that I could add?

Another tip: add LOCAL_ARM_MODE: = arm to Android.mk to speed up work with new chips (although I'm confused exactly what this does and what happens on old chips).

+53
c gcc android android-ndk jni
Feb 23 '11 at 10:41
source share
2 answers

ARM processors have 2 common instruction sets that they support: "ARM" and "Thumb". Although there are different variations of both, ARM instructions have 32 bits and Thumb instructions have 16 bits. The main difference between the two is that ARM instructions have the ability to do more in one instruction than Thumb. For example, one ARM command can add one register to another register, performing a left shift in the second register. In Thumb, one instruction would have to make a shift, then the second instruction would make an addition.

ARM instructions are not so good, but in some cases they can be faster. This is especially true for manual ARM assembly, which can be tuned to new ways to make the best use of "free shifts." Thumb instructions have their advantages as well as their size: they drain the battery less.

In any case, this is what LOCAL_ARM_MODE does - this means that you are compiling your code as ARM instructions instead of Thumb instructions. Compilation in Thumb is the default in the NDK, since it tends to create a smaller binary, and the speed difference is not noticeable for most codes. The compiler may not always be able to take advantage of the extra โ€œoomphโ€ that ARM can provide, so you will ultimately need more or less the same number of instructions.

The result of what you see from C / C ++ code compiled in ARM or Thumb will be identical (no compiler errors ).

This in itself is compatible between the new and old ARM processors for all the Android phones available today. This is because by default the NDK is compiled into the "Application Binary Interface" for ARM-based processors that support the ARMv5TE instruction set. This ABI is known as "armeabi" and can be explicitly installed in Application.mk by putting APP_ABI := armeabi .

The new processors also support the Android-specific ABI, known as armeabi-v7a , which extends armeabi to add a Thumb-2 instruction set and a hardware floating-point instruction set called VFPv3-D16. Armeabi-v7a compatible processors can also support a set of NEON instructions that you must check at runtime and provide code codes when they are available and when not. Here is an example in the NDK / samples directory that does this (hi-neon). Under the hood, the Thumb-2 is more โ€œARM-likeโ€ because its teams can execute more than one command, with the advantage that it still takes up less space.

To compile a bold binary file containing the armeabi and armeabi-v7a libraries, you must add the following to Application.mk:

 APP_ABI := armeabi armeabi-v7a 

When the .apk file is installed, the Android package manager installs the best library for the device. Therefore, he installed the armeabi library on older platforms, and armeabi-v7a on newer devices.

If you want to test the CPU functions at run time, you can use the NDK uint64_t android_getCpuFeatures() function to get the functions supported by the processor. This returns the ANDROID_CPU_ARM_FEATURE_ARMv7 bit on v7a, ANDROID_CPU_ARM_FEATURE_VFPv3 processors if hardware floating points are ANDROID_CPU_ARM_FEATURE_NEON , and ANDROID_CPU_ARM_FEATURE_NEON if extended SIMD instructions are supported. ARM cannot have NEON without VFPv3.

In short: by default, your programs are most compatible. Using LOCAL_ARM_MODE can do something a little faster due to battery life due to the use of ARM instructions - and it is compatible with the default setting. Adding the line APP_ABI := armeabi armeabi-v7a , you will get improved performance on new devices, remain compatible with the old ones, but your .apk file will be larger (due to the presence of 2 libraries). To use NEON instructions, you will need to write special code that detects processor capabilities at runtime, and this only applies to newer devices that can run armeabi-v7a.

+112
Feb 23 '11 at 15:39
source share

Great answer, just add you should use

 APP_ABI := all 

this will compile 4 binaries, armv5, armv7, x86 and mips

you may need a new version of ndk

+23
Feb 25 2018-12-12T00:
source share



All Articles