Building Android NDK applications for different CPU features

Many projects use native code to improve performance. One advantage of developing in NDK over SDK is that we can build different packages for different CPUs, which is the topic of this recipe.

Getting ready

Please read the Building Android NDK application for different ABIs recipe before going through this one.

How to do it…

The following steps build Android NDK applications for different CPU features.

  1. At Eclipse, click on File | New | Other. Select Android Project from Existing Code under Android as shown in the following screenshot. Then click on Next:
    How to do it…
  2. Browse to the samples/hello-neon folder of the Android NDK folder. Then click on Finish.
  3. Start a terminal, then go to the samples/hello-neon/jni folder. Type the command "ndk-build" to build the binaries.
  4. Run the Android project on different devices and emulators. Based on your device/emulator ABI and availability of the NEON feature, you should be able to see the results as follows:
    • For Android device with armeabi ABI, the result is as follows:
      How to do it…
    • For Android device with armeabi-v7a ABI and NEON, the result is as follows:
    How to do it…

How it works…

Android devices are roughly divided by ABIs. However, different devices with the same ABI can have different CPU extensions and features. These extensions and features are optional and therefore we don't know whether a user's device has them until runtime. Detecting and making use of these features can sometimes improve app performance significantly on certain devices.

Android NDK contains a library named cpufeatures, which can be used to detect the CPU family and optional features at runtime. As illustrated in the sample code, the following steps indicate how to use this library:

  1. Add it in the static library list in Android.mk as follows:
    LOCAL_STATIC_LIBRARIES := cpufeatures
  2. At the end of the Android.mk file, import the cpufeatures module:
    $(call import-module,cpufeatures)
  3. In the code, include the header file <cpu-features.h>.
  4. Call detection functions; Currently cpufeatures provides only three functions:
  5. Get the CPU family. The function prototype is as follows:
    AndroidCpuFamily   android_getCpuFamily(); 

    It returns an enum. The supported CPU families are listed in the section to follow.

    ANDROID_CPU_FAMILY_MIPS 
    ANDROID_CPU_FAMILY_MIPS 
    ANDROID_CPU_FAMILY_ARM 
  6. Get the optional CPU features. Each CPU feature is represented by a bit flag and the bit is set to 1 if the feature is available. The function prototype is as follows:
    uint64_t   android_getCpuFeatures();

For the ARM CPU family, the supported CPU feature detections are as follows:

  • ANDROID_CPU_ARM_FEATURE_ARMv7: It means that the ARMv7-a instruction is supported.
  • ANDROID_CPU_ARM_FEATURE_VFPv3: It means that the VFPv3 hardware FPU instruction set extension is supported. Note that this refers to VFPv3-D16, which provides 16 hardware FP registers.
  • ANDROID_CPU_ARM_FEATURE_NEON: It means that he ARM Advanced SIMD (also known as NEON) vector instruction set extension is supported. Note that such CPUs also support VFPv3-D32, which provides 32 hardware FP registers.

For the x86 CPU family, the supported CPU feature detections are as follows:

  • ANDROID_CPU_X86_FEATURE_SSSE3: It means that the SSSE3 instruction extension set is supported.
  • ANDROID_CPU_X86_FEATURE_POPCNT: It means that the POPCNT instruction is supported.
  • ANDROID_CPU_X86_FEATURE_MOVBE: It means that the MOVBE instruction is supported.

We can do a "&" operation to detect if a feature is available or not, as follows:

uint64_t features = android_getCpuFeatures();
if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {
  //NEON is not available
} else {
  //NEON is available
}

Get the number of CPU cores on the device:

int         android_getCpuCount(void);

Tip

Since NDK r8c, more CPU feature detections are available. Please refer to sources/android/cpufeatures/cpu-features.c for more details.

There's more…

There are a few more noteworthy points about CPU features on Android.

More about CPU feature detection

The cpufeatures library can only detect a limited set of CPU features. It is possible to implement our own CPU detection mechanisms. By looking at the NDK source code at /sources/android/cpufeatures/, one can find that the cpufeatures library essentially looks at the /proc/cpuinfo file. We can read this file and parse the content in our application. The following is a screenshot of the file content:

More about CPU feature detection

Please refer to the Android project cpuinfo, available in the book's website for how to do this programmatically.

Different approaches of building for different cpu features

There are a few approaches to building native code for different CPU features:

  • Single library, different binaries at build time: This is demonstrated in the sample project. The helloneon-intrinsics.c file is only compiled for armeabi-v7a ABI.
  • Single library, different execution paths at runtime: This is also shown in the sample project. The code detects whether the NEON feature is available or not at runtime and executes different code blocks.
  • Different libraries, load appropriate library at runtime: Sometimes, we may want to compile the source code into different libraries and differentiate them by names. For example, we may have libmylib-neon.so and libmylib-vfpv3.so . We detect the CPU feature at runtime and load the appropriate library.
  • Different packages, load appropriate library at runtime: If the library is big, it is desirable to deploy different binaries for different CPUs as separate packages. This is done by many video players available on Google Play (for example, MX Player).
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset