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