xref: /aosp_15_r20/external/cpuinfo/src/linux/processors.c (revision 2b54f0db79fd8303838913b20ff3780cddaa909f)
1*2b54f0dbSXin Li #include <stdbool.h>
2*2b54f0dbSXin Li #include <stdint.h>
3*2b54f0dbSXin Li #include <stdlib.h>
4*2b54f0dbSXin Li #include <stdio.h>
5*2b54f0dbSXin Li #include <string.h>
6*2b54f0dbSXin Li 
7*2b54f0dbSXin Li #if !defined(__ANDROID__)
8*2b54f0dbSXin Li 	/*
9*2b54f0dbSXin Li 	 * sched.h is only used for CPU_SETSIZE constant.
10*2b54f0dbSXin Li 	 * Android NDK headers before platform 21 do have this constant in sched.h
11*2b54f0dbSXin Li 	 */
12*2b54f0dbSXin Li 	#include <sched.h>
13*2b54f0dbSXin Li #endif
14*2b54f0dbSXin Li 
15*2b54f0dbSXin Li #include <linux/api.h>
16*2b54f0dbSXin Li #include <cpuinfo/log.h>
17*2b54f0dbSXin Li 
18*2b54f0dbSXin Li 
19*2b54f0dbSXin Li #define STRINGIFY(token) #token
20*2b54f0dbSXin Li 
21*2b54f0dbSXin Li #define KERNEL_MAX_FILENAME "/sys/devices/system/cpu/kernel_max"
22*2b54f0dbSXin Li #define KERNEL_MAX_FILESIZE 32
23*2b54f0dbSXin Li #define FREQUENCY_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/cpufreq/cpuinfo_max_freq"))
24*2b54f0dbSXin Li #define MAX_FREQUENCY_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/cpufreq/cpuinfo_max_freq"
25*2b54f0dbSXin Li #define MIN_FREQUENCY_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/cpufreq/cpuinfo_min_freq"
26*2b54f0dbSXin Li #define FREQUENCY_FILESIZE 32
27*2b54f0dbSXin Li #define PACKAGE_ID_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/topology/physical_package_id"))
28*2b54f0dbSXin Li #define PACKAGE_ID_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/physical_package_id"
29*2b54f0dbSXin Li #define PACKAGE_ID_FILESIZE 32
30*2b54f0dbSXin Li #define CORE_ID_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/topology/core_id"))
31*2b54f0dbSXin Li #define CORE_ID_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id"
32*2b54f0dbSXin Li #define CORE_ID_FILESIZE 32
33*2b54f0dbSXin Li 
34*2b54f0dbSXin Li #define CORE_SIBLINGS_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/topology/core_siblings_list"))
35*2b54f0dbSXin Li #define CORE_SIBLINGS_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_siblings_list"
36*2b54f0dbSXin Li #define THREAD_SIBLINGS_FILENAME_SIZE (sizeof("/sys/devices/system/cpu/cpu" STRINGIFY(UINT32_MAX) "/topology/thread_siblings_list"))
37*2b54f0dbSXin Li #define THREAD_SIBLINGS_FILENAME_FORMAT "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/thread_siblings_list"
38*2b54f0dbSXin Li 
39*2b54f0dbSXin Li #define POSSIBLE_CPULIST_FILENAME "/sys/devices/system/cpu/possible"
40*2b54f0dbSXin Li #define PRESENT_CPULIST_FILENAME "/sys/devices/system/cpu/present"
41*2b54f0dbSXin Li 
42*2b54f0dbSXin Li 
parse_number(const char * start,const char * end,uint32_t number_ptr[restrict static1])43*2b54f0dbSXin Li inline static const char* parse_number(const char* start, const char* end, uint32_t number_ptr[restrict static 1]) {
44*2b54f0dbSXin Li 	uint32_t number = 0;
45*2b54f0dbSXin Li 	const char* parsed = start;
46*2b54f0dbSXin Li 	for (; parsed != end; parsed++) {
47*2b54f0dbSXin Li 		const uint32_t digit = (uint32_t) (uint8_t) (*parsed) - (uint32_t) '0';
48*2b54f0dbSXin Li 		if (digit >= 10) {
49*2b54f0dbSXin Li 			break;
50*2b54f0dbSXin Li 		}
51*2b54f0dbSXin Li 		number = number * UINT32_C(10) + digit;
52*2b54f0dbSXin Li 	}
53*2b54f0dbSXin Li 	*number_ptr = number;
54*2b54f0dbSXin Li 	return parsed;
55*2b54f0dbSXin Li }
56*2b54f0dbSXin Li 
57*2b54f0dbSXin Li /* Locale-independent */
is_whitespace(char c)58*2b54f0dbSXin Li inline static bool is_whitespace(char c) {
59*2b54f0dbSXin Li 	switch (c) {
60*2b54f0dbSXin Li 		case ' ':
61*2b54f0dbSXin Li 		case '\t':
62*2b54f0dbSXin Li 		case '\n':
63*2b54f0dbSXin Li 		case '\r':
64*2b54f0dbSXin Li 			return true;
65*2b54f0dbSXin Li 		default:
66*2b54f0dbSXin Li 			return false;
67*2b54f0dbSXin Li 	}
68*2b54f0dbSXin Li }
69*2b54f0dbSXin Li 
70*2b54f0dbSXin Li #if defined(__ANDROID__) && !defined(CPU_SETSIZE)
71*2b54f0dbSXin Li 	/*
72*2b54f0dbSXin Li 	 * Android NDK headers before platform 21 do not define CPU_SETSIZE,
73*2b54f0dbSXin Li 	 * so we hard-code its value, as defined in platform 21 headers
74*2b54f0dbSXin Li 	 */
75*2b54f0dbSXin Li 	#if defined(__LP64__)
76*2b54f0dbSXin Li 		static const uint32_t default_max_processors_count = 1024;
77*2b54f0dbSXin Li 	#else
78*2b54f0dbSXin Li 		static const uint32_t default_max_processors_count = 32;
79*2b54f0dbSXin Li 	#endif
80*2b54f0dbSXin Li #else
81*2b54f0dbSXin Li 	static const uint32_t default_max_processors_count = CPU_SETSIZE;
82*2b54f0dbSXin Li #endif
83*2b54f0dbSXin Li 
uint32_parser(const char * text_start,const char * text_end,void * context)84*2b54f0dbSXin Li static bool uint32_parser(const char* text_start, const char* text_end, void* context) {
85*2b54f0dbSXin Li 	if (text_start == text_end) {
86*2b54f0dbSXin Li 		cpuinfo_log_error("failed to parse file %s: file is empty", KERNEL_MAX_FILENAME);
87*2b54f0dbSXin Li 		return false;
88*2b54f0dbSXin Li 	}
89*2b54f0dbSXin Li 
90*2b54f0dbSXin Li 	uint32_t kernel_max = 0;
91*2b54f0dbSXin Li 	const char* parsed_end = parse_number(text_start, text_end, &kernel_max);
92*2b54f0dbSXin Li 	if (parsed_end == text_start) {
93*2b54f0dbSXin Li 		cpuinfo_log_error("failed to parse file %s: \"%.*s\" is not an unsigned number",
94*2b54f0dbSXin Li 			KERNEL_MAX_FILENAME, (int) (text_end - text_start), text_start);
95*2b54f0dbSXin Li 		return false;
96*2b54f0dbSXin Li 	} else {
97*2b54f0dbSXin Li 		for (const char* char_ptr = parsed_end; char_ptr != text_end; char_ptr++) {
98*2b54f0dbSXin Li 			if (!is_whitespace(*char_ptr)) {
99*2b54f0dbSXin Li 				cpuinfo_log_warning("non-whitespace characters \"%.*s\" following number in file %s are ignored",
100*2b54f0dbSXin Li 					(int) (text_end - char_ptr), char_ptr, KERNEL_MAX_FILENAME);
101*2b54f0dbSXin Li 				break;
102*2b54f0dbSXin Li 			}
103*2b54f0dbSXin Li 		}
104*2b54f0dbSXin Li 	}
105*2b54f0dbSXin Li 
106*2b54f0dbSXin Li 	uint32_t* kernel_max_ptr = (uint32_t*) context;
107*2b54f0dbSXin Li 	*kernel_max_ptr = kernel_max;
108*2b54f0dbSXin Li 	return true;
109*2b54f0dbSXin Li }
110*2b54f0dbSXin Li 
cpuinfo_linux_get_max_processors_count(void)111*2b54f0dbSXin Li uint32_t cpuinfo_linux_get_max_processors_count(void) {
112*2b54f0dbSXin Li 	uint32_t kernel_max;
113*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_small_file(KERNEL_MAX_FILENAME, KERNEL_MAX_FILESIZE, uint32_parser, &kernel_max)) {
114*2b54f0dbSXin Li 		cpuinfo_log_debug("parsed kernel_max value of %"PRIu32" from %s", kernel_max, KERNEL_MAX_FILENAME);
115*2b54f0dbSXin Li 
116*2b54f0dbSXin Li 		if (kernel_max >= default_max_processors_count) {
117*2b54f0dbSXin Li 			cpuinfo_log_warning("kernel_max value of %"PRIu32" parsed from %s exceeds platform-default limit %"PRIu32,
118*2b54f0dbSXin Li 				kernel_max, KERNEL_MAX_FILENAME, default_max_processors_count - 1);
119*2b54f0dbSXin Li 		}
120*2b54f0dbSXin Li 
121*2b54f0dbSXin Li 		return kernel_max + 1;
122*2b54f0dbSXin Li 	} else {
123*2b54f0dbSXin Li 		cpuinfo_log_warning("using platform-default max processors count = %"PRIu32, default_max_processors_count);
124*2b54f0dbSXin Li 		return default_max_processors_count;
125*2b54f0dbSXin Li 	}
126*2b54f0dbSXin Li }
127*2b54f0dbSXin Li 
cpuinfo_linux_get_processor_max_frequency(uint32_t processor)128*2b54f0dbSXin Li uint32_t cpuinfo_linux_get_processor_max_frequency(uint32_t processor) {
129*2b54f0dbSXin Li 	char max_frequency_filename[FREQUENCY_FILENAME_SIZE];
130*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
131*2b54f0dbSXin Li 		max_frequency_filename, FREQUENCY_FILENAME_SIZE, MAX_FREQUENCY_FILENAME_FORMAT, processor);
132*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= FREQUENCY_FILENAME_SIZE) {
133*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for max frequency of processor %"PRIu32, processor);
134*2b54f0dbSXin Li 		return 0;
135*2b54f0dbSXin Li 	}
136*2b54f0dbSXin Li 
137*2b54f0dbSXin Li 	uint32_t max_frequency;
138*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_small_file(max_frequency_filename, FREQUENCY_FILESIZE, uint32_parser, &max_frequency)) {
139*2b54f0dbSXin Li 		cpuinfo_log_debug("parsed max frequency value of %"PRIu32" KHz for logical processor %"PRIu32" from %s",
140*2b54f0dbSXin Li 			max_frequency, processor, max_frequency_filename);
141*2b54f0dbSXin Li 		return max_frequency;
142*2b54f0dbSXin Li 	} else {
143*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to parse max frequency for processor %"PRIu32" from %s",
144*2b54f0dbSXin Li 			processor, max_frequency_filename);
145*2b54f0dbSXin Li 		return 0;
146*2b54f0dbSXin Li 	}
147*2b54f0dbSXin Li }
148*2b54f0dbSXin Li 
cpuinfo_linux_get_processor_min_frequency(uint32_t processor)149*2b54f0dbSXin Li uint32_t cpuinfo_linux_get_processor_min_frequency(uint32_t processor) {
150*2b54f0dbSXin Li 	char min_frequency_filename[FREQUENCY_FILENAME_SIZE];
151*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
152*2b54f0dbSXin Li 		min_frequency_filename, FREQUENCY_FILENAME_SIZE, MIN_FREQUENCY_FILENAME_FORMAT, processor);
153*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= FREQUENCY_FILENAME_SIZE) {
154*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for min frequency of processor %"PRIu32, processor);
155*2b54f0dbSXin Li 		return 0;
156*2b54f0dbSXin Li 	}
157*2b54f0dbSXin Li 
158*2b54f0dbSXin Li 	uint32_t min_frequency;
159*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_small_file(min_frequency_filename, FREQUENCY_FILESIZE, uint32_parser, &min_frequency)) {
160*2b54f0dbSXin Li 		cpuinfo_log_debug("parsed min frequency value of %"PRIu32" KHz for logical processor %"PRIu32" from %s",
161*2b54f0dbSXin Li 			min_frequency, processor, min_frequency_filename);
162*2b54f0dbSXin Li 		return min_frequency;
163*2b54f0dbSXin Li 	} else {
164*2b54f0dbSXin Li 		/*
165*2b54f0dbSXin Li 		 * This error is less severe than parsing max frequency, because min frequency is only useful for clustering,
166*2b54f0dbSXin Li 		 * while max frequency is also needed for peak FLOPS calculation.
167*2b54f0dbSXin Li 		 */
168*2b54f0dbSXin Li 		cpuinfo_log_info("failed to parse min frequency for processor %"PRIu32" from %s",
169*2b54f0dbSXin Li 			processor, min_frequency_filename);
170*2b54f0dbSXin Li 		return 0;
171*2b54f0dbSXin Li 	}
172*2b54f0dbSXin Li }
173*2b54f0dbSXin Li 
cpuinfo_linux_get_processor_core_id(uint32_t processor,uint32_t core_id_ptr[restrict static1])174*2b54f0dbSXin Li bool cpuinfo_linux_get_processor_core_id(uint32_t processor, uint32_t core_id_ptr[restrict static 1]) {
175*2b54f0dbSXin Li 	char core_id_filename[PACKAGE_ID_FILENAME_SIZE];
176*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
177*2b54f0dbSXin Li 		core_id_filename, CORE_ID_FILENAME_SIZE, CORE_ID_FILENAME_FORMAT, processor);
178*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= CORE_ID_FILENAME_SIZE) {
179*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for core id of processor %"PRIu32, processor);
180*2b54f0dbSXin Li 		return 0;
181*2b54f0dbSXin Li 	}
182*2b54f0dbSXin Li 
183*2b54f0dbSXin Li 	uint32_t core_id;
184*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_small_file(core_id_filename, CORE_ID_FILESIZE, uint32_parser, &core_id)) {
185*2b54f0dbSXin Li 		cpuinfo_log_debug("parsed core id value of %"PRIu32" for logical processor %"PRIu32" from %s",
186*2b54f0dbSXin Li 			core_id, processor, core_id_filename);
187*2b54f0dbSXin Li 		*core_id_ptr = core_id;
188*2b54f0dbSXin Li 		return true;
189*2b54f0dbSXin Li 	} else {
190*2b54f0dbSXin Li 		cpuinfo_log_info("failed to parse core id for processor %"PRIu32" from %s",
191*2b54f0dbSXin Li 			processor, core_id_filename);
192*2b54f0dbSXin Li 		return false;
193*2b54f0dbSXin Li 	}
194*2b54f0dbSXin Li }
195*2b54f0dbSXin Li 
cpuinfo_linux_get_processor_package_id(uint32_t processor,uint32_t package_id_ptr[restrict static1])196*2b54f0dbSXin Li bool cpuinfo_linux_get_processor_package_id(uint32_t processor, uint32_t package_id_ptr[restrict static 1]) {
197*2b54f0dbSXin Li 	char package_id_filename[PACKAGE_ID_FILENAME_SIZE];
198*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
199*2b54f0dbSXin Li 		package_id_filename, PACKAGE_ID_FILENAME_SIZE, PACKAGE_ID_FILENAME_FORMAT, processor);
200*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= PACKAGE_ID_FILENAME_SIZE) {
201*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for package id of processor %"PRIu32, processor);
202*2b54f0dbSXin Li 		return 0;
203*2b54f0dbSXin Li 	}
204*2b54f0dbSXin Li 
205*2b54f0dbSXin Li 	uint32_t package_id;
206*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_small_file(package_id_filename, PACKAGE_ID_FILESIZE, uint32_parser, &package_id)) {
207*2b54f0dbSXin Li 		cpuinfo_log_debug("parsed package id value of %"PRIu32" for logical processor %"PRIu32" from %s",
208*2b54f0dbSXin Li 			package_id, processor, package_id_filename);
209*2b54f0dbSXin Li 		*package_id_ptr = package_id;
210*2b54f0dbSXin Li 		return true;
211*2b54f0dbSXin Li 	} else {
212*2b54f0dbSXin Li 		cpuinfo_log_info("failed to parse package id for processor %"PRIu32" from %s",
213*2b54f0dbSXin Li 			processor, package_id_filename);
214*2b54f0dbSXin Li 		return false;
215*2b54f0dbSXin Li 	}
216*2b54f0dbSXin Li }
217*2b54f0dbSXin Li 
max_processor_number_parser(uint32_t processor_list_start,uint32_t processor_list_end,void * context)218*2b54f0dbSXin Li static bool max_processor_number_parser(uint32_t processor_list_start, uint32_t processor_list_end, void* context) {
219*2b54f0dbSXin Li 	uint32_t* processor_number_ptr = (uint32_t*) context;
220*2b54f0dbSXin Li 	const uint32_t processor_list_last = processor_list_end - 1;
221*2b54f0dbSXin Li 	if (*processor_number_ptr < processor_list_last) {
222*2b54f0dbSXin Li 		*processor_number_ptr = processor_list_last;
223*2b54f0dbSXin Li 	}
224*2b54f0dbSXin Li 	return true;
225*2b54f0dbSXin Li }
226*2b54f0dbSXin Li 
cpuinfo_linux_get_max_possible_processor(uint32_t max_processors_count)227*2b54f0dbSXin Li uint32_t cpuinfo_linux_get_max_possible_processor(uint32_t max_processors_count) {
228*2b54f0dbSXin Li 	uint32_t max_possible_processor = 0;
229*2b54f0dbSXin Li 	if (!cpuinfo_linux_parse_cpulist(POSSIBLE_CPULIST_FILENAME, max_processor_number_parser, &max_possible_processor)) {
230*2b54f0dbSXin Li 		#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
231*2b54f0dbSXin Li 			cpuinfo_log_error("failed to parse the list of possible processors in %s", POSSIBLE_CPULIST_FILENAME);
232*2b54f0dbSXin Li 		#else
233*2b54f0dbSXin Li 			cpuinfo_log_warning("failed to parse the list of possible processors in %s", POSSIBLE_CPULIST_FILENAME);
234*2b54f0dbSXin Li 		#endif
235*2b54f0dbSXin Li 		return UINT32_MAX;
236*2b54f0dbSXin Li 	}
237*2b54f0dbSXin Li 	if (max_possible_processor >= max_processors_count) {
238*2b54f0dbSXin Li 		cpuinfo_log_warning(
239*2b54f0dbSXin Li 			"maximum possible processor number %"PRIu32" exceeds system limit %"PRIu32": truncating to the latter",
240*2b54f0dbSXin Li 			max_possible_processor, max_processors_count - 1);
241*2b54f0dbSXin Li 		max_possible_processor = max_processors_count - 1;
242*2b54f0dbSXin Li 	}
243*2b54f0dbSXin Li 	return max_possible_processor;
244*2b54f0dbSXin Li }
245*2b54f0dbSXin Li 
cpuinfo_linux_get_max_present_processor(uint32_t max_processors_count)246*2b54f0dbSXin Li uint32_t cpuinfo_linux_get_max_present_processor(uint32_t max_processors_count) {
247*2b54f0dbSXin Li 	uint32_t max_present_processor = 0;
248*2b54f0dbSXin Li 	if (!cpuinfo_linux_parse_cpulist(PRESENT_CPULIST_FILENAME, max_processor_number_parser, &max_present_processor)) {
249*2b54f0dbSXin Li 		#if CPUINFO_ARCH_ARM || CPUINFO_ARCH_ARM64
250*2b54f0dbSXin Li 			cpuinfo_log_error("failed to parse the list of present processors in %s", PRESENT_CPULIST_FILENAME);
251*2b54f0dbSXin Li 		#else
252*2b54f0dbSXin Li 			cpuinfo_log_warning("failed to parse the list of present processors in %s", PRESENT_CPULIST_FILENAME);
253*2b54f0dbSXin Li 		#endif
254*2b54f0dbSXin Li 		return UINT32_MAX;
255*2b54f0dbSXin Li 	}
256*2b54f0dbSXin Li 	if (max_present_processor >= max_processors_count) {
257*2b54f0dbSXin Li 		cpuinfo_log_warning(
258*2b54f0dbSXin Li 			"maximum present processor number %"PRIu32" exceeds system limit %"PRIu32": truncating to the latter",
259*2b54f0dbSXin Li 			max_present_processor, max_processors_count - 1);
260*2b54f0dbSXin Li 		max_present_processor = max_processors_count - 1;
261*2b54f0dbSXin Li 	}
262*2b54f0dbSXin Li 	return max_present_processor;
263*2b54f0dbSXin Li }
264*2b54f0dbSXin Li 
265*2b54f0dbSXin Li struct detect_processors_context {
266*2b54f0dbSXin Li 	uint32_t max_processors_count;
267*2b54f0dbSXin Li 	uint32_t* processor0_flags;
268*2b54f0dbSXin Li 	uint32_t processor_struct_size;
269*2b54f0dbSXin Li 	uint32_t detected_flag;
270*2b54f0dbSXin Li };
271*2b54f0dbSXin Li 
detect_processor_parser(uint32_t processor_list_start,uint32_t processor_list_end,void * context)272*2b54f0dbSXin Li static bool detect_processor_parser(uint32_t processor_list_start, uint32_t processor_list_end, void* context) {
273*2b54f0dbSXin Li 	const uint32_t max_processors_count   = ((struct detect_processors_context*) context)->max_processors_count;
274*2b54f0dbSXin Li 	const uint32_t* processor0_flags      = ((struct detect_processors_context*) context)->processor0_flags;
275*2b54f0dbSXin Li 	const uint32_t processor_struct_size  = ((struct detect_processors_context*) context)->processor_struct_size;
276*2b54f0dbSXin Li 	const uint32_t detected_flag          = ((struct detect_processors_context*) context)->detected_flag;
277*2b54f0dbSXin Li 
278*2b54f0dbSXin Li 	for (uint32_t processor = processor_list_start; processor < processor_list_end; processor++) {
279*2b54f0dbSXin Li 		if (processor >= max_processors_count) {
280*2b54f0dbSXin Li 			break;
281*2b54f0dbSXin Li 		}
282*2b54f0dbSXin Li 		*((uint32_t*) ((uintptr_t) processor0_flags + processor_struct_size * processor)) |= detected_flag;
283*2b54f0dbSXin Li 	}
284*2b54f0dbSXin Li 	return true;
285*2b54f0dbSXin Li }
286*2b54f0dbSXin Li 
cpuinfo_linux_detect_possible_processors(uint32_t max_processors_count,uint32_t * processor0_flags,uint32_t processor_struct_size,uint32_t possible_flag)287*2b54f0dbSXin Li bool cpuinfo_linux_detect_possible_processors(uint32_t max_processors_count,
288*2b54f0dbSXin Li 	uint32_t* processor0_flags, uint32_t processor_struct_size, uint32_t possible_flag)
289*2b54f0dbSXin Li {
290*2b54f0dbSXin Li 	struct detect_processors_context context = {
291*2b54f0dbSXin Li 		.max_processors_count = max_processors_count,
292*2b54f0dbSXin Li 		.processor0_flags = processor0_flags,
293*2b54f0dbSXin Li 		.processor_struct_size = processor_struct_size,
294*2b54f0dbSXin Li 		.detected_flag = possible_flag,
295*2b54f0dbSXin Li 	};
296*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_cpulist(POSSIBLE_CPULIST_FILENAME, detect_processor_parser, &context)) {
297*2b54f0dbSXin Li 		return true;
298*2b54f0dbSXin Li 	} else {
299*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to parse the list of possible processors in %s", POSSIBLE_CPULIST_FILENAME);
300*2b54f0dbSXin Li 		return false;
301*2b54f0dbSXin Li 	}
302*2b54f0dbSXin Li }
303*2b54f0dbSXin Li 
cpuinfo_linux_detect_present_processors(uint32_t max_processors_count,uint32_t * processor0_flags,uint32_t processor_struct_size,uint32_t present_flag)304*2b54f0dbSXin Li bool cpuinfo_linux_detect_present_processors(uint32_t max_processors_count,
305*2b54f0dbSXin Li 	uint32_t* processor0_flags, uint32_t processor_struct_size, uint32_t present_flag)
306*2b54f0dbSXin Li {
307*2b54f0dbSXin Li 	struct detect_processors_context context = {
308*2b54f0dbSXin Li 		.max_processors_count = max_processors_count,
309*2b54f0dbSXin Li 		.processor0_flags = processor0_flags,
310*2b54f0dbSXin Li 		.processor_struct_size = processor_struct_size,
311*2b54f0dbSXin Li 		.detected_flag = present_flag,
312*2b54f0dbSXin Li 	};
313*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_cpulist(PRESENT_CPULIST_FILENAME, detect_processor_parser, &context)) {
314*2b54f0dbSXin Li 		return true;
315*2b54f0dbSXin Li 	} else {
316*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to parse the list of present processors in %s", PRESENT_CPULIST_FILENAME);
317*2b54f0dbSXin Li 		return false;
318*2b54f0dbSXin Li 	}
319*2b54f0dbSXin Li }
320*2b54f0dbSXin Li 
321*2b54f0dbSXin Li struct siblings_context {
322*2b54f0dbSXin Li 	const char* group_name;
323*2b54f0dbSXin Li 	uint32_t max_processors_count;
324*2b54f0dbSXin Li 	uint32_t processor;
325*2b54f0dbSXin Li 	cpuinfo_siblings_callback callback;
326*2b54f0dbSXin Li 	void* callback_context;
327*2b54f0dbSXin Li };
328*2b54f0dbSXin Li 
siblings_parser(uint32_t sibling_list_start,uint32_t sibling_list_end,struct siblings_context * context)329*2b54f0dbSXin Li static bool siblings_parser(uint32_t sibling_list_start, uint32_t sibling_list_end, struct siblings_context* context) {
330*2b54f0dbSXin Li 	const char* group_name                   = context->group_name;
331*2b54f0dbSXin Li 	const uint32_t max_processors_count      = context->max_processors_count;
332*2b54f0dbSXin Li 	const uint32_t processor                 = context->processor;
333*2b54f0dbSXin Li 
334*2b54f0dbSXin Li 	if (sibling_list_end > max_processors_count) {
335*2b54f0dbSXin Li 		cpuinfo_log_warning("ignore %s siblings %"PRIu32"-%"PRIu32" of processor %"PRIu32,
336*2b54f0dbSXin Li 			group_name, max_processors_count, sibling_list_end - 1, processor);
337*2b54f0dbSXin Li 		sibling_list_end = max_processors_count;
338*2b54f0dbSXin Li 	}
339*2b54f0dbSXin Li 
340*2b54f0dbSXin Li 	return context->callback(processor, sibling_list_start, sibling_list_end, context->callback_context);
341*2b54f0dbSXin Li }
342*2b54f0dbSXin Li 
cpuinfo_linux_detect_core_siblings(uint32_t max_processors_count,uint32_t processor,cpuinfo_siblings_callback callback,void * context)343*2b54f0dbSXin Li bool cpuinfo_linux_detect_core_siblings(
344*2b54f0dbSXin Li 	uint32_t max_processors_count,
345*2b54f0dbSXin Li 	uint32_t processor,
346*2b54f0dbSXin Li 	cpuinfo_siblings_callback callback,
347*2b54f0dbSXin Li 	void* context)
348*2b54f0dbSXin Li {
349*2b54f0dbSXin Li 	char core_siblings_filename[CORE_SIBLINGS_FILENAME_SIZE];
350*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
351*2b54f0dbSXin Li 		core_siblings_filename, CORE_SIBLINGS_FILENAME_SIZE, CORE_SIBLINGS_FILENAME_FORMAT, processor);
352*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= CORE_SIBLINGS_FILENAME_SIZE) {
353*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for core siblings of processor %"PRIu32, processor);
354*2b54f0dbSXin Li 		return false;
355*2b54f0dbSXin Li 	}
356*2b54f0dbSXin Li 
357*2b54f0dbSXin Li 	struct siblings_context siblings_context = {
358*2b54f0dbSXin Li 		.group_name = "package",
359*2b54f0dbSXin Li 		.max_processors_count = max_processors_count,
360*2b54f0dbSXin Li 		.processor = processor,
361*2b54f0dbSXin Li 		.callback = callback,
362*2b54f0dbSXin Li 		.callback_context = context,
363*2b54f0dbSXin Li 	};
364*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_cpulist(core_siblings_filename,
365*2b54f0dbSXin Li 		(cpuinfo_cpulist_callback) siblings_parser, &siblings_context))
366*2b54f0dbSXin Li 	{
367*2b54f0dbSXin Li 		return true;
368*2b54f0dbSXin Li 	} else {
369*2b54f0dbSXin Li 		cpuinfo_log_info("failed to parse the list of core siblings for processor %"PRIu32" from %s",
370*2b54f0dbSXin Li 			processor, core_siblings_filename);
371*2b54f0dbSXin Li 		return false;
372*2b54f0dbSXin Li 	}
373*2b54f0dbSXin Li }
374*2b54f0dbSXin Li 
cpuinfo_linux_detect_thread_siblings(uint32_t max_processors_count,uint32_t processor,cpuinfo_siblings_callback callback,void * context)375*2b54f0dbSXin Li bool cpuinfo_linux_detect_thread_siblings(
376*2b54f0dbSXin Li 	uint32_t max_processors_count,
377*2b54f0dbSXin Li 	uint32_t processor,
378*2b54f0dbSXin Li 	cpuinfo_siblings_callback callback,
379*2b54f0dbSXin Li 	void* context)
380*2b54f0dbSXin Li {
381*2b54f0dbSXin Li 	char thread_siblings_filename[THREAD_SIBLINGS_FILENAME_SIZE];
382*2b54f0dbSXin Li 	const int chars_formatted = snprintf(
383*2b54f0dbSXin Li 		thread_siblings_filename, THREAD_SIBLINGS_FILENAME_SIZE, THREAD_SIBLINGS_FILENAME_FORMAT, processor);
384*2b54f0dbSXin Li 	if ((unsigned int) chars_formatted >= THREAD_SIBLINGS_FILENAME_SIZE) {
385*2b54f0dbSXin Li 		cpuinfo_log_warning("failed to format filename for thread siblings of processor %"PRIu32, processor);
386*2b54f0dbSXin Li 		return false;
387*2b54f0dbSXin Li 	}
388*2b54f0dbSXin Li 
389*2b54f0dbSXin Li 	struct siblings_context siblings_context = {
390*2b54f0dbSXin Li 		.group_name = "core",
391*2b54f0dbSXin Li 		.max_processors_count = max_processors_count,
392*2b54f0dbSXin Li 		.processor = processor,
393*2b54f0dbSXin Li 		.callback = callback,
394*2b54f0dbSXin Li 		.callback_context = context,
395*2b54f0dbSXin Li 	};
396*2b54f0dbSXin Li 	if (cpuinfo_linux_parse_cpulist(thread_siblings_filename,
397*2b54f0dbSXin Li 		(cpuinfo_cpulist_callback) siblings_parser, &siblings_context))
398*2b54f0dbSXin Li 	{
399*2b54f0dbSXin Li 		return true;
400*2b54f0dbSXin Li 	} else {
401*2b54f0dbSXin Li 		cpuinfo_log_info("failed to parse the list of thread siblings for processor %"PRIu32" from %s",
402*2b54f0dbSXin Li 			processor, thread_siblings_filename);
403*2b54f0dbSXin Li 		return false;
404*2b54f0dbSXin Li 	}
405*2b54f0dbSXin Li }
406*2b54f0dbSXin Li 
407