New upstream version 18.02
[deb_dpdk.git] / examples / ip_pipeline / cpu_core_map.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2015 Intel Corporation
3  */
4
5 #include <inttypes.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <rte_lcore.h>
11
12 #include "cpu_core_map.h"
13
14 struct cpu_core_map {
15         uint32_t n_max_sockets;
16         uint32_t n_max_cores_per_socket;
17         uint32_t n_max_ht_per_core;
18         uint32_t n_sockets;
19         uint32_t n_cores_per_socket;
20         uint32_t n_ht_per_core;
21         int map[0];
22 };
23
24 static inline uint32_t
25 cpu_core_map_pos(struct cpu_core_map *map,
26         uint32_t socket_id,
27         uint32_t core_id,
28         uint32_t ht_id)
29 {
30         return (socket_id * map->n_max_cores_per_socket + core_id) *
31                 map->n_max_ht_per_core + ht_id;
32 }
33
34 static int
35 cpu_core_map_compute_eal(struct cpu_core_map *map);
36
37 static int
38 cpu_core_map_compute_linux(struct cpu_core_map *map);
39
40 static int
41 cpu_core_map_compute_and_check(struct cpu_core_map *map);
42
43 struct cpu_core_map *
44 cpu_core_map_init(uint32_t n_max_sockets,
45         uint32_t n_max_cores_per_socket,
46         uint32_t n_max_ht_per_core,
47         uint32_t eal_initialized)
48 {
49         uint32_t map_size, map_mem_size, i;
50         struct cpu_core_map *map;
51         int status;
52
53         /* Check input arguments */
54         if ((n_max_sockets == 0) ||
55                 (n_max_cores_per_socket == 0) ||
56                 (n_max_ht_per_core == 0))
57                 return NULL;
58
59         /* Memory allocation */
60         map_size = n_max_sockets * n_max_cores_per_socket * n_max_ht_per_core;
61         map_mem_size = sizeof(struct cpu_core_map) + map_size * sizeof(int);
62         map = (struct cpu_core_map *) malloc(map_mem_size);
63         if (map == NULL)
64                 return NULL;
65
66         /* Initialization */
67         map->n_max_sockets = n_max_sockets;
68         map->n_max_cores_per_socket = n_max_cores_per_socket;
69         map->n_max_ht_per_core = n_max_ht_per_core;
70         map->n_sockets = 0;
71         map->n_cores_per_socket = 0;
72         map->n_ht_per_core = 0;
73
74         for (i = 0; i < map_size; i++)
75                 map->map[i] = -1;
76
77         status = (eal_initialized) ?
78                 cpu_core_map_compute_eal(map) :
79                 cpu_core_map_compute_linux(map);
80
81         if (status) {
82                 free(map);
83                 return NULL;
84         }
85
86         status = cpu_core_map_compute_and_check(map);
87         if (status) {
88                 free(map);
89                 return NULL;
90         }
91
92         return map;
93 }
94
95 int
96 cpu_core_map_compute_eal(struct cpu_core_map *map)
97 {
98         uint32_t socket_id, core_id, ht_id;
99
100         /* Compute map */
101         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
102                 uint32_t n_detected, core_id_contig;
103                 int lcore_id;
104
105                 n_detected = 0;
106                 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
107                         struct lcore_config *p = &lcore_config[lcore_id];
108
109                         if ((p->detected) && (p->socket_id == socket_id))
110                                 n_detected++;
111                 }
112
113                 core_id_contig = 0;
114
115                 for (core_id = 0; n_detected ; core_id++) {
116                         ht_id = 0;
117
118                         for (lcore_id = 0;
119                                 lcore_id < RTE_MAX_LCORE;
120                                 lcore_id++) {
121                                 struct lcore_config *p =
122                                         &lcore_config[lcore_id];
123
124                                 if ((p->detected) &&
125                                         (p->socket_id == socket_id) &&
126                                         (p->core_id == core_id)) {
127                                         uint32_t pos = cpu_core_map_pos(map,
128                                                 socket_id,
129                                                 core_id_contig,
130                                                 ht_id);
131
132                                         map->map[pos] = lcore_id;
133                                         ht_id++;
134                                         n_detected--;
135                                 }
136                         }
137
138                         if (ht_id) {
139                                 core_id_contig++;
140                                 if (core_id_contig ==
141                                         map->n_max_cores_per_socket)
142                                         return -1;
143                         }
144                 }
145         }
146
147         return 0;
148 }
149
150 int
151 cpu_core_map_compute_and_check(struct cpu_core_map *map)
152 {
153         uint32_t socket_id, core_id, ht_id;
154
155         /* Compute n_ht_per_core, n_cores_per_socket, n_sockets */
156         for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
157                 if (map->map[ht_id] == -1)
158                         break;
159
160                 map->n_ht_per_core++;
161         }
162
163         if (map->n_ht_per_core == 0)
164                 return -1;
165
166         for (core_id = 0; core_id < map->n_max_cores_per_socket; core_id++) {
167                 uint32_t pos = core_id * map->n_max_ht_per_core;
168
169                 if (map->map[pos] == -1)
170                         break;
171
172                 map->n_cores_per_socket++;
173         }
174
175         if (map->n_cores_per_socket == 0)
176                 return -1;
177
178         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
179                 uint32_t pos = socket_id * map->n_max_cores_per_socket *
180                         map->n_max_ht_per_core;
181
182                 if (map->map[pos] == -1)
183                         break;
184
185                 map->n_sockets++;
186         }
187
188         if (map->n_sockets == 0)
189                 return -1;
190
191         /* Check that each socket has exactly the same number of cores
192         and that each core has exactly the same number of hyper-threads */
193         for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
194                 for (core_id = 0; core_id < map->n_cores_per_socket; core_id++)
195                         for (ht_id = 0;
196                                 ht_id < map->n_max_ht_per_core;
197                                 ht_id++) {
198                                 uint32_t pos = (socket_id *
199                                         map->n_max_cores_per_socket + core_id) *
200                                         map->n_max_ht_per_core + ht_id;
201
202                                 if (((ht_id < map->n_ht_per_core) &&
203                                         (map->map[pos] == -1)) ||
204                                         ((ht_id >= map->n_ht_per_core) &&
205                                         (map->map[pos] != -1)))
206                                         return -1;
207                         }
208
209                 for ( ; core_id < map->n_max_cores_per_socket; core_id++)
210                         for (ht_id = 0;
211                                 ht_id < map->n_max_ht_per_core;
212                                 ht_id++) {
213                                 uint32_t pos = cpu_core_map_pos(map,
214                                         socket_id,
215                                         core_id,
216                                         ht_id);
217
218                                 if (map->map[pos] != -1)
219                                         return -1;
220                         }
221         }
222
223         return 0;
224 }
225
226 #define FILE_LINUX_CPU_N_LCORES \
227         "/sys/devices/system/cpu/present"
228
229 static int
230 cpu_core_map_get_n_lcores_linux(void)
231 {
232         char buffer[64], *string;
233         FILE *fd;
234
235         fd = fopen(FILE_LINUX_CPU_N_LCORES, "r");
236         if (fd == NULL)
237                 return -1;
238
239         if (fgets(buffer, sizeof(buffer), fd) == NULL) {
240                 fclose(fd);
241                 return -1;
242         }
243
244         fclose(fd);
245
246         string = index(buffer, '-');
247         if (string == NULL)
248                 return -1;
249
250         return atoi(++string) + 1;
251 }
252
253 #define FILE_LINUX_CPU_CORE_ID \
254         "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id"
255
256 static int
257 cpu_core_map_get_core_id_linux(int lcore_id)
258 {
259         char buffer[64];
260         FILE *fd;
261         int core_id;
262
263         snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_CORE_ID, lcore_id);
264         fd = fopen(buffer, "r");
265         if (fd == NULL)
266                 return -1;
267
268         if (fgets(buffer, sizeof(buffer), fd) == NULL) {
269                 fclose(fd);
270                 return -1;
271         }
272
273         fclose(fd);
274
275         core_id = atoi(buffer);
276         return core_id;
277 }
278
279 #define FILE_LINUX_CPU_SOCKET_ID \
280         "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/physical_package_id"
281
282 static int
283 cpu_core_map_get_socket_id_linux(int lcore_id)
284 {
285         char buffer[64];
286         FILE *fd;
287         int socket_id;
288
289         snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_SOCKET_ID, lcore_id);
290         fd = fopen(buffer, "r");
291         if (fd == NULL)
292                 return -1;
293
294         if (fgets(buffer, sizeof(buffer), fd) == NULL) {
295                 fclose(fd);
296                 return -1;
297         }
298
299         fclose(fd);
300
301         socket_id = atoi(buffer);
302         return socket_id;
303 }
304
305 int
306 cpu_core_map_compute_linux(struct cpu_core_map *map)
307 {
308         uint32_t socket_id, core_id, ht_id;
309         int n_lcores;
310
311         n_lcores = cpu_core_map_get_n_lcores_linux();
312         if (n_lcores <= 0)
313                 return -1;
314
315         /* Compute map */
316         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
317                 uint32_t n_detected, core_id_contig;
318                 int lcore_id;
319
320                 n_detected = 0;
321                 for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
322                         int lcore_socket_id =
323                                 cpu_core_map_get_socket_id_linux(lcore_id);
324
325 #if !defined(RTE_ARCH_PPC_64)
326                         if (lcore_socket_id < 0)
327                                 return -1;
328 #endif
329
330                         if (((uint32_t) lcore_socket_id) == socket_id)
331                                 n_detected++;
332                 }
333
334                 core_id_contig = 0;
335
336                 for (core_id = 0; n_detected ; core_id++) {
337                         ht_id = 0;
338
339                         for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
340                                 int lcore_socket_id =
341                                         cpu_core_map_get_socket_id_linux(
342                                         lcore_id);
343
344 #if !defined(RTE_ARCH_PPC_64)
345                                 if (lcore_socket_id < 0)
346                                         return -1;
347
348                                 int lcore_core_id =
349                                         cpu_core_map_get_core_id_linux(
350                                                 lcore_id);
351
352                                 if (lcore_core_id < 0)
353                                         return -1;
354 #endif
355
356 #if !defined(RTE_ARCH_PPC_64)
357                                 if (((uint32_t) lcore_socket_id == socket_id) &&
358                                         ((uint32_t) lcore_core_id == core_id)) {
359 #else
360                                 if (((uint32_t) lcore_socket_id == socket_id)) {
361 #endif
362                                         uint32_t pos = cpu_core_map_pos(map,
363                                                 socket_id,
364                                                 core_id_contig,
365                                                 ht_id);
366
367                                         map->map[pos] = lcore_id;
368                                         ht_id++;
369                                         n_detected--;
370                                 }
371                         }
372
373                         if (ht_id) {
374                                 core_id_contig++;
375                                 if (core_id_contig ==
376                                         map->n_max_cores_per_socket)
377                                         return -1;
378                         }
379                 }
380         }
381
382         return 0;
383 }
384
385 void
386 cpu_core_map_print(struct cpu_core_map *map)
387 {
388         uint32_t socket_id, core_id, ht_id;
389
390         if (map == NULL)
391                 return;
392
393         for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
394                 printf("Socket %" PRIu32 ":\n", socket_id);
395
396                 for (core_id = 0;
397                         core_id < map->n_cores_per_socket;
398                         core_id++) {
399                         printf("[%" PRIu32 "] = [", core_id);
400
401                         for (ht_id = 0; ht_id < map->n_ht_per_core; ht_id++) {
402                                 int lcore_id = cpu_core_map_get_lcore_id(map,
403                                         socket_id,
404                                         core_id,
405                                         ht_id);
406
407                                 uint32_t core_id_noncontig =
408                                         cpu_core_map_get_core_id_linux(
409                                                 lcore_id);
410
411                                 printf(" %" PRId32 " (%" PRIu32 ") ",
412                                         lcore_id,
413                                         core_id_noncontig);
414                         }
415
416                         printf("]\n");
417                 }
418         }
419 }
420
421 uint32_t
422 cpu_core_map_get_n_sockets(struct cpu_core_map *map)
423 {
424         if (map == NULL)
425                 return 0;
426
427         return map->n_sockets;
428 }
429
430 uint32_t
431 cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map)
432 {
433         if (map == NULL)
434                 return 0;
435
436         return map->n_cores_per_socket;
437 }
438
439 uint32_t
440 cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map)
441 {
442         if (map == NULL)
443                 return 0;
444
445         return map->n_ht_per_core;
446 }
447
448 int
449 cpu_core_map_get_lcore_id(struct cpu_core_map *map,
450         uint32_t socket_id,
451         uint32_t core_id,
452         uint32_t ht_id)
453 {
454         uint32_t pos;
455
456         if ((map == NULL) ||
457                 (socket_id >= map->n_sockets) ||
458                 (core_id >= map->n_cores_per_socket) ||
459                 (ht_id >= map->n_ht_per_core))
460                 return -1;
461
462         pos = cpu_core_map_pos(map, socket_id, core_id, ht_id);
463
464         return map->map[pos];
465 }
466
467 void
468 cpu_core_map_free(struct cpu_core_map *map)
469 {
470         free(map);
471 }