Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2017 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <inttypes.h>
7 : : #include <string.h>
8 : :
9 : : #include <rte_service.h>
10 : : #include <rte_service_component.h>
11 : :
12 : : #include <eal_export.h>
13 : : #include <eal_trace_internal.h>
14 : : #include <rte_lcore.h>
15 : : #include <rte_lcore_var.h>
16 : : #include <rte_bitset.h>
17 : : #include <rte_branch_prediction.h>
18 : : #include <rte_common.h>
19 : : #include <rte_cycles.h>
20 : : #include <rte_atomic.h>
21 : : #include <rte_malloc.h>
22 : : #include <rte_spinlock.h>
23 : : #include <rte_trace_point.h>
24 : :
25 : : #include "eal_private.h"
26 : :
27 : : #define RTE_SERVICE_NUM_MAX 64
28 : :
29 : : #define SERVICE_F_REGISTERED (1 << 0)
30 : : #define SERVICE_F_STATS_ENABLED (1 << 1)
31 : : #define SERVICE_F_START_CHECK (1 << 2)
32 : :
33 : : /* runstates for services and lcores, denoting if they are active or not */
34 : : #define RUNSTATE_STOPPED 0
35 : : #define RUNSTATE_RUNNING 1
36 : :
37 : : /* internal representation of a service */
38 : : struct __rte_cache_aligned rte_service_spec_impl {
39 : : /* public part of the struct */
40 : : struct rte_service_spec spec;
41 : :
42 : : /* spin lock that when set indicates a service core is currently
43 : : * running this service callback. When not set, a core may take the
44 : : * lock and then run the service callback.
45 : : */
46 : : rte_spinlock_t execute_lock;
47 : :
48 : : /* API set/get-able variables */
49 : : RTE_ATOMIC(int8_t) app_runstate;
50 : : RTE_ATOMIC(int8_t) comp_runstate;
51 : : uint8_t internal_flags;
52 : :
53 : : /* per service statistics */
54 : : /* Indicates how many cores the service is mapped to run on.
55 : : * It does not indicate the number of cores the service is running
56 : : * on currently.
57 : : */
58 : : RTE_ATOMIC(uint32_t) num_mapped_cores;
59 : : };
60 : :
61 : : struct service_stats {
62 : : RTE_ATOMIC(uint64_t) calls;
63 : : RTE_ATOMIC(uint64_t) idle_calls;
64 : : RTE_ATOMIC(uint64_t) error_calls;
65 : : RTE_ATOMIC(uint64_t) cycles;
66 : : };
67 : :
68 : : /* the internal values of a service core */
69 : : struct __rte_cache_aligned core_state {
70 : : /* map of services IDs are run on this core */
71 : : RTE_BITSET_DECLARE(mapped_services, RTE_SERVICE_NUM_MAX);
72 : : RTE_ATOMIC(uint8_t) runstate; /* running or stopped */
73 : : RTE_ATOMIC(uint8_t) thread_active; /* indicates when thread is in service_run() */
74 : : uint8_t is_service_core; /* set if core is currently a service core */
75 : : RTE_BITSET_DECLARE(service_active_on_lcore, RTE_SERVICE_NUM_MAX);
76 : : RTE_ATOMIC(uint64_t) loops;
77 : : RTE_ATOMIC(uint64_t) cycles;
78 : : struct service_stats service_stats[RTE_SERVICE_NUM_MAX];
79 : : };
80 : :
81 : : static uint32_t rte_service_count;
82 : : static struct rte_service_spec_impl *rte_services;
83 : : static RTE_LCORE_VAR_HANDLE(struct core_state, lcore_states);
84 : : static uint32_t rte_service_library_initialized;
85 : :
86 : : int32_t
87 : 180 : rte_service_init(void)
88 : : {
89 [ - + ]: 180 : if (rte_service_library_initialized) {
90 : 0 : EAL_LOG(NOTICE,
91 : : "service library init() called, init flag %d",
92 : : rte_service_library_initialized);
93 : 0 : return -EALREADY;
94 : : }
95 : :
96 : 180 : rte_services = rte_calloc("rte_services", RTE_SERVICE_NUM_MAX,
97 : : sizeof(struct rte_service_spec_impl),
98 : : RTE_CACHE_LINE_SIZE);
99 [ - + ]: 180 : if (!rte_services) {
100 : 0 : EAL_LOG(ERR, "error allocating rte services array");
101 : 0 : goto fail_mem;
102 : : }
103 : :
104 [ + - ]: 180 : if (lcore_states == NULL)
105 : 180 : RTE_LCORE_VAR_ALLOC(lcore_states);
106 : :
107 : : int i;
108 : 180 : struct rte_config *cfg = rte_eal_get_configuration();
109 [ + + ]: 23220 : for (i = 0; i < RTE_MAX_LCORE; i++) {
110 [ - + ]: 23040 : if (lcore_config[i].core_role == ROLE_SERVICE) {
111 [ # # ]: 0 : if ((unsigned int)i == cfg->main_lcore)
112 : 0 : continue;
113 : 0 : rte_service_lcore_add(i);
114 : : }
115 : : }
116 : :
117 : 180 : rte_service_library_initialized = 1;
118 : 180 : return 0;
119 : : fail_mem:
120 : 0 : rte_free(rte_services);
121 : 0 : return -ENOMEM;
122 : : }
123 : :
124 : : RTE_EXPORT_SYMBOL(rte_service_finalize)
125 : : void
126 : 272 : rte_service_finalize(void)
127 : : {
128 [ + + ]: 272 : if (!rte_service_library_initialized)
129 : : return;
130 : :
131 : 180 : rte_service_lcore_reset_all();
132 : 180 : rte_eal_mp_wait_lcore();
133 : :
134 : 180 : rte_free(rte_services);
135 : :
136 : 180 : rte_service_library_initialized = 0;
137 : : }
138 : :
139 : : static inline bool
140 : : service_registered(uint32_t id)
141 : : {
142 : 8402599 : return rte_services[id].internal_flags & SERVICE_F_REGISTERED;
143 : : }
144 : :
145 : : static inline bool
146 : : service_valid(uint32_t id)
147 : : {
148 [ + - - + : 8402419 : return id < RTE_SERVICE_NUM_MAX && service_registered(id);
- - - - +
- - + + -
- + + + -
+ - + - +
- + - + -
+ - + - +
- + ]
149 : : }
150 : :
151 : : static struct rte_service_spec_impl *
152 : : service_get(uint32_t id)
153 : : {
154 : 139000 : return &rte_services[id];
155 : : }
156 : :
157 : : /* validate ID and retrieve service pointer, or return error value */
158 : : #define SERVICE_VALID_GET_OR_ERR_RET(id, service, retval) do { \
159 : : if (!service_valid(id)) \
160 : : return retval; \
161 : : service = &rte_services[id]; \
162 : : } while (0)
163 : :
164 : : /* returns 1 if statistics should be collected for service
165 : : * Returns 0 if statistics should not be collected for service
166 : : */
167 : : static inline int
168 : : service_stats_enabled(struct rte_service_spec_impl *impl)
169 : : {
170 : 8402097 : return !!(impl->internal_flags & SERVICE_F_STATS_ENABLED);
171 : : }
172 : :
173 : : static inline int
174 : : service_mt_safe(struct rte_service_spec_impl *s)
175 : : {
176 : 8402095 : return !!(s->spec.capabilities & RTE_SERVICE_CAP_MT_SAFE);
177 : : }
178 : :
179 : : RTE_EXPORT_SYMBOL(rte_service_set_stats_enable)
180 : : int32_t
181 [ + - ]: 2 : rte_service_set_stats_enable(uint32_t id, int32_t enabled)
182 : : {
183 : : struct rte_service_spec_impl *s;
184 [ + - ]: 2 : SERVICE_VALID_GET_OR_ERR_RET(id, s, 0);
185 : :
186 [ + + ]: 2 : if (enabled)
187 : 1 : s->internal_flags |= SERVICE_F_STATS_ENABLED;
188 : : else
189 : 1 : s->internal_flags &= ~(SERVICE_F_STATS_ENABLED);
190 : :
191 : : return 0;
192 : : }
193 : :
194 : : RTE_EXPORT_SYMBOL(rte_service_set_runstate_mapped_check)
195 : : int32_t
196 [ + - ]: 3 : rte_service_set_runstate_mapped_check(uint32_t id, int32_t enabled)
197 : : {
198 : : struct rte_service_spec_impl *s;
199 [ + - ]: 3 : SERVICE_VALID_GET_OR_ERR_RET(id, s, 0);
200 : :
201 [ - + ]: 3 : if (enabled)
202 : 0 : s->internal_flags |= SERVICE_F_START_CHECK;
203 : : else
204 : 3 : s->internal_flags &= ~(SERVICE_F_START_CHECK);
205 : :
206 : : return 0;
207 : : }
208 : :
209 : : RTE_EXPORT_SYMBOL(rte_service_get_count)
210 : : uint32_t
211 : 203 : rte_service_get_count(void)
212 : : {
213 : 203 : return rte_service_count;
214 : : }
215 : :
216 : : RTE_EXPORT_SYMBOL(rte_service_get_by_name)
217 : : int32_t
218 : 4 : rte_service_get_by_name(const char *name, uint32_t *service_id)
219 : : {
220 [ + + ]: 4 : if (!service_id)
221 : : return -EINVAL;
222 : :
223 : : int i;
224 [ + + ]: 131 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
225 [ + + ]: 129 : if (service_registered(i) &&
226 [ + - ]: 1 : strcmp(name, rte_services[i].spec.name) == 0) {
227 : 1 : *service_id = i;
228 : 1 : return 0;
229 : : }
230 : : }
231 : :
232 : : return -ENODEV;
233 : : }
234 : :
235 : : RTE_EXPORT_SYMBOL(rte_service_get_name)
236 : : const char *
237 [ + - ]: 1 : rte_service_get_name(uint32_t id)
238 : : {
239 : : struct rte_service_spec_impl *s;
240 [ + - ]: 1 : SERVICE_VALID_GET_OR_ERR_RET(id, s, 0);
241 : 1 : return s->spec.name;
242 : : }
243 : :
244 : : RTE_EXPORT_SYMBOL(rte_service_probe_capability)
245 : : int32_t
246 [ + - ]: 2 : rte_service_probe_capability(uint32_t id, uint32_t capability)
247 : : {
248 : : struct rte_service_spec_impl *s;
249 [ + - ]: 2 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
250 : 2 : return !!(s->spec.capabilities & capability);
251 : : }
252 : :
253 : : RTE_EXPORT_SYMBOL(rte_service_component_register)
254 : : int32_t
255 : 50 : rte_service_component_register(const struct rte_service_spec *spec,
256 : : uint32_t *id_ptr)
257 : : {
258 : : uint32_t i;
259 : : int32_t free_slot = -1;
260 : :
261 [ + + + + ]: 50 : if (spec->callback == NULL || strlen(spec->name) == 0)
262 : : return -EINVAL;
263 : :
264 [ + - ]: 52 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
265 [ + + ]: 52 : if (!service_registered(i)) {
266 : 24 : free_slot = i;
267 : 24 : break;
268 : : }
269 : : }
270 : :
271 [ + - ]: 24 : if ((free_slot < 0) || (i == RTE_SERVICE_NUM_MAX))
272 : : return -ENOSPC;
273 : :
274 : 24 : struct rte_service_spec_impl *s = &rte_services[free_slot];
275 : 24 : s->spec = *spec;
276 : 24 : s->internal_flags |= SERVICE_F_REGISTERED | SERVICE_F_START_CHECK;
277 : :
278 : 24 : rte_service_count++;
279 : :
280 [ + + ]: 24 : if (id_ptr)
281 : 21 : *id_ptr = free_slot;
282 : :
283 [ - + ]: 24 : rte_eal_trace_service_component_register(free_slot, spec->name);
284 : :
285 : 24 : return 0;
286 : : }
287 : :
288 : : RTE_EXPORT_SYMBOL(rte_service_component_unregister)
289 : : int32_t
290 [ + + ]: 37 : rte_service_component_unregister(uint32_t id)
291 : : {
292 : : struct rte_service_spec_impl *s;
293 [ + + ]: 37 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
294 : :
295 : 14 : rte_service_count--;
296 : :
297 : : s->internal_flags &= ~(SERVICE_F_REGISTERED);
298 : :
299 : : unsigned int lcore_id;
300 : : struct core_state *cs;
301 : : /* clear the run-bit in all cores */
302 [ + + ]: 1806 : RTE_LCORE_VAR_FOREACH(lcore_id, cs, lcore_states)
303 : 1792 : rte_bitset_clear(cs->mapped_services, id);
304 : :
305 : : memset(&rte_services[id], 0, sizeof(struct rte_service_spec_impl));
306 : :
307 : 14 : return 0;
308 : : }
309 : :
310 : : RTE_EXPORT_SYMBOL(rte_service_component_runstate_set)
311 : : int32_t
312 [ + - ]: 78 : rte_service_component_runstate_set(uint32_t id, uint32_t runstate)
313 : : {
314 : : struct rte_service_spec_impl *s;
315 [ + - ]: 78 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
316 : :
317 : : /* comp_runstate act as the guard variable. Use store-release
318 : : * memory order. This synchronizes with load-acquire in
319 : : * service_run and service_runstate_get function.
320 : : */
321 [ + - ]: 78 : if (runstate)
322 : 78 : rte_atomic_store_explicit(&s->comp_runstate, RUNSTATE_RUNNING,
323 : : rte_memory_order_release);
324 : : else
325 : 0 : rte_atomic_store_explicit(&s->comp_runstate, RUNSTATE_STOPPED,
326 : : rte_memory_order_release);
327 : :
328 : : return 0;
329 : : }
330 : :
331 : : RTE_EXPORT_SYMBOL(rte_service_runstate_set)
332 : : int32_t
333 [ + - ]: 130 : rte_service_runstate_set(uint32_t id, uint32_t runstate)
334 : : {
335 : : struct rte_service_spec_impl *s;
336 [ + - ]: 130 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
337 : :
338 : : /* app_runstate act as the guard variable. Use store-release
339 : : * memory order. This synchronizes with load-acquire in
340 : : * service_run runstate_get function.
341 : : */
342 [ + + ]: 130 : if (runstate)
343 : 67 : rte_atomic_store_explicit(&s->app_runstate, RUNSTATE_RUNNING,
344 : : rte_memory_order_release);
345 : : else
346 : 63 : rte_atomic_store_explicit(&s->app_runstate, RUNSTATE_STOPPED,
347 : : rte_memory_order_release);
348 : :
349 : 130 : rte_eal_trace_service_runstate_set(id, runstate);
350 : 130 : return 0;
351 : : }
352 : :
353 : : RTE_EXPORT_SYMBOL(rte_service_runstate_get)
354 : : int32_t
355 [ + - ]: 121 : rte_service_runstate_get(uint32_t id)
356 : : {
357 : : struct rte_service_spec_impl *s;
358 [ + - ]: 121 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
359 : :
360 : : /* comp_runstate and app_runstate act as the guard variables.
361 : : * Use load-acquire memory order. This synchronizes with
362 : : * store-release in service state set functions.
363 : : */
364 [ + - ]: 121 : if (rte_atomic_load_explicit(&s->comp_runstate, rte_memory_order_acquire) ==
365 : 121 : RUNSTATE_RUNNING &&
366 [ + + ]: 121 : rte_atomic_load_explicit(&s->app_runstate, rte_memory_order_acquire) ==
367 : : RUNSTATE_RUNNING) {
368 : 119 : int check_disabled = !(s->internal_flags &
369 : : SERVICE_F_START_CHECK);
370 : 119 : int lcore_mapped = (rte_atomic_load_explicit(&s->num_mapped_cores,
371 : 119 : rte_memory_order_relaxed) > 0);
372 : :
373 : 119 : return (check_disabled | lcore_mapped);
374 : : } else
375 : 2 : return 0;
376 : :
377 : : }
378 : :
379 : : static void
380 : 0 : service_counter_add(RTE_ATOMIC(uint64_t) *counter, uint64_t operand)
381 : : {
382 : : /* The lcore service worker thread is the only writer, and
383 : : * thus only a non-atomic load and an atomic store is needed,
384 : : * and not the more expensive atomic add.
385 : : */
386 : : uint64_t value;
387 : :
388 : 0 : value = rte_atomic_load_explicit(counter, rte_memory_order_relaxed);
389 : :
390 : 0 : rte_atomic_store_explicit(counter, value + operand,
391 : : rte_memory_order_relaxed);
392 : 0 : }
393 : :
394 : : static inline void
395 [ - + ]: 8402095 : service_runner_do_callback(struct rte_service_spec_impl *s,
396 : : struct core_state *cs, uint32_t service_idx)
397 : : {
398 : 8402095 : rte_eal_trace_service_run_begin(service_idx, rte_lcore_id());
399 : 8402095 : void *userdata = s->spec.callback_userdata;
400 : :
401 [ - + ]: 8402095 : if (service_stats_enabled(s)) {
402 : : uint64_t start = rte_rdtsc();
403 : 0 : int rc = s->spec.callback(userdata);
404 : :
405 : : struct service_stats *service_stats =
406 : : &cs->service_stats[service_idx];
407 : :
408 : 0 : service_counter_add(&service_stats->calls, 1);
409 : :
410 [ # # ]: 0 : if (rc == -EAGAIN)
411 : 0 : service_counter_add(&service_stats->idle_calls, 1);
412 [ # # ]: 0 : else if (rc != 0)
413 : 0 : service_counter_add(&service_stats->error_calls, 1);
414 : :
415 [ # # ]: 0 : if (likely(rc != -EAGAIN)) {
416 : : uint64_t end = rte_rdtsc();
417 : 0 : uint64_t cycles = end - start;
418 : :
419 : 0 : service_counter_add(&cs->cycles, cycles);
420 : 0 : service_counter_add(&service_stats->cycles, cycles);
421 : : }
422 : : } else {
423 : 8402095 : s->spec.callback(userdata);
424 : : }
425 : 8402095 : rte_eal_trace_service_run_end(service_idx, rte_lcore_id());
426 : 8402095 : }
427 : :
428 : :
429 : : /* Expects the service 's' is valid. */
430 : : static int32_t
431 : 8540993 : service_run(uint32_t i, struct core_state *cs, const uint64_t *mapped_services,
432 : : struct rte_service_spec_impl *s, uint32_t serialize_mt_unsafe)
433 : : {
434 [ + - ]: 8540993 : if (!s)
435 : : return -EINVAL;
436 : :
437 : : /* comp_runstate and app_runstate act as the guard variables.
438 : : * Use load-acquire memory order. This synchronizes with
439 : : * store-release in service state set functions.
440 : : */
441 [ + - ]: 8540993 : if (rte_atomic_load_explicit(&s->comp_runstate, rte_memory_order_acquire) !=
442 : 8540993 : RUNSTATE_RUNNING ||
443 [ + + ]: 8540993 : rte_atomic_load_explicit(&s->app_runstate, rte_memory_order_acquire) !=
444 [ - + ]: 8402095 : RUNSTATE_RUNNING ||
445 [ - + ]: 8402095 : !rte_bitset_test(mapped_services, i)) {
446 : 138898 : rte_bitset_clear(cs->service_active_on_lcore, i);
447 : 138898 : return -ENOEXEC;
448 : : }
449 : :
450 [ + + ]: 8402095 : rte_bitset_set(cs->service_active_on_lcore, i);
451 : :
452 [ + + + + ]: 8402095 : if ((service_mt_safe(s) == 0) && (serialize_mt_unsafe == 1)) {
453 [ + - ]: 5295 : if (!rte_spinlock_trylock(&s->execute_lock))
454 : : return -EBUSY;
455 : :
456 : 5295 : service_runner_do_callback(s, cs, i);
457 : : rte_spinlock_unlock(&s->execute_lock);
458 : : } else
459 : 8396800 : service_runner_do_callback(s, cs, i);
460 : :
461 : : return 0;
462 : : }
463 : :
464 : : RTE_EXPORT_SYMBOL(rte_service_may_be_active)
465 : : int32_t
466 : 63 : rte_service_may_be_active(uint32_t id)
467 : : {
468 : 63 : uint32_t ids[RTE_MAX_LCORE] = {0};
469 : 63 : int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
470 : : int i;
471 : :
472 [ + + ]: 63 : if (!service_valid(id))
473 : : return -EINVAL;
474 : :
475 [ + + ]: 64 : for (i = 0; i < lcore_count; i++) {
476 : : struct core_state *cs =
477 [ + + ]: 3 : RTE_LCORE_VAR_LCORE(ids[i], lcore_states);
478 : :
479 [ + + ]: 3 : if (rte_bitset_test(cs->service_active_on_lcore, id))
480 : : return 1;
481 : : }
482 : :
483 : : return 0;
484 : : }
485 : :
486 : : RTE_EXPORT_SYMBOL(rte_service_run_iter_on_app_lcore)
487 : : int32_t
488 : 8401995 : rte_service_run_iter_on_app_lcore(uint32_t id, uint32_t serialize_mt_unsafe)
489 : : {
490 [ + - ]: 8401995 : struct core_state *cs = RTE_LCORE_VAR(lcore_states);
491 : : struct rte_service_spec_impl *s;
492 : :
493 [ + - ]: 8401995 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
494 : :
495 : : /* Increment num_mapped_cores to reflect that this core is
496 : : * now mapped capable of running the service.
497 : : */
498 : 8401995 : rte_atomic_fetch_add_explicit(&s->num_mapped_cores, 1, rte_memory_order_relaxed);
499 : :
500 : : RTE_BITSET_DECLARE(all_services, RTE_SERVICE_NUM_MAX);
501 : : rte_bitset_set_all(all_services, RTE_SERVICE_NUM_MAX);
502 : 8401995 : int ret = service_run(id, cs, all_services, s, serialize_mt_unsafe);
503 : :
504 : 8401995 : rte_atomic_fetch_sub_explicit(&s->num_mapped_cores, 1, rte_memory_order_relaxed);
505 : :
506 : 8401995 : return ret;
507 : : }
508 : :
509 : : static int32_t
510 : 1 : service_runner_func(void *arg)
511 : : {
512 : : RTE_SET_USED(arg);
513 : 1 : struct core_state *cs = RTE_LCORE_VAR(lcore_states);
514 : :
515 : 1 : rte_atomic_store_explicit(&cs->thread_active, 1, rte_memory_order_seq_cst);
516 : :
517 : : /* runstate act as the guard variable. Use load-acquire
518 : : * memory order here to synchronize with store-release
519 : : * in runstate update functions.
520 : : */
521 [ + + ]: 139809 : while (rte_atomic_load_explicit(&cs->runstate, rte_memory_order_acquire) ==
522 : : RUNSTATE_RUNNING) {
523 : : ssize_t id;
524 : :
525 [ + - + - : 278806 : RTE_BITSET_FOREACH_SET(id, cs->mapped_services, RTE_SERVICE_NUM_MAX) {
- + + + ]
526 : : /* return value ignored as no change to code flow */
527 : 138998 : service_run(id, cs, cs->mapped_services, service_get(id), 1);
528 : : }
529 : :
530 : 139808 : rte_atomic_store_explicit(&cs->loops, cs->loops + 1, rte_memory_order_relaxed);
531 : : }
532 : :
533 : : /* Switch off this core for all services, to ensure that future
534 : : * calls to may_be_active() know this core is switched off.
535 : : */
536 : 1 : rte_bitset_clear_all(cs->service_active_on_lcore, RTE_SERVICE_NUM_MAX);
537 : :
538 : : /* Use SEQ CST memory ordering to avoid any re-ordering around
539 : : * this store, ensuring that once this store is visible, the service
540 : : * lcore thread really is done in service cores code.
541 : : */
542 : 1 : rte_atomic_store_explicit(&cs->thread_active, 0, rte_memory_order_seq_cst);
543 : 1 : return 0;
544 : : }
545 : :
546 : : RTE_EXPORT_SYMBOL(rte_service_lcore_may_be_active)
547 : : int32_t
548 : 0 : rte_service_lcore_may_be_active(uint32_t lcore)
549 : : {
550 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
551 : :
552 [ # # # # ]: 0 : if (lcore >= RTE_MAX_LCORE || !cs->is_service_core)
553 : : return -EINVAL;
554 : :
555 : : /* Load thread_active using ACQUIRE to avoid instructions dependent on
556 : : * the result being re-ordered before this load completes.
557 : : */
558 : 0 : return rte_atomic_load_explicit(&cs->thread_active,
559 : : rte_memory_order_acquire);
560 : : }
561 : :
562 : : RTE_EXPORT_SYMBOL(rte_service_lcore_count)
563 : : int32_t
564 : 243 : rte_service_lcore_count(void)
565 : : {
566 : : int32_t count = 0;
567 : :
568 : : unsigned int lcore_id;
569 : : struct core_state *cs;
570 [ + + ]: 31347 : RTE_LCORE_VAR_FOREACH(lcore_id, cs, lcore_states)
571 : 31104 : count += cs->is_service_core;
572 : :
573 : 243 : return count;
574 : : }
575 : :
576 : : RTE_EXPORT_SYMBOL(rte_service_lcore_list)
577 : : int32_t
578 : 243 : rte_service_lcore_list(uint32_t array[], uint32_t n)
579 : : {
580 : 243 : uint32_t count = rte_service_lcore_count();
581 [ + - ]: 243 : if (count > n)
582 : : return -ENOMEM;
583 : :
584 [ + - ]: 243 : if (!array)
585 : : return -EINVAL;
586 : :
587 : : uint32_t i;
588 : : uint32_t idx = 0;
589 [ + + ]: 31347 : for (i = 0; i < RTE_MAX_LCORE; i++) {
590 : : struct core_state *cs =
591 [ + + ]: 31104 : RTE_LCORE_VAR_LCORE(i, lcore_states);
592 [ + + ]: 31104 : if (cs->is_service_core) {
593 : 3 : array[idx] = i;
594 : 3 : idx++;
595 : : }
596 : : }
597 : :
598 : : return count;
599 : : }
600 : :
601 : : RTE_EXPORT_SYMBOL(rte_service_lcore_count_services)
602 : : int32_t
603 : 0 : rte_service_lcore_count_services(uint32_t lcore)
604 : : {
605 [ # # ]: 0 : if (lcore >= RTE_MAX_LCORE)
606 : : return -EINVAL;
607 : :
608 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
609 [ # # ]: 0 : if (!cs->is_service_core)
610 : : return -ENOTSUP;
611 : :
612 : 0 : return rte_bitset_count_set(cs->mapped_services, RTE_SERVICE_NUM_MAX);
613 : : }
614 : :
615 : : RTE_EXPORT_SYMBOL(rte_service_start_with_defaults)
616 : : int32_t
617 : 180 : rte_service_start_with_defaults(void)
618 : : {
619 : : /* create a default mapping from cores to services, then start the
620 : : * services to make them transparent to unaware applications.
621 : : */
622 : : uint32_t i;
623 : : int ret;
624 : 180 : uint32_t count = rte_service_get_count();
625 : :
626 : : int32_t lcore_iter = 0;
627 : 180 : uint32_t ids[RTE_MAX_LCORE] = {0};
628 : 180 : int32_t lcore_count = rte_service_lcore_list(ids, RTE_MAX_LCORE);
629 : :
630 [ - + ]: 180 : if (lcore_count == 0)
631 : : return -ENOTSUP;
632 : :
633 [ # # ]: 0 : for (i = 0; (int)i < lcore_count; i++)
634 : 0 : rte_service_lcore_start(ids[i]);
635 : :
636 [ # # ]: 0 : for (i = 0; i < count; i++) {
637 : : /* do 1:1 core mapping here, with each service getting
638 : : * assigned a single core by default. Adding multiple services
639 : : * should multiplex to a single core, or 1:1 if there are the
640 : : * same amount of services as service-cores
641 : : */
642 : 0 : ret = rte_service_map_lcore_set(i, ids[lcore_iter], 1);
643 [ # # ]: 0 : if (ret)
644 : : return -ENODEV;
645 : :
646 : 0 : lcore_iter++;
647 [ # # ]: 0 : if (lcore_iter >= lcore_count)
648 : : lcore_iter = 0;
649 : :
650 : 0 : ret = rte_service_runstate_set(i, 1);
651 [ # # ]: 0 : if (ret)
652 : : return -ENOEXEC;
653 : : }
654 : :
655 : : return 0;
656 : : }
657 : :
658 : : static int32_t
659 : 8 : service_update(uint32_t sid, uint32_t lcore, uint32_t *set, uint32_t *enabled)
660 : : {
661 [ + - ]: 8 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
662 : :
663 : : /* validate ID, or return error value */
664 [ + - + + ]: 8 : if (!service_valid(sid) || lcore >= RTE_MAX_LCORE ||
665 [ + - ]: 6 : !cs->is_service_core)
666 : : return -EINVAL;
667 : :
668 [ + + ]: 6 : if (set) {
669 [ + + ]: 4 : bool lcore_mapped = rte_bitset_test(cs->mapped_services, sid);
670 : :
671 [ + + + - ]: 4 : if (*set && !lcore_mapped) {
672 : : rte_bitset_set(cs->mapped_services, sid);
673 : 3 : rte_atomic_fetch_add_explicit(&rte_services[sid].num_mapped_cores,
674 : : 1, rte_memory_order_relaxed);
675 : : }
676 [ + + + - ]: 4 : if (!*set && lcore_mapped) {
677 : : rte_bitset_clear(cs->mapped_services, sid);
678 : 1 : rte_atomic_fetch_sub_explicit(&rte_services[sid].num_mapped_cores,
679 : : 1, rte_memory_order_relaxed);
680 : : }
681 : : }
682 : :
683 [ + + ]: 6 : if (enabled)
684 : 2 : *enabled = rte_bitset_test(cs->mapped_services, sid);
685 : :
686 : : return 0;
687 : : }
688 : :
689 : : RTE_EXPORT_SYMBOL(rte_service_map_lcore_set)
690 : : int32_t
691 : 6 : rte_service_map_lcore_set(uint32_t id, uint32_t lcore, uint32_t enabled)
692 : : {
693 [ - + ]: 6 : uint32_t on = enabled > 0;
694 : 6 : rte_eal_trace_service_map_lcore(id, lcore, enabled);
695 : 6 : return service_update(id, lcore, &on, 0);
696 : : }
697 : :
698 : : RTE_EXPORT_SYMBOL(rte_service_map_lcore_get)
699 : : int32_t
700 : 2 : rte_service_map_lcore_get(uint32_t id, uint32_t lcore)
701 : : {
702 : : uint32_t enabled;
703 : 2 : int ret = service_update(id, lcore, 0, &enabled);
704 [ + - ]: 2 : if (ret == 0)
705 : 2 : return enabled;
706 : : return ret;
707 : : }
708 : :
709 : : static void
710 : 6 : set_lcore_state(uint32_t lcore, int32_t state)
711 : : {
712 : : /* mark core state in hugepage backed config */
713 : 6 : struct rte_config *cfg = rte_eal_get_configuration();
714 [ - + ]: 6 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
715 : 6 : cfg->lcore_role[lcore] = state;
716 : :
717 : : /* mark state in process local lcore_config */
718 : 6 : lcore_config[lcore].core_role = state;
719 : :
720 : : /* update per-lcore optimized state tracking */
721 [ - + ]: 6 : cs->is_service_core = (state == ROLE_SERVICE);
722 : :
723 : 6 : rte_eal_trace_service_lcore_state_change(lcore, state);
724 : 6 : }
725 : :
726 : : RTE_EXPORT_SYMBOL(rte_service_lcore_reset_all)
727 : : int32_t
728 : 203 : rte_service_lcore_reset_all(void)
729 : : {
730 : : /* loop over cores, reset all mapped services */
731 : : uint32_t i;
732 [ + + ]: 26187 : for (i = 0; i < RTE_MAX_LCORE; i++) {
733 [ + + ]: 25984 : struct core_state *cs = RTE_LCORE_VAR_LCORE(i, lcore_states);
734 : :
735 [ + + ]: 25984 : if (cs->is_service_core) {
736 : 3 : rte_bitset_clear_all(cs->mapped_services, RTE_SERVICE_NUM_MAX);
737 : 3 : set_lcore_state(i, ROLE_RTE);
738 : : /* runstate act as guard variable Use
739 : : * store-release memory order here to synchronize
740 : : * with load-acquire in runstate read functions.
741 : : */
742 : 3 : rte_atomic_store_explicit(&cs->runstate,
743 : : RUNSTATE_STOPPED, rte_memory_order_release);
744 : : }
745 : : }
746 [ + + ]: 13195 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
747 : 12992 : rte_atomic_store_explicit(&rte_services[i].num_mapped_cores, 0,
748 : : rte_memory_order_relaxed);
749 : :
750 : 203 : return 0;
751 : : }
752 : :
753 : : RTE_EXPORT_SYMBOL(rte_service_lcore_add)
754 : : int32_t
755 : 3 : rte_service_lcore_add(uint32_t lcore)
756 : : {
757 [ + - ]: 3 : if (lcore >= RTE_MAX_LCORE)
758 : : return -EINVAL;
759 : :
760 [ + - ]: 3 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
761 [ + - ]: 3 : if (cs->is_service_core)
762 : : return -EALREADY;
763 : :
764 : 3 : set_lcore_state(lcore, ROLE_SERVICE);
765 : :
766 : : /* ensure that after adding a core the mask and state are defaults */
767 : 3 : rte_bitset_clear_all(cs->mapped_services, RTE_SERVICE_NUM_MAX);
768 : : /* Use store-release memory order here to synchronize with
769 : : * load-acquire in runstate read functions.
770 : : */
771 : 3 : rte_atomic_store_explicit(&cs->runstate, RUNSTATE_STOPPED,
772 : : rte_memory_order_release);
773 : :
774 : 3 : return rte_eal_wait_lcore(lcore);
775 : : }
776 : :
777 : : RTE_EXPORT_SYMBOL(rte_service_lcore_del)
778 : : int32_t
779 : 0 : rte_service_lcore_del(uint32_t lcore)
780 : : {
781 [ # # ]: 0 : if (lcore >= RTE_MAX_LCORE)
782 : : return -EINVAL;
783 : :
784 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
785 [ # # ]: 0 : if (!cs->is_service_core)
786 : : return -EINVAL;
787 : :
788 : : /* runstate act as the guard variable. Use load-acquire
789 : : * memory order here to synchronize with store-release
790 : : * in runstate update functions.
791 : : */
792 [ # # ]: 0 : if (rte_atomic_load_explicit(&cs->runstate, rte_memory_order_acquire) !=
793 : : RUNSTATE_STOPPED)
794 : : return -EBUSY;
795 : :
796 : 0 : set_lcore_state(lcore, ROLE_RTE);
797 : :
798 : 0 : rte_smp_wmb();
799 : 0 : return 0;
800 : : }
801 : :
802 : : RTE_EXPORT_SYMBOL(rte_service_lcore_start)
803 : : int32_t
804 : 1 : rte_service_lcore_start(uint32_t lcore)
805 : : {
806 [ + - ]: 1 : if (lcore >= RTE_MAX_LCORE)
807 : : return -EINVAL;
808 : :
809 [ + - ]: 1 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
810 [ + - ]: 1 : if (!cs->is_service_core)
811 : : return -EINVAL;
812 : :
813 : : /* runstate act as the guard variable. Use load-acquire
814 : : * memory order here to synchronize with store-release
815 : : * in runstate update functions.
816 : : */
817 [ + - ]: 1 : if (rte_atomic_load_explicit(&cs->runstate, rte_memory_order_acquire) ==
818 : : RUNSTATE_RUNNING)
819 : : return -EALREADY;
820 : :
821 : : /* set core to run state first, and then launch otherwise it will
822 : : * return immediately as runstate keeps it in the service poll loop
823 : : */
824 : : /* Use load-acquire memory order here to synchronize with
825 : : * store-release in runstate update functions.
826 : : */
827 [ - + ]: 1 : rte_atomic_store_explicit(&cs->runstate, RUNSTATE_RUNNING, rte_memory_order_release);
828 : :
829 : 1 : rte_eal_trace_service_lcore_start(lcore);
830 : :
831 : 1 : int ret = rte_eal_remote_launch(service_runner_func, 0, lcore);
832 : : /* returns -EBUSY if the core is already launched, 0 on success */
833 : 1 : return ret;
834 : : }
835 : :
836 : : RTE_EXPORT_SYMBOL(rte_service_lcore_stop)
837 : : int32_t
838 : 0 : rte_service_lcore_stop(uint32_t lcore)
839 : : {
840 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
841 : :
842 [ # # ]: 0 : if (lcore >= RTE_MAX_LCORE)
843 : : return -EINVAL;
844 : :
845 : : /* runstate act as the guard variable. Use load-acquire
846 : : * memory order here to synchronize with store-release
847 : : * in runstate update functions.
848 : : */
849 [ # # ]: 0 : if (rte_atomic_load_explicit(&cs->runstate, rte_memory_order_acquire) ==
850 : : RUNSTATE_STOPPED)
851 : : return -EALREADY;
852 : :
853 : : uint32_t i;
854 : :
855 [ # # ]: 0 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
856 : 0 : bool enabled = rte_bitset_test(cs->mapped_services, i);
857 : 0 : bool service_running = rte_service_runstate_get(i);
858 : : bool only_core = (1 ==
859 : 0 : rte_atomic_load_explicit(&rte_services[i].num_mapped_cores,
860 : : rte_memory_order_relaxed));
861 : :
862 : : /* if the core is mapped, and the service is running, and this
863 : : * is the only core that is mapped, the service would cease to
864 : : * run if this core stopped, so fail instead.
865 : : */
866 [ # # # # ]: 0 : if (enabled && service_running && only_core)
867 : : return -EBUSY;
868 : : }
869 : :
870 : : /* Use store-release memory order here to synchronize with
871 : : * load-acquire in runstate read functions.
872 : : */
873 [ # # ]: 0 : rte_atomic_store_explicit(&cs->runstate, RUNSTATE_STOPPED,
874 : : rte_memory_order_release);
875 : :
876 : 0 : rte_eal_trace_service_lcore_stop(lcore);
877 : :
878 : 0 : return 0;
879 : : }
880 : :
881 : : static uint64_t
882 : : lcore_attr_get_loops(unsigned int lcore)
883 : : {
884 : : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
885 : :
886 : 0 : return rte_atomic_load_explicit(&cs->loops, rte_memory_order_relaxed);
887 : : }
888 : :
889 : : static uint64_t
890 : : lcore_attr_get_cycles(unsigned int lcore)
891 : : {
892 : : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
893 : :
894 : 0 : return rte_atomic_load_explicit(&cs->cycles, rte_memory_order_relaxed);
895 : : }
896 : :
897 : : static uint64_t
898 : 0 : lcore_attr_get_service_calls(uint32_t service_id, unsigned int lcore)
899 : : {
900 : 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
901 : :
902 : 0 : return rte_atomic_load_explicit(&cs->service_stats[service_id].calls,
903 : : rte_memory_order_relaxed);
904 : : }
905 : :
906 : : static uint64_t
907 : 0 : lcore_attr_get_service_idle_calls(uint32_t service_id, unsigned int lcore)
908 : : {
909 : 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
910 : :
911 : 0 : return rte_atomic_load_explicit(&cs->service_stats[service_id].idle_calls,
912 : : rte_memory_order_relaxed);
913 : : }
914 : :
915 : : static uint64_t
916 : 0 : lcore_attr_get_service_error_calls(uint32_t service_id, unsigned int lcore)
917 : : {
918 : 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
919 : :
920 : 0 : return rte_atomic_load_explicit(&cs->service_stats[service_id].error_calls,
921 : : rte_memory_order_relaxed);
922 : : }
923 : :
924 : : static uint64_t
925 : 0 : lcore_attr_get_service_cycles(uint32_t service_id, unsigned int lcore)
926 : : {
927 : 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
928 : :
929 : 0 : return rte_atomic_load_explicit(&cs->service_stats[service_id].cycles,
930 : : rte_memory_order_relaxed);
931 : : }
932 : :
933 : : typedef uint64_t (*lcore_attr_get_fun)(uint32_t service_id,
934 : : unsigned int lcore);
935 : :
936 : : static uint64_t
937 : : attr_get(uint32_t id, lcore_attr_get_fun lcore_attr_get)
938 : : {
939 : : unsigned int lcore;
940 : : uint64_t sum = 0;
941 : :
942 [ + + - - : 516 : for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
- - + + ]
943 : : struct core_state *cs =
944 [ - + - - : 512 : RTE_LCORE_VAR_LCORE(lcore, lcore_states);
- - - + ]
945 : :
946 [ - + - - : 512 : if (cs->is_service_core)
- - - + ]
947 : 0 : sum += lcore_attr_get(id, lcore);
948 : : }
949 : :
950 : : return sum;
951 : : }
952 : :
953 : : static uint64_t
954 : 2 : attr_get_service_calls(uint32_t service_id)
955 : : {
956 : 2 : return attr_get(service_id, lcore_attr_get_service_calls);
957 : : }
958 : :
959 : : static uint64_t
960 : 0 : attr_get_service_idle_calls(uint32_t service_id)
961 : : {
962 : 0 : return attr_get(service_id, lcore_attr_get_service_idle_calls);
963 : : }
964 : :
965 : : static uint64_t
966 : 0 : attr_get_service_error_calls(uint32_t service_id)
967 : : {
968 : 0 : return attr_get(service_id, lcore_attr_get_service_error_calls);
969 : : }
970 : :
971 : : static uint64_t
972 : 2 : attr_get_service_cycles(uint32_t service_id)
973 : : {
974 : 2 : return attr_get(service_id, lcore_attr_get_service_cycles);
975 : : }
976 : :
977 : : RTE_EXPORT_SYMBOL(rte_service_attr_get)
978 : : int32_t
979 [ # # ]: 0 : rte_service_attr_get(uint32_t id, uint32_t attr_id, uint64_t *attr_value)
980 : : {
981 [ # # ]: 0 : if (!service_valid(id))
982 : : return -EINVAL;
983 : :
984 [ # # ]: 0 : if (!attr_value)
985 : : return -EINVAL;
986 : :
987 [ # # # # : 0 : switch (attr_id) {
# ]
988 : 0 : case RTE_SERVICE_ATTR_CALL_COUNT:
989 : 0 : *attr_value = attr_get_service_calls(id);
990 : 0 : return 0;
991 : 0 : case RTE_SERVICE_ATTR_IDLE_CALL_COUNT:
992 : 0 : *attr_value = attr_get_service_idle_calls(id);
993 : 0 : return 0;
994 : 0 : case RTE_SERVICE_ATTR_ERROR_CALL_COUNT:
995 : 0 : *attr_value = attr_get_service_error_calls(id);
996 : 0 : return 0;
997 : 0 : case RTE_SERVICE_ATTR_CYCLES:
998 : 0 : *attr_value = attr_get_service_cycles(id);
999 : 0 : return 0;
1000 : : default:
1001 : : return -EINVAL;
1002 : : }
1003 : : }
1004 : :
1005 : : RTE_EXPORT_SYMBOL(rte_service_lcore_attr_get)
1006 : : int32_t
1007 : 0 : rte_service_lcore_attr_get(uint32_t lcore, uint32_t attr_id,
1008 : : uint64_t *attr_value)
1009 : : {
1010 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
1011 : :
1012 [ # # ]: 0 : if (lcore >= RTE_MAX_LCORE || !attr_value)
1013 : : return -EINVAL;
1014 : :
1015 [ # # ]: 0 : if (!cs->is_service_core)
1016 : : return -ENOTSUP;
1017 : :
1018 [ # # # ]: 0 : switch (attr_id) {
1019 : : case RTE_SERVICE_LCORE_ATTR_LOOPS:
1020 : 0 : *attr_value = lcore_attr_get_loops(lcore);
1021 : 0 : return 0;
1022 : : case RTE_SERVICE_LCORE_ATTR_CYCLES:
1023 : 0 : *attr_value = lcore_attr_get_cycles(lcore);
1024 : 0 : return 0;
1025 : : default:
1026 : : return -EINVAL;
1027 : : }
1028 : : }
1029 : :
1030 : : RTE_EXPORT_SYMBOL(rte_service_attr_reset_all)
1031 : : int32_t
1032 [ # # ]: 0 : rte_service_attr_reset_all(uint32_t id)
1033 : : {
1034 : : unsigned int lcore;
1035 : :
1036 [ # # ]: 0 : if (!service_valid(id))
1037 : : return -EINVAL;
1038 : :
1039 [ # # ]: 0 : for (lcore = 0; lcore < RTE_MAX_LCORE; lcore++) {
1040 : : struct core_state *cs =
1041 : 0 : RTE_LCORE_VAR_LCORE(lcore, lcore_states);
1042 : :
1043 : 0 : cs->service_stats[id] = (struct service_stats) {};
1044 : : }
1045 : :
1046 : : return 0;
1047 : : }
1048 : :
1049 : : RTE_EXPORT_SYMBOL(rte_service_lcore_attr_reset_all)
1050 : : int32_t
1051 : 0 : rte_service_lcore_attr_reset_all(uint32_t lcore)
1052 : : {
1053 [ # # ]: 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
1054 : :
1055 [ # # ]: 0 : if (lcore >= RTE_MAX_LCORE)
1056 : : return -EINVAL;
1057 : :
1058 [ # # ]: 0 : if (!cs->is_service_core)
1059 : : return -ENOTSUP;
1060 : :
1061 : 0 : cs->loops = 0;
1062 : :
1063 : 0 : return 0;
1064 : : }
1065 : :
1066 : : static void
1067 : 2 : service_dump_one(FILE *f, uint32_t id)
1068 : : {
1069 : : struct rte_service_spec_impl *s;
1070 : : uint64_t service_calls;
1071 : : uint64_t service_cycles;
1072 : :
1073 : 2 : service_calls = attr_get_service_calls(id);
1074 : 2 : service_cycles = attr_get_service_cycles(id);
1075 : :
1076 : : /* avoid divide by zero */
1077 : : if (service_calls == 0)
1078 : : service_calls = 1;
1079 : :
1080 : : s = service_get(id);
1081 : :
1082 : 2 : fprintf(f, " %s: stats %d\tcalls %"PRIu64"\tcycles %"
1083 : : PRIu64"\tavg: %"PRIu64"\n",
1084 : 2 : s->spec.name, service_stats_enabled(s), service_calls,
1085 : : service_cycles, service_cycles / service_calls);
1086 : 2 : }
1087 : :
1088 : : static void
1089 : 0 : service_dump_calls_per_lcore(FILE *f, uint32_t lcore)
1090 : : {
1091 : : uint32_t i;
1092 : 0 : struct core_state *cs = RTE_LCORE_VAR_LCORE(lcore, lcore_states);
1093 : :
1094 : : fprintf(f, "%02d\t", lcore);
1095 [ # # ]: 0 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
1096 [ # # ]: 0 : if (!service_registered(i))
1097 : 0 : continue;
1098 : 0 : fprintf(f, "%"PRIu64"\t", cs->service_stats[i].calls);
1099 : : }
1100 : : fprintf(f, "\n");
1101 : 0 : }
1102 : :
1103 : : RTE_EXPORT_SYMBOL(rte_service_dump)
1104 : : int32_t
1105 : 2 : rte_service_dump(FILE *f, uint32_t id)
1106 : : {
1107 : : uint32_t i;
1108 : : int print_one = (id != UINT32_MAX);
1109 : :
1110 : : /* print only the specified service */
1111 [ + - ]: 2 : if (print_one) {
1112 : : struct rte_service_spec_impl *s;
1113 [ + - ]: 2 : SERVICE_VALID_GET_OR_ERR_RET(id, s, -EINVAL);
1114 : 2 : fprintf(f, "Service %s Summary\n", s->spec.name);
1115 : 2 : service_dump_one(f, id);
1116 : 2 : return 0;
1117 : : }
1118 : :
1119 : : /* print all services, as UINT32_MAX was passed as id */
1120 : : fprintf(f, "Services Summary\n");
1121 [ # # ]: 0 : for (i = 0; i < RTE_SERVICE_NUM_MAX; i++) {
1122 [ # # ]: 0 : if (!service_registered(i))
1123 : 0 : continue;
1124 : 0 : service_dump_one(f, i);
1125 : : }
1126 : :
1127 : : fprintf(f, "Service Cores Summary\n");
1128 [ # # ]: 0 : for (i = 0; i < RTE_MAX_LCORE; i++) {
1129 [ # # ]: 0 : if (lcore_config[i].core_role != ROLE_SERVICE)
1130 : 0 : continue;
1131 : :
1132 : 0 : service_dump_calls_per_lcore(f, i);
1133 : : }
1134 : :
1135 : : return 0;
1136 : : }
|