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