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