Dealing with CPU features

ABI: using the preprocessor's pre-defined macros

It's usually most convenient to determine the ABI at build time using #ifdef in conjunction with:

  • __arm__ for 32-bit ARM
  • __aarch64__ for 64-bit ARM
  • __i386__ for 32-bit X86
  • __x86_64__ for 64-bit X86

Note that 32-bit X86 is called __i386__, not __x86__ as you might expect!

CPU core counts: using libc's sysconf(3)

sysconf(3) lets you query both _SC_NPROCESSORS_CONF (the number of CPU cores in the system) and _SC_NPROCESSORS_ONLN (the number of CPU cores currently online).

Features: using libc's getauxval(3)

From API level 18 on, getauxval(3) is available in Android's C library. The AT_HWCAP and AT_HWCAP2 arguments return bitmasks listing CPU-specific features. See the various hwcap.h headers in the NDK for the constants to compare against, such as HWCAP_SHA512 for arm64's SHA512 instructions, or HWCAP_IDIVT for arm's Thumb integer division instructions.

The Google cpu_features library

One problem with AT_HWCAP is that sometimes devices are mistaken. Some old devices, for example, claim to have integer division instructions but do not.

Google's cpu_features library works around such issues by applying its own knowledge of specific SoCs (by parsing /proc/cpuinfo to work out the specific SoC in question).

An alternative workaround is to install a signal handler for SIGILL and simply try to execute the instruction in question. BoringSSL/OpenSSL use this technique, for example.

The NDK cpufeatures library

The NDK provides a small library named cpufeatures that offers functionality similar to getauxval(3), but which also works on API levels before 18. Unlike the other cpu_features library, it does not have extra knowledge about specific SoCs.

NDK cpufeatures API

uint64_t android_getCpuFeatures();

Returns a set of bit flags, each flag representing one CPU-family-specific feature. The rest of this section provides information on features for the respective families.

32-bit ARM CPU family

The following flags are available for the 32-bit ARM CPU family:

ANDROID_CPU_ARM_FEATURE_VFPv2
Indicates that the device's CPU supports the VFPv2 instruction set. Most ARMv6 CPUs support this instruction set.
ANDROID_CPU_ARM_FEATURE_ARMv7
Indicates that the device's CPU supports the ARMv7-A instruction set as supported by the armeabi-v7a ABI. This instruction set supports both Thumb-2 and VFPv3-D16 instructions. This return value also indicates support for the VFPv3 hardware FPU instruction-set extension.
ANDROID_CPU_ARM_FEATURE_VFPv3
Indicates that the device's CPU supports the VFPv3 hardware FPU instruction-set extension.

This value is equivalent to the VFPv3-D16 instruction set, which provides provides only 16 hardware double-precision FP registers.

ANDROID_CPU_ARM_FEATURE_VFP_D32
Indicates that the device's CPU supports 32 hardware double-precision FP registers instead of 16. Even when there are 32 hardware double-precision FP registers, there are still only 32 single-precision registers mapped to the same register banks.
ANDROID_CPU_ARM_FEATURE_NEON
Indicates that the device's CPU supports the ARM Advanced SIMD (NEON) vector instruction set extension. Note that ARM mandates that such CPUs also implement VFPv3-D32, which provides 32 hardware FP registers (shared with the NEON unit).
ANDROID_CPU_ARM_FEATURE_VFP_FP16
Indicates that the device's CPU supports instructions to perform floating-point operations on 16-bit registers. This feature is part of the VFPv4 specification.
ANDROID_CPU_ARM_FEATURE_VFP_FMA
Indicates that the device's CPU supports the fused multiply-accumulate extension for the VFP instruction set. Also part of the VFPv4 specification.
ANDROID_CPU_ARM_FEATURE_NEON_FMA
Indicates that the device's CPU supports the fused multiply-accumulate extension for the NEON instruction set. Also part of the VFPv4 specification.
ANDROID_CPU_ARM_FEATURE_IDIV_ARM
Indicates that the device's CPU supports integer division in ARM mode. Only available on later- model CPUs, such as Cortex-A15.
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2
Indicates that the device's CPU supports Integer division in Thumb-2 mode. Only available on later-model CPUs, such as Cortex-A15.
ANDROID_CPU_ARM_FEATURE_iWMMXt
Indicates that the device's CPU supports an instruction-set extension that adds MMX registers and instructions. This feature is only available on a few XScale- based CPUs.
ANDROID_CPU_ARM_FEATURE_LDREX_STREX
Indicates that the device's CPU supports LDREX and STREX instructions available since ARMv6. Together, these instructions provide atomic updates on memory with the help of exclusive monitor.

64-bit ARM CPU family

The following flags are available for the 64-bit ARM CPU family:

ANDROID_CPU_ARM64_FEATURE_FP
Indicates that the device's CPU has a Floating Point Unit (FPU). All Android ARM64 devices must support this feature.
ANDROID_CPU_ARM64_FEATURE_ASIMD
Indicates that the device's CPU has an Advanced SIMD (ASIMD) unit. All Android ARM64 devices must support this feature.
ANDROID_CPU_ARM64_FEATURE_AES
Indicates that the device's CPU supports AES instructions.
ANDROID_CPU_ARM64_FEATURE_CRC32
Indicates that the device's CPU supports CRC32 instructions.
ANDROID_CPU_ARM64_FEATURE_SHA1
Indicates that the device's CPU supports SHA1 instructions.
ANDROID_CPU_ARM64_FEATURE_SHA2
Indicates that the device's CPU supports SHA2 instructions.
ANDROID_CPU_ARM64_FEATURE_PMULL
Indicates that the device's CPU supports 64-bit PMULL and PMULL2 instructions.

32-bit x86 CPU family

The following flags are available for the 32-bit x86 CPU family.

ANDROID_CPU_X86_FEATURE_SSSE3
Indicates that the device's CPU supports the SSSE3 instruction extension set.
ANDROID_CPU_X86_FEATURE_POPCNT
Indicates that the device's CPU supports the POPCNT instruction.
ANDROID_CPU_X86_FEATURE_MOVBE
Indicates that the device's CPU supports the MOVBE instruction. This instruction is specific to some Intel IA-32 CPUs, such as Atom.

android_getCpuFeatures() returns 0 for CPU families for which there are no listed extensions.

int android_getCpuCount(void);

Returns the number of CPU cores in the system, which may be higher than the number that are actually online.

AndroidCpuFamily android_getCpuFamily();

Returns one of the following constants representing the CPU family/architecture that the device supports:

  • ANDROID_CPU_FAMILY_ARM
  • ANDROID_CPU_FAMILY_X86
  • ANDROID_CPU_FAMILY_ARM64
  • ANDROID_CPU_FAMILY_X86_64

For a 32-bit executable on a 64-bit system, this function returns the 32-bit architecture.

Using NDK cpufeatures with ndk-build

The cpufeatures library is available as an import module. To use it:

  • Add cpufeatures to LOCAL_STATIC_LIBRARIES.

  • #include <cpu-features.h> in your source code.

  • Import android/cpufeatures at the end of your Android.mk.

Here is an example Android.mk that imports cpufeatures:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := your-module-name
LOCAL_SRC_FILES := ...
LOCAL_STATIC_LIBRARIES := cpufeatures
include $(BUILD_SHARED_LIBRARY)

$(call import-module,android/cpufeatures)