Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <inttypes.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : :
9 : : #include <rte_common.h>
10 : : #include <rte_branch_prediction.h>
11 : : #include <rte_errno.h>
12 : : #include <rte_lcore.h>
13 : : #include <rte_log.h>
14 : : #ifndef RTE_EXEC_ENV_WINDOWS
15 : : #include <rte_telemetry.h>
16 : : #endif
17 : :
18 : : #include "eal_private.h"
19 : : #include "eal_thread.h"
20 : :
21 : 2173 : unsigned int rte_get_main_lcore(void)
22 : : {
23 : 2173 : return rte_eal_get_configuration()->main_lcore;
24 : : }
25 : :
26 : 12767 : unsigned int rte_lcore_count(void)
27 : : {
28 : 12767 : return rte_eal_get_configuration()->lcore_count;
29 : : }
30 : :
31 : 0 : int rte_lcore_index(int lcore_id)
32 : : {
33 [ # # ]: 0 : if (unlikely(lcore_id >= RTE_MAX_LCORE))
34 : : return -1;
35 : :
36 [ # # ]: 0 : if (lcore_id < 0) {
37 [ # # ]: 0 : if (rte_lcore_id() == LCORE_ID_ANY)
38 : : return -1;
39 : :
40 : 0 : lcore_id = (int)rte_lcore_id();
41 : : }
42 : :
43 : 0 : return lcore_config[lcore_id].core_index;
44 : : }
45 : :
46 : 0 : int rte_lcore_to_cpu_id(int lcore_id)
47 : : {
48 [ # # ]: 0 : if (unlikely(lcore_id >= RTE_MAX_LCORE))
49 : : return -1;
50 : :
51 [ # # ]: 0 : if (lcore_id < 0) {
52 [ # # ]: 0 : if (rte_lcore_id() == LCORE_ID_ANY)
53 : : return -1;
54 : :
55 : 0 : lcore_id = (int)rte_lcore_id();
56 : : }
57 : :
58 : 0 : return lcore_config[lcore_id].core_id;
59 : : }
60 : :
61 : 0 : rte_cpuset_t rte_lcore_cpuset(unsigned int lcore_id)
62 : : {
63 : 0 : return lcore_config[lcore_id].cpuset;
64 : : }
65 : :
66 : : enum rte_lcore_role_t
67 : 1 : rte_eal_lcore_role(unsigned int lcore_id)
68 : : {
69 : 1 : struct rte_config *cfg = rte_eal_get_configuration();
70 : :
71 [ + - ]: 1 : if (lcore_id >= RTE_MAX_LCORE)
72 : : return ROLE_OFF;
73 : 1 : return cfg->lcore_role[lcore_id];
74 : : }
75 : :
76 : : int
77 : 24448 : rte_lcore_has_role(unsigned int lcore_id, enum rte_lcore_role_t role)
78 : : {
79 : 24448 : struct rte_config *cfg = rte_eal_get_configuration();
80 : :
81 [ + - ]: 24448 : if (lcore_id >= RTE_MAX_LCORE)
82 : : return -EINVAL;
83 : :
84 : 24448 : return cfg->lcore_role[lcore_id] == role;
85 : : }
86 : :
87 : 71818271 : int rte_lcore_is_enabled(unsigned int lcore_id)
88 : : {
89 : 71818271 : struct rte_config *cfg = rte_eal_get_configuration();
90 : :
91 [ + - ]: 71802014 : if (lcore_id >= RTE_MAX_LCORE)
92 : : return 0;
93 : 71802014 : return cfg->lcore_role[lcore_id] == ROLE_RTE;
94 : : }
95 : :
96 : 1124373 : unsigned int rte_get_next_lcore(unsigned int i, int skip_main, int wrap)
97 : : {
98 : 1124373 : i++;
99 [ + + ]: 1124373 : if (wrap)
100 : 1122263 : i %= RTE_MAX_LCORE;
101 : :
102 [ + + ]: 71949486 : while (i < RTE_MAX_LCORE) {
103 [ + + + + ]: 71948427 : if (!rte_lcore_is_enabled(i) ||
104 [ + + ]: 1751 : (skip_main && (i == rte_get_main_lcore()))) {
105 : 70825113 : i++;
106 [ + + ]: 70825113 : if (wrap)
107 : 70690467 : i %= RTE_MAX_LCORE;
108 : 70825113 : continue;
109 : : }
110 : : break;
111 : : }
112 : 1135362 : return i;
113 : : }
114 : :
115 : : unsigned int
116 : 265 : rte_lcore_to_socket_id(unsigned int lcore_id)
117 : : {
118 : 265 : return lcore_config[lcore_id].socket_id;
119 : : }
120 : :
121 : : static int
122 : 125960 : socket_id_cmp(const void *a, const void *b)
123 : : {
124 : : const int *lcore_id_a = a;
125 : : const int *lcore_id_b = b;
126 : :
127 [ + + ]: 125960 : if (*lcore_id_a < *lcore_id_b)
128 : : return -1;
129 [ + + ]: 124080 : if (*lcore_id_a > *lcore_id_b)
130 : 26320 : return 1;
131 : : return 0;
132 : : }
133 : :
134 : : /*
135 : : * Parse /sys/devices/system/cpu to get the number of physical and logical
136 : : * processors on the machine. The function will fill the cpu_info
137 : : * structure.
138 : : */
139 : : int
140 : 235 : rte_eal_cpu_init(void)
141 : : {
142 : : /* pointer to global configuration */
143 : 235 : struct rte_config *config = rte_eal_get_configuration();
144 : : unsigned lcore_id;
145 : : unsigned count = 0;
146 : : unsigned int socket_id, prev_socket_id;
147 : : int lcore_to_socket_id[RTE_MAX_LCORE];
148 : :
149 : : /*
150 : : * Parse the maximum set of logical cores, detect the subset of running
151 : : * ones and enable them by default.
152 : : */
153 [ + + ]: 30315 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
154 : 30080 : lcore_config[lcore_id].core_index = count;
155 : :
156 : : /* init cpuset for per lcore config */
157 : 30080 : CPU_ZERO(&lcore_config[lcore_id].cpuset);
158 : :
159 : : /* find socket first */
160 : 30080 : socket_id = eal_cpu_socket_id(lcore_id);
161 : 30080 : lcore_to_socket_id[lcore_id] = socket_id;
162 : :
163 [ + + ]: 30080 : if (eal_cpu_detected(lcore_id) == 0) {
164 : 26320 : config->lcore_role[lcore_id] = ROLE_OFF;
165 : 26320 : lcore_config[lcore_id].core_index = -1;
166 : 26320 : continue;
167 : : }
168 : :
169 : : /* By default, lcore 1:1 map to cpu id */
170 : 3760 : CPU_SET(lcore_id, &lcore_config[lcore_id].cpuset);
171 : :
172 : : /* By default, each detected core is enabled */
173 : 3760 : config->lcore_role[lcore_id] = ROLE_RTE;
174 : 3760 : lcore_config[lcore_id].core_role = ROLE_RTE;
175 : 3760 : lcore_config[lcore_id].core_id = eal_cpu_core_id(lcore_id);
176 : 3760 : lcore_config[lcore_id].socket_id = socket_id;
177 : 3760 : EAL_LOG(DEBUG, "Detected lcore %u as "
178 : : "core %u on socket %u",
179 : : lcore_id, lcore_config[lcore_id].core_id,
180 : : lcore_config[lcore_id].socket_id);
181 : 3760 : count++;
182 : : }
183 [ + + ]: 210795 : for (; lcore_id < CPU_SETSIZE; lcore_id++) {
184 [ + - ]: 210560 : if (eal_cpu_detected(lcore_id) == 0)
185 : 210560 : continue;
186 : 0 : EAL_LOG(DEBUG, "Skipped lcore %u as core %u on socket %u",
187 : : lcore_id, eal_cpu_core_id(lcore_id),
188 : : eal_cpu_socket_id(lcore_id));
189 : : }
190 : :
191 : : /* Set the count of enabled logical cores of the EAL configuration */
192 : 235 : config->lcore_count = count;
193 : 235 : EAL_LOG(DEBUG,
194 : : "Maximum logical cores by configuration: %u",
195 : : RTE_MAX_LCORE);
196 : 235 : EAL_LOG(INFO, "Detected CPU lcores: %u", config->lcore_count);
197 : :
198 : : /* sort all socket id's in ascending order */
199 : 235 : qsort(lcore_to_socket_id, RTE_DIM(lcore_to_socket_id),
200 : : sizeof(lcore_to_socket_id[0]), socket_id_cmp);
201 : :
202 : : prev_socket_id = -1;
203 : 235 : config->numa_node_count = 0;
204 [ + + ]: 30315 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
205 : 30080 : socket_id = lcore_to_socket_id[lcore_id];
206 [ + + ]: 30080 : if (socket_id != prev_socket_id)
207 : 470 : config->numa_nodes[config->numa_node_count++] =
208 : : socket_id;
209 : : prev_socket_id = socket_id;
210 : : }
211 : 235 : EAL_LOG(INFO, "Detected NUMA nodes: %u", config->numa_node_count);
212 : :
213 : 235 : return 0;
214 : : }
215 : :
216 : : unsigned int
217 : 1019 : rte_socket_count(void)
218 : : {
219 : 1019 : const struct rte_config *config = rte_eal_get_configuration();
220 : 1019 : return config->numa_node_count;
221 : : }
222 : :
223 : : int
224 : 82988 : rte_socket_id_by_idx(unsigned int idx)
225 : : {
226 : 82988 : const struct rte_config *config = rte_eal_get_configuration();
227 [ + + ]: 82988 : if (idx >= config->numa_node_count) {
228 : 10 : rte_errno = EINVAL;
229 : 10 : return -1;
230 : : }
231 : 82978 : return config->numa_nodes[idx];
232 : : }
233 : :
234 : : static rte_rwlock_t lcore_lock = RTE_RWLOCK_INITIALIZER;
235 : : struct lcore_callback {
236 : : TAILQ_ENTRY(lcore_callback) next;
237 : : char *name;
238 : : rte_lcore_init_cb init;
239 : : rte_lcore_uninit_cb uninit;
240 : : void *arg;
241 : : };
242 : : static TAILQ_HEAD(lcore_callbacks_head, lcore_callback) lcore_callbacks =
243 : : TAILQ_HEAD_INITIALIZER(lcore_callbacks);
244 : :
245 : : static int
246 : 12 : callback_init(struct lcore_callback *callback, unsigned int lcore_id)
247 : : {
248 [ + - ]: 12 : if (callback->init == NULL)
249 : : return 0;
250 : 12 : EAL_LOG(DEBUG, "Call init for lcore callback %s, lcore_id %u",
251 : : callback->name, lcore_id);
252 : 12 : return callback->init(lcore_id, callback->arg);
253 : : }
254 : :
255 : : static void
256 : 10 : callback_uninit(struct lcore_callback *callback, unsigned int lcore_id)
257 : : {
258 [ + - ]: 10 : if (callback->uninit == NULL)
259 : : return;
260 : 10 : EAL_LOG(DEBUG, "Call uninit for lcore callback %s, lcore_id %u",
261 : : callback->name, lcore_id);
262 : 10 : callback->uninit(lcore_id, callback->arg);
263 : : }
264 : :
265 : : static void
266 : : free_callback(struct lcore_callback *callback)
267 : : {
268 : 4 : free(callback->name);
269 : 4 : free(callback);
270 : 3 : }
271 : :
272 : : void *
273 : 4 : rte_lcore_callback_register(const char *name, rte_lcore_init_cb init,
274 : : rte_lcore_uninit_cb uninit, void *arg)
275 : : {
276 : 4 : struct rte_config *cfg = rte_eal_get_configuration();
277 : : struct lcore_callback *callback;
278 : : unsigned int lcore_id;
279 : :
280 [ + - ]: 4 : if (name == NULL)
281 : : return NULL;
282 : 4 : callback = calloc(1, sizeof(*callback));
283 [ + - ]: 4 : if (callback == NULL)
284 : : return NULL;
285 [ - + ]: 4 : if (asprintf(&callback->name, "%s-%p", name, arg) == -1) {
286 : 0 : free(callback);
287 : 0 : return NULL;
288 : : }
289 : 4 : callback->init = init;
290 : 4 : callback->uninit = uninit;
291 : 4 : callback->arg = arg;
292 : 4 : rte_rwlock_write_lock(&lcore_lock);
293 [ - + ]: 4 : if (callback->init == NULL)
294 : 0 : goto no_init;
295 [ + + ]: 389 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
296 [ + + ]: 386 : if (cfg->lcore_role[lcore_id] == ROLE_OFF)
297 : 378 : continue;
298 [ + + ]: 8 : if (callback_init(callback, lcore_id) == 0)
299 : 7 : continue;
300 : : /* Callback refused init for this lcore, uninitialize all
301 : : * previous lcore.
302 : : */
303 [ + + ]: 2 : while (lcore_id-- != 0) {
304 [ - + ]: 1 : if (cfg->lcore_role[lcore_id] == ROLE_OFF)
305 : 0 : continue;
306 : 1 : callback_uninit(callback, lcore_id);
307 : : }
308 : : free_callback(callback);
309 : : callback = NULL;
310 : 1 : goto out;
311 : : }
312 : 3 : no_init:
313 : 3 : TAILQ_INSERT_TAIL(&lcore_callbacks, callback, next);
314 [ + - + - ]: 9 : EAL_LOG(DEBUG, "Registered new lcore callback %s (%sinit, %suninit).",
315 : : callback->name, callback->init == NULL ? "NO " : "",
316 : : callback->uninit == NULL ? "NO " : "");
317 : 4 : out:
318 : : rte_rwlock_write_unlock(&lcore_lock);
319 : 4 : return callback;
320 : : }
321 : :
322 : : void
323 : 3 : rte_lcore_callback_unregister(void *handle)
324 : : {
325 : 3 : struct rte_config *cfg = rte_eal_get_configuration();
326 : : struct lcore_callback *callback = handle;
327 : : unsigned int lcore_id;
328 : :
329 [ + - ]: 3 : if (callback == NULL)
330 : : return;
331 : 3 : rte_rwlock_write_lock(&lcore_lock);
332 [ - + ]: 3 : if (callback->uninit == NULL)
333 : 0 : goto no_uninit;
334 [ + + ]: 387 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
335 [ + + ]: 384 : if (cfg->lcore_role[lcore_id] == ROLE_OFF)
336 : 378 : continue;
337 : 6 : callback_uninit(callback, lcore_id);
338 : : }
339 : 3 : no_uninit:
340 [ + + ]: 3 : TAILQ_REMOVE(&lcore_callbacks, callback, next);
341 : : rte_rwlock_write_unlock(&lcore_lock);
342 : 3 : EAL_LOG(DEBUG, "Unregistered lcore callback %s-%p.",
343 : : callback->name, callback->arg);
344 : : free_callback(callback);
345 : : }
346 : :
347 : : unsigned int
348 : 129 : eal_lcore_non_eal_allocate(void)
349 : : {
350 : 129 : struct rte_config *cfg = rte_eal_get_configuration();
351 : : struct lcore_callback *callback;
352 : : struct lcore_callback *prev;
353 : : unsigned int lcore_id;
354 : :
355 : 129 : rte_rwlock_write_lock(&lcore_lock);
356 [ + + ]: 8389 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
357 [ + + ]: 8388 : if (cfg->lcore_role[lcore_id] != ROLE_OFF)
358 : : continue;
359 : 128 : cfg->lcore_role[lcore_id] = ROLE_NON_EAL;
360 : 128 : cfg->lcore_count++;
361 : 128 : break;
362 : : }
363 [ + + ]: 129 : if (lcore_id == RTE_MAX_LCORE) {
364 : 1 : EAL_LOG(DEBUG, "No lcore available.");
365 : 1 : goto out;
366 : : }
367 [ + + ]: 131 : TAILQ_FOREACH(callback, &lcore_callbacks, next) {
368 [ + + ]: 4 : if (callback_init(callback, lcore_id) == 0)
369 : : continue;
370 : : /* Callback refused init for this lcore, call uninit for all
371 : : * previous callbacks.
372 : : */
373 : 1 : prev = TAILQ_PREV(callback, lcore_callbacks_head, next);
374 [ + + ]: 2 : while (prev != NULL) {
375 : 1 : callback_uninit(prev, lcore_id);
376 : 1 : prev = TAILQ_PREV(prev, lcore_callbacks_head, next);
377 : : }
378 : 1 : EAL_LOG(DEBUG, "Initialization refused for lcore %u.",
379 : : lcore_id);
380 : 1 : cfg->lcore_role[lcore_id] = ROLE_OFF;
381 : 1 : cfg->lcore_count--;
382 : : lcore_id = RTE_MAX_LCORE;
383 : 1 : goto out;
384 : : }
385 : 127 : out:
386 : : rte_rwlock_write_unlock(&lcore_lock);
387 : 129 : return lcore_id;
388 : : }
389 : :
390 : : void
391 : 127 : eal_lcore_non_eal_release(unsigned int lcore_id)
392 : : {
393 : 127 : struct rte_config *cfg = rte_eal_get_configuration();
394 : : struct lcore_callback *callback;
395 : :
396 : 127 : rte_rwlock_write_lock(&lcore_lock);
397 [ - + ]: 127 : if (cfg->lcore_role[lcore_id] != ROLE_NON_EAL)
398 : 0 : goto out;
399 [ + + ]: 129 : TAILQ_FOREACH(callback, &lcore_callbacks, next)
400 : 2 : callback_uninit(callback, lcore_id);
401 : 127 : cfg->lcore_role[lcore_id] = ROLE_OFF;
402 : 127 : cfg->lcore_count--;
403 : 127 : out:
404 : : rte_rwlock_write_unlock(&lcore_lock);
405 : 127 : }
406 : :
407 : : int
408 : 3 : rte_lcore_iterate(rte_lcore_iterate_cb cb, void *arg)
409 : : {
410 : 3 : struct rte_config *cfg = rte_eal_get_configuration();
411 : : unsigned int lcore_id;
412 : : int ret = 0;
413 : :
414 : 3 : rte_rwlock_read_lock(&lcore_lock);
415 [ + + ]: 387 : for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
416 [ + + ]: 384 : if (cfg->lcore_role[lcore_id] == ROLE_OFF)
417 : 377 : continue;
418 : 7 : ret = cb(lcore_id, arg);
419 [ + - ]: 7 : if (ret != 0)
420 : : break;
421 : : }
422 : : rte_rwlock_read_unlock(&lcore_lock);
423 : 3 : return ret;
424 : : }
425 : :
426 : : static const char *
427 : : lcore_role_str(enum rte_lcore_role_t role)
428 : : {
429 : 7 : switch (role) {
430 : : case ROLE_RTE:
431 : : return "RTE";
432 : 0 : case ROLE_SERVICE:
433 : 0 : return "SERVICE";
434 : 1 : case ROLE_NON_EAL:
435 : 1 : return "NON_EAL";
436 : 0 : default:
437 : 0 : return "UNKNOWN";
438 : : }
439 : : }
440 : :
441 : : static rte_lcore_usage_cb lcore_usage_cb;
442 : :
443 : : void
444 : 0 : rte_lcore_register_usage_cb(rte_lcore_usage_cb cb)
445 : : {
446 : 0 : lcore_usage_cb = cb;
447 : 0 : }
448 : :
449 : : static float
450 : : calc_usage_ratio(const struct rte_lcore_usage *usage)
451 : : {
452 : 0 : return usage->total_cycles != 0 ?
453 [ # # ]: 0 : (usage->busy_cycles * 100.0) / usage->total_cycles : (float)0;
454 : : }
455 : :
456 : : static int
457 : 7 : lcore_dump_cb(unsigned int lcore_id, void *arg)
458 : : {
459 : 7 : struct rte_config *cfg = rte_eal_get_configuration();
460 : : char cpuset[RTE_CPU_AFFINITY_STR_LEN];
461 : : struct rte_lcore_usage usage;
462 : : rte_lcore_usage_cb usage_cb;
463 [ - + ]: 7 : char *usage_str = NULL;
464 : : FILE *f = arg;
465 : : int ret;
466 : :
467 : : /* The callback may not set all the fields in the structure, so clear it here. */
468 : : memset(&usage, 0, sizeof(usage));
469 : : /* Guard against concurrent modification of lcore_usage_cb. */
470 : 7 : usage_cb = lcore_usage_cb;
471 [ - + - - ]: 7 : if (usage_cb != NULL && usage_cb(lcore_id, &usage) == 0) {
472 [ # # ]: 0 : if (asprintf(&usage_str, ", busy cycles %"PRIu64"/%"PRIu64" (ratio %.02f%%)",
473 : : usage.busy_cycles, usage.total_cycles,
474 : : calc_usage_ratio(&usage)) < 0) {
475 : : return -ENOMEM;
476 : : }
477 : : }
478 : 7 : ret = eal_thread_dump_affinity(&lcore_config[lcore_id].cpuset, cpuset,
479 : : sizeof(cpuset));
480 [ - + - + : 8 : fprintf(f, "lcore %u, socket %u, role %s, cpuset %s%s%s\n", lcore_id,
- + ]
481 : : rte_lcore_to_socket_id(lcore_id),
482 : : lcore_role_str(cfg->lcore_role[lcore_id]), cpuset,
483 [ - + ]: 7 : ret == 0 ? "" : "...", usage_str != NULL ? usage_str : "");
484 : 7 : free(usage_str);
485 : :
486 : 7 : return 0;
487 : : }
488 : :
489 : : void
490 : 3 : rte_lcore_dump(FILE *f)
491 : : {
492 : 3 : rte_lcore_iterate(lcore_dump_cb, f);
493 : 3 : }
494 : :
495 : : #ifndef RTE_EXEC_ENV_WINDOWS
496 : : static int
497 : 0 : lcore_telemetry_id_cb(unsigned int lcore_id, void *arg)
498 : : {
499 : : struct rte_tel_data *d = arg;
500 : :
501 : 0 : return rte_tel_data_add_array_int(d, lcore_id);
502 : : }
503 : :
504 : : static int
505 : 0 : handle_lcore_list(const char *cmd __rte_unused, const char *params __rte_unused,
506 : : struct rte_tel_data *d)
507 : : {
508 : : int ret;
509 : :
510 : 0 : ret = rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
511 [ # # ]: 0 : if (ret == 0)
512 : 0 : ret = rte_lcore_iterate(lcore_telemetry_id_cb, d);
513 : :
514 : 0 : return ret;
515 : : }
516 : :
517 : : struct lcore_telemetry_info {
518 : : unsigned int lcore_id;
519 : : struct rte_tel_data *d;
520 : : };
521 : :
522 : : static void
523 [ # # ]: 0 : format_usage_ratio(char *buf, uint16_t size, const struct rte_lcore_usage *usage)
524 : : {
525 : : float ratio = calc_usage_ratio(usage);
526 : 0 : snprintf(buf, size, "%.02f%%", ratio);
527 : 0 : }
528 : :
529 : : static int
530 : 0 : lcore_telemetry_info_cb(unsigned int lcore_id, void *arg)
531 : : {
532 : 0 : struct rte_config *cfg = rte_eal_get_configuration();
533 : : struct lcore_telemetry_info *info = arg;
534 : : char ratio_str[RTE_TEL_MAX_STRING_LEN];
535 : : struct rte_lcore_usage usage;
536 : : struct rte_tel_data *cpuset;
537 : : rte_lcore_usage_cb usage_cb;
538 : : unsigned int cpu;
539 : :
540 [ # # ]: 0 : if (lcore_id != info->lcore_id)
541 : : return 0;
542 : :
543 : 0 : rte_tel_data_start_dict(info->d);
544 : 0 : rte_tel_data_add_dict_int(info->d, "lcore_id", lcore_id);
545 : 0 : rte_tel_data_add_dict_int(info->d, "socket", rte_lcore_to_socket_id(lcore_id));
546 [ # # # # ]: 0 : rte_tel_data_add_dict_string(info->d, "role", lcore_role_str(cfg->lcore_role[lcore_id]));
547 : 0 : cpuset = rte_tel_data_alloc();
548 [ # # ]: 0 : if (cpuset == NULL)
549 : : return -ENOMEM;
550 : 0 : rte_tel_data_start_array(cpuset, RTE_TEL_INT_VAL);
551 [ # # ]: 0 : for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
552 [ # # ]: 0 : if (CPU_ISSET(cpu, &lcore_config[lcore_id].cpuset))
553 : 0 : rte_tel_data_add_array_int(cpuset, cpu);
554 : : }
555 : 0 : rte_tel_data_add_dict_container(info->d, "cpuset", cpuset, 0);
556 : : /* The callback may not set all the fields in the structure, so clear it here. */
557 : : memset(&usage, 0, sizeof(usage));
558 : : /* Guard against concurrent modification of lcore_usage_cb. */
559 : 0 : usage_cb = lcore_usage_cb;
560 [ # # # # ]: 0 : if (usage_cb != NULL && usage_cb(lcore_id, &usage) == 0) {
561 : 0 : rte_tel_data_add_dict_uint(info->d, "total_cycles", usage.total_cycles);
562 : 0 : rte_tel_data_add_dict_uint(info->d, "busy_cycles", usage.busy_cycles);
563 : 0 : format_usage_ratio(ratio_str, sizeof(ratio_str), &usage);
564 : 0 : rte_tel_data_add_dict_string(info->d, "usage_ratio", ratio_str);
565 : : }
566 : :
567 : : /* Return non-zero positive value to stop iterating over lcore_id. */
568 : : return 1;
569 : : }
570 : :
571 : : static int
572 : 0 : handle_lcore_info(const char *cmd __rte_unused, const char *params, struct rte_tel_data *d)
573 : : {
574 : 0 : struct lcore_telemetry_info info = { .d = d };
575 : : unsigned long lcore_id;
576 : : char *endptr;
577 : :
578 [ # # ]: 0 : if (params == NULL)
579 : : return -EINVAL;
580 : 0 : errno = 0;
581 : 0 : lcore_id = strtoul(params, &endptr, 10);
582 [ # # ]: 0 : if (errno)
583 : 0 : return -errno;
584 [ # # # # : 0 : if (*params == '\0' || *endptr != '\0' || lcore_id >= RTE_MAX_LCORE)
# # ]
585 : : return -EINVAL;
586 : :
587 : 0 : info.lcore_id = lcore_id;
588 : :
589 : 0 : return rte_lcore_iterate(lcore_telemetry_info_cb, &info);
590 : : }
591 : :
592 : : struct lcore_telemetry_usage {
593 : : struct rte_tel_data *lcore_ids;
594 : : struct rte_tel_data *total_cycles;
595 : : struct rte_tel_data *busy_cycles;
596 : : struct rte_tel_data *usage_ratio;
597 : : };
598 : :
599 : : static int
600 [ # # ]: 0 : lcore_telemetry_usage_cb(unsigned int lcore_id, void *arg)
601 : : {
602 : : char ratio_str[RTE_TEL_MAX_STRING_LEN];
603 : : struct lcore_telemetry_usage *u = arg;
604 : : struct rte_lcore_usage usage;
605 : : rte_lcore_usage_cb usage_cb;
606 : :
607 : : /* The callback may not set all the fields in the structure, so clear it here. */
608 : : memset(&usage, 0, sizeof(usage));
609 : : /* Guard against concurrent modification of lcore_usage_cb. */
610 : 0 : usage_cb = lcore_usage_cb;
611 [ # # # # ]: 0 : if (usage_cb != NULL && usage_cb(lcore_id, &usage) == 0) {
612 : 0 : rte_tel_data_add_array_uint(u->lcore_ids, lcore_id);
613 : 0 : rte_tel_data_add_array_uint(u->total_cycles, usage.total_cycles);
614 : 0 : rte_tel_data_add_array_uint(u->busy_cycles, usage.busy_cycles);
615 : 0 : format_usage_ratio(ratio_str, sizeof(ratio_str), &usage);
616 : 0 : rte_tel_data_add_array_string(u->usage_ratio, ratio_str);
617 : : }
618 : :
619 : 0 : return 0;
620 : : }
621 : :
622 : : static int
623 : 0 : handle_lcore_usage(const char *cmd __rte_unused, const char *params __rte_unused,
624 : : struct rte_tel_data *d)
625 : : {
626 : : struct lcore_telemetry_usage usage;
627 : : struct rte_tel_data *total_cycles;
628 : : struct rte_tel_data *busy_cycles;
629 : : struct rte_tel_data *usage_ratio;
630 : : struct rte_tel_data *lcore_ids;
631 : :
632 : 0 : lcore_ids = rte_tel_data_alloc();
633 : 0 : total_cycles = rte_tel_data_alloc();
634 : 0 : busy_cycles = rte_tel_data_alloc();
635 : 0 : usage_ratio = rte_tel_data_alloc();
636 [ # # ]: 0 : if (lcore_ids == NULL || total_cycles == NULL || busy_cycles == NULL ||
637 [ # # ]: 0 : usage_ratio == NULL) {
638 : 0 : rte_tel_data_free(lcore_ids);
639 : 0 : rte_tel_data_free(total_cycles);
640 : 0 : rte_tel_data_free(busy_cycles);
641 : 0 : rte_tel_data_free(usage_ratio);
642 : 0 : return -ENOMEM;
643 : : }
644 : :
645 : 0 : rte_tel_data_start_dict(d);
646 : 0 : rte_tel_data_start_array(lcore_ids, RTE_TEL_UINT_VAL);
647 : 0 : rte_tel_data_start_array(total_cycles, RTE_TEL_UINT_VAL);
648 : 0 : rte_tel_data_start_array(busy_cycles, RTE_TEL_UINT_VAL);
649 : 0 : rte_tel_data_start_array(usage_ratio, RTE_TEL_STRING_VAL);
650 : 0 : rte_tel_data_add_dict_container(d, "lcore_ids", lcore_ids, 0);
651 : 0 : rte_tel_data_add_dict_container(d, "total_cycles", total_cycles, 0);
652 : 0 : rte_tel_data_add_dict_container(d, "busy_cycles", busy_cycles, 0);
653 : 0 : rte_tel_data_add_dict_container(d, "usage_ratio", usage_ratio, 0);
654 : 0 : usage.lcore_ids = lcore_ids;
655 : 0 : usage.total_cycles = total_cycles;
656 : 0 : usage.busy_cycles = busy_cycles;
657 : 0 : usage.usage_ratio = usage_ratio;
658 : :
659 : 0 : return rte_lcore_iterate(lcore_telemetry_usage_cb, &usage);
660 : : }
661 : :
662 : 235 : RTE_INIT(lcore_telemetry)
663 : : {
664 : 235 : rte_telemetry_register_cmd("/eal/lcore/list", handle_lcore_list,
665 : : "List of lcore ids. Takes no parameters");
666 : 235 : rte_telemetry_register_cmd("/eal/lcore/info", handle_lcore_info,
667 : : "Returns lcore info. Parameters: int lcore_id");
668 : 235 : rte_telemetry_register_cmd("/eal/lcore/usage", handle_lcore_usage,
669 : : "Returns lcore cycles usage. Takes no parameters");
670 : 235 : }
671 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
|