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