• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <math.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include <emscripten/threading.h>
8 
9 #include <cpuinfo.h>
10 #include <cpuinfo/internal-api.h>
11 #include <cpuinfo/log.h>
12 
13 static const volatile float infinity = INFINITY;
14 
15 static struct cpuinfo_package static_package = {};
16 
17 static struct cpuinfo_cache static_x86_l3 = {
18 	.size = 2 * 1024 * 1024,
19 	.associativity = 16,
20 	.sets = 2048,
21 	.partitions = 1,
22 	.line_size = 64,
23 };
24 
cpuinfo_emscripten_init(void)25 void cpuinfo_emscripten_init(void) {
26 	struct cpuinfo_processor* processors = NULL;
27 	struct cpuinfo_core* cores = NULL;
28 	struct cpuinfo_cluster* clusters = NULL;
29 	struct cpuinfo_cache* l1i = NULL;
30 	struct cpuinfo_cache* l1d = NULL;
31 	struct cpuinfo_cache* l2 = NULL;
32 
33 	const bool is_x86 = signbit(infinity - infinity);
34 
35 	int logical_cores_count = emscripten_num_logical_cores();
36 	if (logical_cores_count <= 0) {
37 		logical_cores_count = 1;
38 	}
39 	uint32_t processor_count = (uint32_t)logical_cores_count;
40 	uint32_t core_count = processor_count;
41 	uint32_t cluster_count = 1;
42 	uint32_t big_cluster_core_count = core_count;
43 	uint32_t processors_per_core = 1;
44 	if (is_x86) {
45 		if (processor_count % 2 == 0) {
46 			processors_per_core = 2;
47 			core_count = processor_count / 2;
48 			big_cluster_core_count = core_count;
49 		}
50 	} else {
51 		/* Assume ARM/ARM64 */
52 		if (processor_count > 4) {
53 			/* Assume big.LITTLE architecture */
54 			cluster_count = 2;
55 			big_cluster_core_count = processor_count >= 8 ? 4 : 2;
56 		}
57 	}
58 	uint32_t l2_count = is_x86 ? core_count : cluster_count;
59 
60 	processors = calloc(processor_count, sizeof(struct cpuinfo_processor));
61 	if (processors == NULL) {
62 		cpuinfo_log_error(
63 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " logical processors",
64 			processor_count * sizeof(struct cpuinfo_processor),
65 			processor_count);
66 		goto cleanup;
67 	}
68 	cores = calloc(processor_count, sizeof(struct cpuinfo_core));
69 	if (cores == NULL) {
70 		cpuinfo_log_error(
71 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " cores",
72 			processor_count * sizeof(struct cpuinfo_core),
73 			processor_count);
74 		goto cleanup;
75 	}
76 	clusters = calloc(cluster_count, sizeof(struct cpuinfo_cluster));
77 	if (clusters == NULL) {
78 		cpuinfo_log_error(
79 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " clusters",
80 			cluster_count * sizeof(struct cpuinfo_cluster),
81 			cluster_count);
82 		goto cleanup;
83 	}
84 
85 	l1i = calloc(core_count, sizeof(struct cpuinfo_cache));
86 	if (l1i == NULL) {
87 		cpuinfo_log_error(
88 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " L1I caches",
89 			core_count * sizeof(struct cpuinfo_cache),
90 			core_count);
91 		goto cleanup;
92 	}
93 
94 	l1d = calloc(core_count, sizeof(struct cpuinfo_cache));
95 	if (l1d == NULL) {
96 		cpuinfo_log_error(
97 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " L1D caches",
98 			core_count * sizeof(struct cpuinfo_cache),
99 			core_count);
100 		goto cleanup;
101 	}
102 
103 	l2 = calloc(l2_count, sizeof(struct cpuinfo_cache));
104 	if (l2 == NULL) {
105 		cpuinfo_log_error(
106 			"failed to allocate %zu bytes for descriptions of %" PRIu32 " L2 caches",
107 			l2_count * sizeof(struct cpuinfo_cache),
108 			l2_count);
109 		goto cleanup;
110 	}
111 
112 	static_package.processor_count = processor_count;
113 	static_package.core_count = core_count;
114 	static_package.cluster_count = cluster_count;
115 	if (is_x86) {
116 		strncpy(static_package.name, "x86 vCPU", CPUINFO_PACKAGE_NAME_MAX);
117 	} else {
118 		strncpy(static_package.name, "ARM vCPU", CPUINFO_PACKAGE_NAME_MAX);
119 	}
120 
121 	for (uint32_t i = 0; i < core_count; i++) {
122 		for (uint32_t j = 0; j < processors_per_core; j++) {
123 			processors[i * processors_per_core + j] = (struct cpuinfo_processor){
124 				.smt_id = j,
125 				.core = cores + i,
126 				.cluster = clusters + (uint32_t)(i >= big_cluster_core_count),
127 				.package = &static_package,
128 				.cache.l1i = l1i + i,
129 				.cache.l1d = l1d + i,
130 				.cache.l2 = is_x86 ? l2 + i : l2 + (uint32_t)(i >= big_cluster_core_count),
131 				.cache.l3 = is_x86 ? &static_x86_l3 : NULL,
132 			};
133 		}
134 
135 		cores[i] = (struct cpuinfo_core){
136 			.processor_start = i * processors_per_core,
137 			.processor_count = processors_per_core,
138 			.core_id = i,
139 			.cluster = clusters + (uint32_t)(i >= big_cluster_core_count),
140 			.package = &static_package,
141 			.vendor = cpuinfo_vendor_unknown,
142 			.uarch = cpuinfo_uarch_unknown,
143 			.frequency = 0,
144 		};
145 
146 		l1i[i] = (struct cpuinfo_cache){
147 			.size = 32 * 1024,
148 			.associativity = 4,
149 			.sets = 128,
150 			.partitions = 1,
151 			.line_size = 64,
152 			.processor_start = i * processors_per_core,
153 			.processor_count = processors_per_core,
154 		};
155 
156 		l1d[i] = (struct cpuinfo_cache){
157 			.size = 32 * 1024,
158 			.associativity = 4,
159 			.sets = 128,
160 			.partitions = 1,
161 			.line_size = 64,
162 			.processor_start = i * processors_per_core,
163 			.processor_count = processors_per_core,
164 		};
165 
166 		if (is_x86) {
167 			l2[i] = (struct cpuinfo_cache){
168 				.size = 256 * 1024,
169 				.associativity = 8,
170 				.sets = 512,
171 				.partitions = 1,
172 				.line_size = 64,
173 				.processor_start = i * processors_per_core,
174 				.processor_count = processors_per_core,
175 			};
176 		}
177 	}
178 
179 	if (is_x86) {
180 		clusters[0] = (struct cpuinfo_cluster){
181 			.processor_start = 0,
182 			.processor_count = processor_count,
183 			.core_start = 0,
184 			.core_count = core_count,
185 			.cluster_id = 0,
186 			.package = &static_package,
187 			.vendor = cpuinfo_vendor_unknown,
188 			.uarch = cpuinfo_uarch_unknown,
189 			.frequency = 0,
190 		};
191 
192 		static_x86_l3.processor_count = processor_count;
193 	} else {
194 		clusters[0] = (struct cpuinfo_cluster){
195 			.processor_start = 0,
196 			.processor_count = big_cluster_core_count,
197 			.core_start = 0,
198 			.core_count = big_cluster_core_count,
199 			.cluster_id = 0,
200 			.package = &static_package,
201 			.vendor = cpuinfo_vendor_unknown,
202 			.uarch = cpuinfo_uarch_unknown,
203 			.frequency = 0,
204 		};
205 
206 		l2[0] = (struct cpuinfo_cache){
207 			.size = 1024 * 1024,
208 			.associativity = 8,
209 			.sets = 2048,
210 			.partitions = 1,
211 			.line_size = 64,
212 			.processor_start = 0,
213 			.processor_count = big_cluster_core_count,
214 		};
215 
216 		if (cluster_count > 1) {
217 			l2[1] = (struct cpuinfo_cache){
218 				.size = 256 * 1024,
219 				.associativity = 8,
220 				.sets = 512,
221 				.partitions = 1,
222 				.line_size = 64,
223 				.processor_start = big_cluster_core_count,
224 				.processor_count = processor_count - big_cluster_core_count,
225 			};
226 
227 			clusters[1] = (struct cpuinfo_cluster){
228 				.processor_start = big_cluster_core_count,
229 				.processor_count = processor_count - big_cluster_core_count,
230 				.core_start = big_cluster_core_count,
231 				.core_count = processor_count - big_cluster_core_count,
232 				.cluster_id = 1,
233 				.package = &static_package,
234 				.vendor = cpuinfo_vendor_unknown,
235 				.uarch = cpuinfo_uarch_unknown,
236 				.frequency = 0,
237 			};
238 		}
239 	}
240 
241 	/* Commit changes */
242 	cpuinfo_cache[cpuinfo_cache_level_1i] = l1i;
243 	cpuinfo_cache[cpuinfo_cache_level_1d] = l1d;
244 	cpuinfo_cache[cpuinfo_cache_level_2] = l2;
245 	if (is_x86) {
246 		cpuinfo_cache[cpuinfo_cache_level_3] = &static_x86_l3;
247 	}
248 
249 	cpuinfo_processors = processors;
250 	cpuinfo_cores = cores;
251 	cpuinfo_clusters = clusters;
252 	cpuinfo_packages = &static_package;
253 
254 	cpuinfo_cache_count[cpuinfo_cache_level_1i] = processor_count;
255 	cpuinfo_cache_count[cpuinfo_cache_level_1d] = processor_count;
256 	cpuinfo_cache_count[cpuinfo_cache_level_2] = l2_count;
257 	if (is_x86) {
258 		cpuinfo_cache_count[cpuinfo_cache_level_3] = 1;
259 	}
260 
261 	cpuinfo_global_uarch = (struct cpuinfo_uarch_info){
262 		.uarch = cpuinfo_uarch_unknown,
263 		.processor_count = processor_count,
264 		.core_count = core_count,
265 	};
266 
267 	cpuinfo_processors_count = processor_count;
268 	cpuinfo_cores_count = processor_count;
269 	cpuinfo_clusters_count = cluster_count;
270 	cpuinfo_packages_count = 1;
271 
272 	cpuinfo_max_cache_size = is_x86 ? 128 * 1024 * 1024 : 8 * 1024 * 1024;
273 
274 	cpuinfo_is_initialized = true;
275 
276 	processors = NULL;
277 	cores = NULL;
278 	clusters = NULL;
279 	l1i = l1d = l2 = NULL;
280 
281 cleanup:
282 	free(processors);
283 	free(cores);
284 	free(clusters);
285 	free(l1i);
286 	free(l1d);
287 	free(l2);
288 }
289