CPU 기능 다루기

ABI: 전처리기의 사전 정의된 매크로 사용

대개 다음과 함께 #ifdef를 사용하여 빌드 시 ABI를 결정하는 것이 가장 편리합니다.

  • __arm__: 32비트 ARM의 경우
  • __aarch64__: 64비트 ARM의 경우
  • __i386__: 32비트 X86의 경우
  • __x86_64__: 64비트 X86의 경우

32비트 X86은 __x86__일 것으로 생각할 수 있지만 __i386__입니다.

CPU 코어 수: libc의 sysconf(3) 사용

sysconf(3)를 사용하면 _SC_NPROCESSORS_CONF(시스템 내 CPU 코어의 수) 및 _SC_NPROCESSORS_ONLN(현재 온라인 상태인 CPU 코어의 수)을 모두 쿼리할 수 있습니다.

기능: libc의 getauxval(3) 사용

API 수준 18부터는 Android의 C 라이브러리에서 getauxval(3)을 사용할 수 있습니다. AT_HWCAPAT_HWCAP2 인수는 CPU별 기능을 목록으로 나열하는 비트마스크를 반환합니다. 비교할 만한 상수(예: arm64의 SHA512 명령의 경우 HWCAP_SHA512 또는 arm의 Thumb 정수 나눗셈 명령의 경우 HWCAP_IDIVT)는 NDK의 다양한 hwcap.h 헤더를 참조하세요.

Google cpu_features 라이브러리

AT_HWCAP에는 한 가지 문제가 있는데, 기기를 잘못 인식할 때가 있다는 것입니다. 예를 들어 일부 구형 기기의 경우 정수 나눗셈 명령이 있다고 하지만 사실은 없습니다.

Google의 cpu_features 라이브러리는 특정 SoC의 자체 지식(/proc/cpuinfo를 파싱하여 문제의 특정 SoC 해결)을 적용하여 이러한 문제를 해결합니다.

다른 해결 방법은 SIGILL의 신호 핸들러를 설치하고 문제의 명령을 실행해 보는 것입니다. 예를 들어 BoringSSL/OpenSSL에서 이 기술을 사용합니다.

NDK cpufeatures 라이브러리

NDK는 cpufeatures라는 작은 라이브러리를 제공합니다. 이 라이브러리는 getauxval(3)과 비슷한 기능을 제공하지만 API 수준 18 미만에서도 작동합니다. 다른 cpu_features 라이브러리와 달리 이 라이브러리에는 특정 SoC에 대한 추가 지식이 없습니다.

NDK cpufeatures API

uint64_t android_getCpuFeatures();
    

비트 플래그를 반환하며, 각 플래그는 하나의 CPU 제품군별 기능을 나타냅니다. 이 섹션의 나머지 부분에서는 각 제품군의 기능을 설명합니다.

32비트 ARM CPU 제품군

32비트 ARM CPU 제품군에서 다음 플래그를 사용할 수 있습니다.

ANDROID_CPU_ARM_FEATURE_VFPv2
기기의 CPU에서 VFPv2 명령 집합을 지원함을 나타냅니다. 대부분의 ARMv6 CPU에서는 이 명령 집합을 지원합니다.
ANDROID_CPU_ARM_FEATURE_ARMv7
기기의 CPU가 armeabi-v7a ABI에서 지원하는 ARMv7-A 명령 집합을 지원함을 나타냅니다. 이 명령 집합은 Thumb-2와 VFPv3-D16 명령을 모두 지원합니다. 이 반환 값은 VFPv3 하드웨어 FPU 명령 집합 확장을 지원함을 나타내기도 합니다.
ANDROID_CPU_ARM_FEATURE_VFPv3
기기의 CPU에서 VFPv3 하드웨어 FPU 명령 집합 확장을 지원함을 나타냅니다.

이 값은 16개의 하드웨어 배정밀도 FP 레지스터만 제공하는 VFPv3-D16 명령 집합과 같은 것입니다.

