LCOV - code coverage report
Current view: top level - lib/eal/common - rte_service.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 225 358 62.8 %
Date: 2025-05-01 17:49:45 Functions: 32 48 66.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 162 352 46.0 %

           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                 :            : }

Generated by: LCOV version 1.14