remove extra parentheses in return statement
[dpdk.git] / examples / ip_pipeline / cpu_core_map.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include <rte_lcore.h>
40
41 #include "cpu_core_map.h"
42
43 struct cpu_core_map {
44         uint32_t n_max_sockets;
45         uint32_t n_max_cores_per_socket;
46         uint32_t n_max_ht_per_core;
47         uint32_t n_sockets;
48         uint32_t n_cores_per_socket;
49         uint32_t n_ht_per_core;
50         int map[0];
51 };
52
53 static inline uint32_t
54 cpu_core_map_pos(struct cpu_core_map *map,
55         uint32_t socket_id,
56         uint32_t core_id,
57         uint32_t ht_id)
58 {
59         return (socket_id * map->n_max_cores_per_socket + core_id) *
60                 map->n_max_ht_per_core + ht_id;
61 }
62
63 static int
64 cpu_core_map_compute_eal(struct cpu_core_map *map);
65
66 static int
67 cpu_core_map_compute_linux(struct cpu_core_map *map);
68
69 static int
70 cpu_core_map_compute_and_check(struct cpu_core_map *map);
71
72 struct cpu_core_map *
73 cpu_core_map_init(uint32_t n_max_sockets,
74         uint32_t n_max_cores_per_socket,
75         uint32_t n_max_ht_per_core,
76         uint32_t eal_initialized)
77 {
78         uint32_t map_size, map_mem_size, i;
79         struct cpu_core_map *map;
80         int status;
81
82         /* Check input arguments */
83         if ((n_max_sockets == 0) ||
84                 (n_max_cores_per_socket == 0) ||
85                 (n_max_ht_per_core == 0))
86                 return NULL;
87
88         /* Memory allocation */
89         map_size = n_max_sockets * n_max_cores_per_socket * n_max_ht_per_core;
90         map_mem_size = sizeof(struct cpu_core_map) + map_size * sizeof(int);
91         map = (struct cpu_core_map *) malloc(map_mem_size);
92         if (map == NULL)
93                 return NULL;
94
95         /* Initialization */
96         map->n_max_sockets = n_max_sockets;
97         map->n_max_cores_per_socket = n_max_cores_per_socket;
98         map->n_max_ht_per_core = n_max_ht_per_core;
99         map->n_sockets = 0;
100         map->n_cores_per_socket = 0;
101         map->n_ht_per_core = 0;
102
103         for (i = 0; i < map_size; i++)
104                 map->map[i] = -1;
105
106         status = (eal_initialized) ?
107                 cpu_core_map_compute_eal(map) :
108                 cpu_core_map_compute_linux(map);
109
110         if (status) {
111                 free(map);
112                 return NULL;
113         }
114
115         status = cpu_core_map_compute_and_check(map);
116         if (status) {
117                 free(map);
118                 return NULL;
119         }
120
121         return map;
122 }
123
124 int
125 cpu_core_map_compute_eal(struct cpu_core_map *map)
126 {
127         uint32_t socket_id, core_id, ht_id;
128
129         /* Compute map */
130         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
131                 uint32_t n_detected, core_id_contig;
132                 int lcore_id;
133
134                 n_detected = 0;
135                 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
136                         struct lcore_config *p = &lcore_config[lcore_id];
137
138                         if ((p->detected) && (p->socket_id == socket_id))
139                                 n_detected++;
140                 }
141
142                 core_id_contig = 0;
143
144                 for (core_id = 0; n_detected ; core_id++) {
145                         ht_id = 0;
146
147                         for (lcore_id = 0;
148                                 lcore_id < RTE_MAX_LCORE;
149                                 lcore_id++) {
150                                 struct lcore_config *p =
151                                         &lcore_config[lcore_id];
152
153                                 if ((p->detected) &&
154                                         (p->socket_id == socket_id) &&
155                                         (p->core_id == core_id)) {
156                                         uint32_t pos = cpu_core_map_pos(map,
157                                                 socket_id,
158                                                 core_id_contig,
159                                                 ht_id);
160
161                                         map->map[pos] = lcore_id;
162                                         ht_id++;
163                                         n_detected--;
164                                 }
165                         }
166
167                         if (ht_id) {
168                                 core_id_contig++;
169                                 if (core_id_contig ==
170                                         map->n_max_cores_per_socket)
171                                         return -1;
172                         }
173                 }
174         }
175
176         return 0;
177 }
178
179 int
180 cpu_core_map_compute_and_check(struct cpu_core_map *map)
181 {
182         uint32_t socket_id, core_id, ht_id;
183
184         /* Compute n_ht_per_core, n_cores_per_socket, n_sockets */
185         for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) {
186                 if (map->map[ht_id] == -1)
187                         break;
188
189                 map->n_ht_per_core++;
190         }
191
192         if (map->n_ht_per_core == 0)
193                 return -1;
194
195         for (core_id = 0; core_id < map->n_max_cores_per_socket; core_id++) {
196                 uint32_t pos = core_id * map->n_max_ht_per_core;
197
198                 if (map->map[pos] == -1)
199                         break;
200
201                 map->n_cores_per_socket++;
202         }
203
204         if (map->n_cores_per_socket == 0)
205                 return -1;
206
207         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
208                 uint32_t pos = socket_id * map->n_max_cores_per_socket *
209                         map->n_max_ht_per_core;
210
211                 if (map->map[pos] == -1)
212                         break;
213
214                 map->n_sockets++;
215         }
216
217         if (map->n_sockets == 0)
218                 return -1;
219
220         /* Check that each socket has exactly the same number of cores
221         and that each core has exactly the same number of hyper-threads */
222         for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
223                 for (core_id = 0; core_id < map->n_cores_per_socket; core_id++)
224                         for (ht_id = 0;
225                                 ht_id < map->n_max_ht_per_core;
226                                 ht_id++) {
227                                 uint32_t pos = (socket_id *
228                                         map->n_max_cores_per_socket + core_id) *
229                                         map->n_max_ht_per_core + ht_id;
230
231                                 if (((ht_id < map->n_ht_per_core) &&
232                                         (map->map[pos] == -1)) ||
233                                         ((ht_id >= map->n_ht_per_core) &&
234                                         (map->map[pos] != -1)))
235                                         return -1;
236                         }
237
238                 for ( ; core_id < map->n_max_cores_per_socket; core_id++)
239                         for (ht_id = 0;
240                                 ht_id < map->n_max_ht_per_core;
241                                 ht_id++) {
242                                 uint32_t pos = cpu_core_map_pos(map,
243                                         socket_id,
244                                         core_id,
245                                         ht_id);
246
247                                 if (map->map[pos] != -1)
248                                         return -1;
249                         }
250         }
251
252         return 0;
253 }
254
255 #define FILE_LINUX_CPU_N_LCORES \
256         "/sys/devices/system/cpu/present"
257
258 static int
259 cpu_core_map_get_n_lcores_linux(void)
260 {
261         char buffer[64], *string;
262         FILE *fd;
263
264         fd = fopen(FILE_LINUX_CPU_N_LCORES, "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         string = index(buffer, '-');
276         if (string == NULL)
277                 return -1;
278
279         return atoi(++string) + 1;
280 }
281
282 #define FILE_LINUX_CPU_CORE_ID \
283         "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/core_id"
284
285 static int
286 cpu_core_map_get_core_id_linux(int lcore_id)
287 {
288         char buffer[64];
289         FILE *fd;
290         int core_id;
291
292         snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_CORE_ID, lcore_id);
293         fd = fopen(buffer, "r");
294         if (fd == NULL)
295                 return -1;
296
297         if (fgets(buffer, sizeof(buffer), fd) == NULL) {
298                 fclose(fd);
299                 return -1;
300         }
301
302         fclose(fd);
303
304         core_id = atoi(buffer);
305         return core_id;
306 }
307
308 #define FILE_LINUX_CPU_SOCKET_ID \
309         "/sys/devices/system/cpu/cpu%" PRIu32 "/topology/physical_package_id"
310
311 static int
312 cpu_core_map_get_socket_id_linux(int lcore_id)
313 {
314         char buffer[64];
315         FILE *fd;
316         int socket_id;
317
318         snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_SOCKET_ID, lcore_id);
319         fd = fopen(buffer, "r");
320         if (fd == NULL)
321                 return -1;
322
323         if (fgets(buffer, sizeof(buffer), fd) == NULL) {
324                 fclose(fd);
325                 return -1;
326         }
327
328         fclose(fd);
329
330         socket_id = atoi(buffer);
331         return socket_id;
332 }
333
334 int
335 cpu_core_map_compute_linux(struct cpu_core_map *map)
336 {
337         uint32_t socket_id, core_id, ht_id;
338         int n_lcores;
339
340         n_lcores = cpu_core_map_get_n_lcores_linux();
341         if (n_lcores <= 0)
342                 return -1;
343
344         /* Compute map */
345         for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) {
346                 uint32_t n_detected, core_id_contig;
347                 int lcore_id;
348
349                 n_detected = 0;
350                 for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
351                         int lcore_socket_id =
352                                 cpu_core_map_get_socket_id_linux(lcore_id);
353
354                         if (lcore_socket_id < 0)
355                                 return -1;
356
357                         if (((uint32_t) lcore_socket_id) == socket_id)
358                                 n_detected++;
359                 }
360
361                 core_id_contig = 0;
362
363                 for (core_id = 0; n_detected ; core_id++) {
364                         ht_id = 0;
365
366                         for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) {
367                                 int lcore_socket_id =
368                                         cpu_core_map_get_socket_id_linux(
369                                         lcore_id);
370
371                                 if (lcore_socket_id < 0)
372                                         return -1;
373
374                                 int lcore_core_id =
375                                         cpu_core_map_get_core_id_linux(
376                                                 lcore_id);
377
378                                 if (lcore_core_id < 0)
379                                         return -1;
380
381                                 if (((uint32_t) lcore_socket_id == socket_id) &&
382                                         ((uint32_t) lcore_core_id == core_id)) {
383                                         uint32_t pos = cpu_core_map_pos(map,
384                                                 socket_id,
385                                                 core_id_contig,
386                                                 ht_id);
387
388                                         map->map[pos] = lcore_id;
389                                         ht_id++;
390                                         n_detected--;
391                                 }
392                         }
393
394                         if (ht_id) {
395                                 core_id_contig++;
396                                 if (core_id_contig ==
397                                         map->n_max_cores_per_socket)
398                                         return -1;
399                         }
400                 }
401         }
402
403         return 0;
404 }
405
406 void
407 cpu_core_map_print(struct cpu_core_map *map)
408 {
409         uint32_t socket_id, core_id, ht_id;
410
411         if (map == NULL)
412                 return;
413
414         for (socket_id = 0; socket_id < map->n_sockets; socket_id++) {
415                 printf("Socket %" PRIu32 ":\n", socket_id);
416
417                 for (core_id = 0;
418                         core_id < map->n_cores_per_socket;
419                         core_id++) {
420                         printf("[%" PRIu32 "] = [", core_id);
421
422                         for (ht_id = 0; ht_id < map->n_ht_per_core; ht_id++) {
423                                 int lcore_id = cpu_core_map_get_lcore_id(map,
424                                         socket_id,
425                                         core_id,
426                                         ht_id);
427
428                                 uint32_t core_id_noncontig =
429                                         cpu_core_map_get_core_id_linux(
430                                                 lcore_id);
431
432                                 printf(" %" PRId32 " (%" PRIu32 ") ",
433                                         lcore_id,
434                                         core_id_noncontig);
435                         }
436
437                         printf("]\n");
438                 }
439         }
440 }
441
442 uint32_t
443 cpu_core_map_get_n_sockets(struct cpu_core_map *map)
444 {
445         if (map == NULL)
446                 return 0;
447
448         return map->n_sockets;
449 }
450
451 uint32_t
452 cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map)
453 {
454         if (map == NULL)
455                 return 0;
456
457         return map->n_cores_per_socket;
458 }
459
460 uint32_t
461 cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map)
462 {
463         if (map == NULL)
464                 return 0;
465
466         return map->n_ht_per_core;
467 }
468
469 int
470 cpu_core_map_get_lcore_id(struct cpu_core_map *map,
471         uint32_t socket_id,
472         uint32_t core_id,
473         uint32_t ht_id)
474 {
475         uint32_t pos;
476
477         if ((map == NULL) ||
478                 (socket_id >= map->n_sockets) ||
479                 (core_id >= map->n_cores_per_socket) ||
480                 (ht_id >= map->n_ht_per_core))
481                 return -1;
482
483         pos = cpu_core_map_pos(map, socket_id, core_id, ht_id);
484
485         return map->map[pos];
486 }
487
488 void
489 cpu_core_map_free(struct cpu_core_map *map)
490 {
491         free(map);
492 }