xref: /aosp_15_r20/external/cpu_features/ndk_compat/cpu-features.c (revision eca53ba6d2e951e174b64682eaf56a36b8204c89)
1*eca53ba6SRoland Levillain #include "cpu-features.h"
2*eca53ba6SRoland Levillain 
3*eca53ba6SRoland Levillain #include <pthread.h>
4*eca53ba6SRoland Levillain 
5*eca53ba6SRoland Levillain #include "cpu_features_macros.h"
6*eca53ba6SRoland Levillain #include "internal/filesystem.h"
7*eca53ba6SRoland Levillain #include "internal/stack_line_reader.h"
8*eca53ba6SRoland Levillain #include "internal/string_view.h"
9*eca53ba6SRoland Levillain 
10*eca53ba6SRoland Levillain #if defined(CPU_FEATURES_ARCH_ARM)
11*eca53ba6SRoland Levillain #include "cpuinfo_arm.h"
12*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_X86)
13*eca53ba6SRoland Levillain #include "cpuinfo_x86.h"
14*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_MIPS)
15*eca53ba6SRoland Levillain #include "cpuinfo_mips.h"
16*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_AARCH64)
17*eca53ba6SRoland Levillain #include "cpuinfo_aarch64.h"
18*eca53ba6SRoland Levillain #endif
19*eca53ba6SRoland Levillain 
20*eca53ba6SRoland Levillain static pthread_once_t g_once;
21*eca53ba6SRoland Levillain static int g_inited;
22*eca53ba6SRoland Levillain static uint64_t g_cpuFeatures;
23*eca53ba6SRoland Levillain static int g_cpuCount;
24*eca53ba6SRoland Levillain 
25*eca53ba6SRoland Levillain #ifdef CPU_FEATURES_ARCH_ARM
26*eca53ba6SRoland Levillain static uint32_t g_cpuIdArm;
27*eca53ba6SRoland Levillain #endif
28*eca53ba6SRoland Levillain 
set_cpu_mask_bit(uint32_t index,uint32_t * cpu_mask)29*eca53ba6SRoland Levillain static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) {
30*eca53ba6SRoland Levillain   *cpu_mask |= 1UL << index;
31*eca53ba6SRoland Levillain }
32*eca53ba6SRoland Levillain 
33*eca53ba6SRoland Levillain // Examples of valid inputs: "31", "4-31"
parse_cpu_mask(const StringView text,uint32_t * cpu_mask)34*eca53ba6SRoland Levillain static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) {
35*eca53ba6SRoland Levillain   int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-');
36*eca53ba6SRoland Levillain   if (separator_index < 0) {  // A single cpu index
37*eca53ba6SRoland Levillain     int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text);
38*eca53ba6SRoland Levillain     if (cpu_index < 0) return;
39*eca53ba6SRoland Levillain     set_cpu_mask_bit(cpu_index, cpu_mask);
40*eca53ba6SRoland Levillain   } else {
41*eca53ba6SRoland Levillain     int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber(
42*eca53ba6SRoland Levillain         CpuFeatures_StringView_KeepFront(text, separator_index));
43*eca53ba6SRoland Levillain     int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber(
44*eca53ba6SRoland Levillain         CpuFeatures_StringView_PopFront(text, separator_index + 1));
45*eca53ba6SRoland Levillain     int i;
46*eca53ba6SRoland Levillain     if (cpu_index_a < 0 || cpu_index_b < 0) return;
47*eca53ba6SRoland Levillain     for (i = cpu_index_a; i <= cpu_index_b; ++i) {
48*eca53ba6SRoland Levillain       if (i < 32) {
49*eca53ba6SRoland Levillain         set_cpu_mask_bit(i, cpu_mask);
50*eca53ba6SRoland Levillain       }
51*eca53ba6SRoland Levillain     }
52*eca53ba6SRoland Levillain   }
53*eca53ba6SRoland Levillain }
54*eca53ba6SRoland Levillain 
55*eca53ba6SRoland Levillain // Format specification from
56*eca53ba6SRoland Levillain // https://www.kernel.org/doc/Documentation/cputopology.txt
57*eca53ba6SRoland Levillain // Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3"
parse_cpu_mask_line(const LineResult result,uint32_t * cpu_mask)58*eca53ba6SRoland Levillain static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) {
59*eca53ba6SRoland Levillain   if (!result.full_line || result.eof) return;
60*eca53ba6SRoland Levillain   StringView line = result.line;
61*eca53ba6SRoland Levillain   for (; line.size > 0;) {
62*eca53ba6SRoland Levillain     int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ',');
63*eca53ba6SRoland Levillain     if (next_entry_index < 0) {
64*eca53ba6SRoland Levillain       parse_cpu_mask(line, cpu_mask);
65*eca53ba6SRoland Levillain       break;
66*eca53ba6SRoland Levillain     }
67*eca53ba6SRoland Levillain     StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index);
68*eca53ba6SRoland Levillain     parse_cpu_mask(entry, cpu_mask);
69*eca53ba6SRoland Levillain     line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1);
70*eca53ba6SRoland Levillain   }
71*eca53ba6SRoland Levillain }
72*eca53ba6SRoland Levillain 
update_cpu_mask_from_file(const char * filename,uint32_t * cpu_mask)73*eca53ba6SRoland Levillain static void update_cpu_mask_from_file(const char* filename,
74*eca53ba6SRoland Levillain                                       uint32_t* cpu_mask) {
75*eca53ba6SRoland Levillain   const int fd = CpuFeatures_OpenFile(filename);
76*eca53ba6SRoland Levillain   if (fd >= 0) {
77*eca53ba6SRoland Levillain     StackLineReader reader;
78*eca53ba6SRoland Levillain     StackLineReader_Initialize(&reader, fd);
79*eca53ba6SRoland Levillain     parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask);
80*eca53ba6SRoland Levillain     CpuFeatures_CloseFile(fd);
81*eca53ba6SRoland Levillain   }
82*eca53ba6SRoland Levillain }
83*eca53ba6SRoland Levillain 
get_cpu_count(void)84*eca53ba6SRoland Levillain static int get_cpu_count(void) {
85*eca53ba6SRoland Levillain   uint32_t cpu_mask = 0;
86*eca53ba6SRoland Levillain   update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask);
87*eca53ba6SRoland Levillain   update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask);
88*eca53ba6SRoland Levillain   return __builtin_popcount(cpu_mask);
89*eca53ba6SRoland Levillain }
90*eca53ba6SRoland Levillain 
android_cpuInit(void)91*eca53ba6SRoland Levillain static void android_cpuInit(void) {
92*eca53ba6SRoland Levillain   g_cpuFeatures = 0;
93*eca53ba6SRoland Levillain   g_cpuCount = 1;
94*eca53ba6SRoland Levillain   g_inited = 1;
95*eca53ba6SRoland Levillain 
96*eca53ba6SRoland Levillain   g_cpuCount = get_cpu_count();
97*eca53ba6SRoland Levillain   if (g_cpuCount == 0) {
98*eca53ba6SRoland Levillain     g_cpuCount = 1;
99*eca53ba6SRoland Levillain   }
100*eca53ba6SRoland Levillain #if defined(CPU_FEATURES_ARCH_ARM)
101*eca53ba6SRoland Levillain   ArmInfo info = GetArmInfo();
102*eca53ba6SRoland Levillain   if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
103*eca53ba6SRoland Levillain   if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
104*eca53ba6SRoland Levillain   if (info.features.neon) {
105*eca53ba6SRoland Levillain     g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
106*eca53ba6SRoland Levillain     g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32;
107*eca53ba6SRoland Levillain   }
108*eca53ba6SRoland Levillain   if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16;
109*eca53ba6SRoland Levillain   if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
110*eca53ba6SRoland Levillain   if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
111*eca53ba6SRoland Levillain   if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
112*eca53ba6SRoland Levillain   if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
113*eca53ba6SRoland Levillain   if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
114*eca53ba6SRoland Levillain   if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
115*eca53ba6SRoland Levillain   if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
116*eca53ba6SRoland Levillain   if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
117*eca53ba6SRoland Levillain   if (info.architecture >= 6)
118*eca53ba6SRoland Levillain     g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
119*eca53ba6SRoland Levillain   if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
120*eca53ba6SRoland Levillain   if (info.features.vfpv4) {
121*eca53ba6SRoland Levillain     g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA;
122*eca53ba6SRoland Levillain     g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
123*eca53ba6SRoland Levillain   }
124*eca53ba6SRoland Levillain   g_cpuIdArm = GetArmCpuId(&info);
125*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_X86)
126*eca53ba6SRoland Levillain   X86Info info = GetX86Info();
127*eca53ba6SRoland Levillain   if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
128*eca53ba6SRoland Levillain   if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
129*eca53ba6SRoland Levillain   if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
130*eca53ba6SRoland Levillain   if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
131*eca53ba6SRoland Levillain   if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
132*eca53ba6SRoland Levillain   if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
133*eca53ba6SRoland Levillain   if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
134*eca53ba6SRoland Levillain   if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
135*eca53ba6SRoland Levillain   if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
136*eca53ba6SRoland Levillain   if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
137*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_MIPS)
138*eca53ba6SRoland Levillain   MipsInfo info = GetMipsInfo();
139*eca53ba6SRoland Levillain   if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
140*eca53ba6SRoland Levillain   if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
141*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_AARCH64)
142*eca53ba6SRoland Levillain   Aarch64Info info = GetAarch64Info();
143*eca53ba6SRoland Levillain   if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
144*eca53ba6SRoland Levillain   if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
145*eca53ba6SRoland Levillain   if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
146*eca53ba6SRoland Levillain   if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
147*eca53ba6SRoland Levillain   if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
148*eca53ba6SRoland Levillain   if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
149*eca53ba6SRoland Levillain   if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
150*eca53ba6SRoland Levillain #endif
151*eca53ba6SRoland Levillain }
152*eca53ba6SRoland Levillain 
android_getCpuFamily(void)153*eca53ba6SRoland Levillain AndroidCpuFamily android_getCpuFamily(void) {
154*eca53ba6SRoland Levillain #if defined(CPU_FEATURES_ARCH_ARM)
155*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_ARM;
156*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_X86_32)
157*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_X86;
158*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_MIPS64)
159*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_MIPS64;
160*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_MIPS32)
161*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_MIPS;
162*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_AARCH64)
163*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_ARM64;
164*eca53ba6SRoland Levillain #elif defined(CPU_FEATURES_ARCH_X86_64)
165*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_X86_64;
166*eca53ba6SRoland Levillain #else
167*eca53ba6SRoland Levillain   return ANDROID_CPU_FAMILY_UNKNOWN;
168*eca53ba6SRoland Levillain #endif
169*eca53ba6SRoland Levillain }
170*eca53ba6SRoland Levillain 
android_getCpuFeatures(void)171*eca53ba6SRoland Levillain uint64_t android_getCpuFeatures(void) {
172*eca53ba6SRoland Levillain   pthread_once(&g_once, android_cpuInit);
173*eca53ba6SRoland Levillain   return g_cpuFeatures;
174*eca53ba6SRoland Levillain }
175*eca53ba6SRoland Levillain 
android_getCpuCount(void)176*eca53ba6SRoland Levillain int android_getCpuCount(void) {
177*eca53ba6SRoland Levillain   pthread_once(&g_once, android_cpuInit);
178*eca53ba6SRoland Levillain   return g_cpuCount;
179*eca53ba6SRoland Levillain }
180*eca53ba6SRoland Levillain 
android_cpuInitDummy(void)181*eca53ba6SRoland Levillain static void android_cpuInitDummy(void) { g_inited = 1; }
182*eca53ba6SRoland Levillain 
android_setCpu(int cpu_count,uint64_t cpu_features)183*eca53ba6SRoland Levillain int android_setCpu(int cpu_count, uint64_t cpu_features) {
184*eca53ba6SRoland Levillain   /* Fail if the library was already initialized. */
185*eca53ba6SRoland Levillain   if (g_inited) return 0;
186*eca53ba6SRoland Levillain   g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
187*eca53ba6SRoland Levillain   g_cpuFeatures = cpu_features;
188*eca53ba6SRoland Levillain   pthread_once(&g_once, android_cpuInitDummy);
189*eca53ba6SRoland Levillain   return 1;
190*eca53ba6SRoland Levillain }
191*eca53ba6SRoland Levillain 
192*eca53ba6SRoland Levillain #ifdef CPU_FEATURES_ARCH_ARM
193*eca53ba6SRoland Levillain 
android_getCpuIdArm(void)194*eca53ba6SRoland Levillain uint32_t android_getCpuIdArm(void) {
195*eca53ba6SRoland Levillain   pthread_once(&g_once, android_cpuInit);
196*eca53ba6SRoland Levillain   return g_cpuIdArm;
197*eca53ba6SRoland Levillain }
198*eca53ba6SRoland Levillain 
android_setCpuArm(int cpu_count,uint64_t cpu_features,uint32_t cpu_id)199*eca53ba6SRoland Levillain int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) {
200*eca53ba6SRoland Levillain   if (!android_setCpu(cpu_count, cpu_features)) return 0;
201*eca53ba6SRoland Levillain   g_cpuIdArm = cpu_id;
202*eca53ba6SRoland Levillain   return 1;
203*eca53ba6SRoland Levillain }
204*eca53ba6SRoland Levillain 
205*eca53ba6SRoland Levillain #endif  // CPU_FEATURES_ARCH_ARM
206