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