ANDROID_CPU_ARM_FEATURE_VFP_D32
기기의 CPU에서 16개가 아니라 32개의 하드웨어 배정밀도 FP 레지스터를 지원함을 나타냅니다. 32개의 하드웨어 배정밀도 FP 레지스터가 있더라도, 같은 레지스터 뱅크에 매핑되는 단정밀도 레지스터는 여전히 32개뿐입니다.
ANDROID_CPU_ARM_FEATURE_NEON
기기의 CPU에서 ARM Advanced SIMD(NEON) 벡터 명령 집합 확장을 지원함을 나타냅니다. ARM은 이와 같은 CPU가 32개의 하드웨어 FP 레지스터(NEON 장치와 공유됨)를 제공하는 VFPv3-D32도 구현하도록 합니다.
ANDROID_CPU_ARM_FEATURE_VFP_FP16
기기의 CPU가 16비트 레지스터에서 부동 소수점 연산을 수행하는 명령을 지원함을 나타냅니다. 이 기능은 VFPv4 사양에 포함됩니다.
ANDROID_CPU_ARM_FEATURE_VFP_FMA
기기의 CPU에서 VFP 명령 집합의 FMA(Fused Multiply-Accumulate, 승산-누산 결합) 확장을 지원함을 나타냅니다. VFPv4 사양에도 포함됩니다.
ANDROID_CPU_ARM_FEATURE_NEON_FMA
기기의 CPU에서 NEON 명령 집합의 FMA(Fused Multiply-Accumulate, 승산-누산 결합) 확장을 지원함을 나타냅니다. VFPv4 사양에도 포함됩니다.
ANDROID_CPU_ARM_FEATURE_IDIV_ARM
기기의 CPU가 ARM 모드에서 정수 나눗셈을 지원함을 나타냅니다. Cortex-A15와 같은 최신 모델 CPU에서만 지원됩니다.
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2
기기의 CPU가 Thumb-2 모드에서 정수 나눗셈을 지원함을 나타냅니다. Cortex-A15와 같은 최신 모델 CPU에서만 지원됩니다
ANDROID_CPU_ARM_FEATURE_iWMMXt
기기의 CPU에서 MMX 레지스터와 명령을 추가하는 명령 집합 확장을 지원함을 나타냅니다. 이 기능은 몇몇 XScale 기반 CPU에서만 지원됩니다.
ANDROID_CPU_ARM_FEATURE_LDREX_STREX
기기의 CPU에서 ARMv6 이후 사용 가능한 LDREX 및 STREX 명령을 지원함을 나타냅니다. 이와 함께, 이러한 명령은 전용 모니터의 지원으로 메모리에서 원자성 업데이트를 제공합니다.

64비트 ARM CPU 제품군

64비트 ARM CPU 제품군에서 다음 플래그를 사용할 수 있습니다.

ANDROID_CPU_ARM64_FEATURE_FP
기기의 CPU에 부동 소수점 유닛(FPU)이 있음을 나타냅니다. 모든 Android ARM64 기기에서는 이 기능을 지원해야 합니다.
ANDROID_CPU_ARM64_FEATURE_ASIMD
기기의 CPU에 Advanced SIMD(ASIMD) 유닛이 있음을 나타냅니다. 모든 Android ARM64 기기에서는 이 기능을 지원해야 합니다.
ANDROID_CPU_ARM64_FEATURE_AES
기기의 CPU에서 AES 명령을 지원함을 나타냅니다.
ANDROID_CPU_ARM64_FEATURE_CRC32
기기의 CPU에서 CRC32 명령을 지원함을 나타냅니다.
ANDROID_CPU_ARM64_FEATURE_SHA1
기기의 CPU에서 SHA1 명령을 지원함을 나타냅니다.
ANDROID_CPU_ARM64_FEATURE_SHA2
기기의 CPU에서 SHA2 명령을 지원함을 나타냅니다.
ANDROID_CPU_ARM64_FEATURE_PMULL
기기의 CPU에서 64비트 PMULLPMULL2 명령을 지원함을 나타냅니다.

32비트 x86 CPU 제품군

32비트 x86 CPU 제품군에서 다음 플래그를 사용할 수 있습니다.

ANDROID_CPU_X86_FEATURE_SSSE3
기기의 CPU에서 SSSE3 명령 확장 집합을 지원함을 나타냅니다.
ANDROID_CPU_X86_FEATURE_POPCNT
기기의 CPU에서 POPCNT 명령을 지원함을 나타냅니다.
ANDROID_CPU_X86_FEATURE_MOVBE
기기의 CPU에서 MOVBE 명령을 지원함을 나타냅니다. 이 명령은 Atom과 같은 일부 Intel IA-32 CPU에만 적용됩니다.

목록에 있는 확장 기능이 없는 CPU 제품군의 경우 android_getCpuFeatures()에서 0을 반환합니다.

int android_getCpuCount(void);
    

시스템 내 CPU 코어의 수를 반환합니다. 이 수는 실제 온라인 상태인 코어 수보다 많을 수 있습니다.

AndroidCpuFamily android_getCpuFamily();
    

기기에서 지원하는 CPU 제품군/아키텍처를 나타내는 다음 상수 중 하나를 반환합니다.

  • ANDROID_CPU_FAMILY_ARM
  • ANDROID_CPU_FAMILY_X86
  • ANDROID_CPU_FAMILY_ARM64
  • ANDROID_CPU_FAMILY_X86_64

64비트 시스템에 있는 32비트 실행 파일의 경우 이 함수는 32비트 아키텍처를 반환합니다.

ndk-build로 NDK cpufeatures 사용

cpufeatures 라이브러리는 가져오기 모듈로 사용할 수 있습니다. 사용하려면 다음을 수행합니다.

  • LOCAL_STATIC_LIBRARIEScpufeatures를 추가합니다.

  • 소스 코드에 #include <cpu-features.h>를 포함합니다.

  • Android.mk 끝에서 android/cpufeatures를 가져옵니다.

다음은 cpufeatures를 가져오는 Android.mk의 예입니다.

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)