LCOV - code coverage report
Current view: top level - vlib - threads.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 62 71 87.3 %
Date: 2023-10-26 01:39:38 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #ifndef included_vlib_threads_h
      16             : #define included_vlib_threads_h
      17             : 
      18             : #include <vlib/main.h>
      19             : #include <vppinfra/callback.h>
      20             : #include <linux/sched.h>
      21             : 
      22             : void vlib_set_thread_name (char *name);
      23             : 
      24             : /* arg is actually a vlib__thread_t * */
      25             : typedef void (vlib_thread_function_t) (void *arg);
      26             : 
      27             : typedef struct vlib_thread_registration_
      28             : {
      29             :   /* constructor generated list of thread registrations */
      30             :   struct vlib_thread_registration_ *next;
      31             : 
      32             :   /* config parameters */
      33             :   char *name;
      34             :   char *short_name;
      35             :   vlib_thread_function_t *function;
      36             :   uword mheap_size;
      37             :   int fixed_count;
      38             :   u32 count;
      39             :   int no_data_structure_clone;
      40             :   u32 frame_queue_nelts;
      41             : 
      42             :   /* All threads of this type run on pthreads */
      43             :   int use_pthreads;
      44             :   u32 first_index;
      45             :   uword *coremask;
      46             : } vlib_thread_registration_t;
      47             : 
      48             : /*
      49             :  * Frames have their cpu / vlib_main_t index in the low-order N bits
      50             :  * Make VLIB_MAX_CPUS a power-of-two, please...
      51             :  */
      52             : 
      53             : #ifndef VLIB_MAX_CPUS
      54             : #define VLIB_MAX_CPUS 256
      55             : #endif
      56             : 
      57             : #if VLIB_MAX_CPUS > CLIB_MAX_MHEAPS
      58             : #error Please increase number of per-cpu mheaps
      59             : #endif
      60             : 
      61             : #define VLIB_CPU_MASK (VLIB_MAX_CPUS - 1)       /* 0x3f, max */
      62             : #define VLIB_OFFSET_MASK (~VLIB_CPU_MASK)
      63             : 
      64             : #define VLIB_LOG2_THREAD_STACK_SIZE (21)
      65             : #define VLIB_THREAD_STACK_SIZE (1<<VLIB_LOG2_THREAD_STACK_SIZE)
      66             : 
      67             : typedef struct
      68             : {
      69             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      70             :   volatile u32 valid;
      71             :   u32 maybe_trace : 1;
      72             :   u32 n_vectors;
      73             :   u32 offset;
      74             :   STRUCT_MARK (end_of_reset);
      75             : 
      76             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
      77             :   u32 buffer_index[VLIB_FRAME_SIZE];
      78             :   u32 aux_data[VLIB_FRAME_SIZE];
      79             : }
      80             : vlib_frame_queue_elt_t;
      81             : 
      82             : typedef struct
      83             : {
      84             :   /* First cache line */
      85             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      86             :   volatile u32 *wait_at_barrier;
      87             :   volatile u32 *workers_at_barrier;
      88             : 
      89             :   /* Second Cache Line */
      90             :     CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
      91             :   void *thread_mheap;
      92             :   u8 *thread_stack;
      93             :   void (*thread_function) (void *);
      94             :   void *thread_function_arg;
      95             :   i64 recursion_level;
      96             :   elog_track_t elog_track;
      97             :   u32 instance_id;
      98             :   vlib_thread_registration_t *registration;
      99             :   u8 *name;
     100             :   u64 barrier_sync_count;
     101             :   u8 barrier_elog_enabled;
     102             :   const char *barrier_caller;
     103             :   const char *barrier_context;
     104             :   volatile u32 *node_reforks_required;
     105             :   volatile u32 wait_before_barrier;
     106             :   volatile u32 workers_before_barrier;
     107             :   volatile u32 done_work_before_barrier;
     108             : 
     109             :   long lwp;
     110             :   int cpu_id;
     111             :   int core_id;
     112             :   int numa_id;
     113             :   pthread_t thread_id;
     114             : } vlib_worker_thread_t;
     115             : 
     116             : extern vlib_worker_thread_t *vlib_worker_threads;
     117             : 
     118             : typedef struct
     119             : {
     120             :   /* static data */
     121             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
     122             :   vlib_frame_queue_elt_t *elts;
     123             :   u64 vector_threshold;
     124             :   u64 trace;
     125             :   u32 nelts;
     126             : 
     127             :   /* modified by enqueue side  */
     128             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
     129             :   volatile u64 tail;
     130             : 
     131             :   /* modified by dequeue side  */
     132             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);
     133             :   volatile u64 head;
     134             : }
     135             : vlib_frame_queue_t;
     136             : 
     137             : struct vlib_frame_queue_main_t_;
     138             : typedef u32 (vlib_frame_queue_dequeue_fn_t) (
     139             :   vlib_main_t *vm, struct vlib_frame_queue_main_t_ *fqm);
     140             : typedef struct vlib_frame_queue_main_t_
     141             : {
     142             :   u32 node_index;
     143             :   u32 frame_queue_nelts;
     144             : 
     145             :   vlib_frame_queue_t **vlib_frame_queues;
     146             : 
     147             :   /* for frame queue tracing */
     148             :   frame_queue_trace_t *frame_queue_traces;
     149             :   frame_queue_nelt_counter_t *frame_queue_histogram;
     150             :   vlib_frame_queue_dequeue_fn_t *frame_queue_dequeue_fn;
     151             : } vlib_frame_queue_main_t;
     152             : 
     153             : typedef struct
     154             : {
     155             :   uword node_index;
     156             :   uword type_opaque;
     157             :   uword data;
     158             : } vlib_process_signal_event_mt_args_t;
     159             : 
     160             : /* Called early, in thread 0's context */
     161             : clib_error_t *vlib_thread_init (vlib_main_t * vm);
     162             : 
     163             : void vlib_worker_thread_node_runtime_update (void);
     164             : 
     165             : void vlib_create_worker_threads (vlib_main_t * vm, int n,
     166             :                                  void (*thread_function) (void *));
     167             : 
     168             : void vlib_worker_thread_init (vlib_worker_thread_t * w);
     169             : u32 vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts);
     170             : 
     171             : /* Check for a barrier sync request every 30ms */
     172             : #define BARRIER_SYNC_DELAY (0.030000)
     173             : 
     174             : #if CLIB_DEBUG > 0
     175             : /* long barrier timeout, for gdb... */
     176             : #define BARRIER_SYNC_TIMEOUT (600.1)
     177             : #else
     178             : #define BARRIER_SYNC_TIMEOUT (1.0)
     179             : #endif
     180             : 
     181             : #define vlib_worker_thread_barrier_sync(X) {vlib_worker_thread_barrier_sync_int(X, __FUNCTION__);}
     182             : 
     183             : void vlib_worker_thread_barrier_sync_int (vlib_main_t * vm,
     184             :                                           const char *func_name);
     185             : void vlib_worker_thread_barrier_release (vlib_main_t * vm);
     186             : u8 vlib_worker_thread_barrier_held (void);
     187             : void vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm);
     188             : void vlib_worker_thread_node_refork (void);
     189             : /**
     190             :  * Wait until each of the workers has been once around the track
     191             :  */
     192             : void vlib_worker_wait_one_loop (void);
     193             : 
     194             : static_always_inline uword
     195   121054426 : vlib_get_thread_index (void)
     196             : {
     197   121054426 :   return __os_thread_index;
     198             : }
     199             : 
     200             : always_inline void
     201      155689 : vlib_smp_unsafe_warning (void)
     202             : {
     203             :   if (CLIB_DEBUG > 0)
     204             :     {
     205      155689 :       if (vlib_get_thread_index ())
     206           0 :         fformat (stderr, "%s: SMP unsafe warning...\n", __FUNCTION__);
     207             :     }
     208      155689 : }
     209             : 
     210             : always_inline int
     211      201967 : __foreach_vlib_main_helper (vlib_main_t *ii, vlib_main_t **p)
     212             : {
     213             :   vlib_main_t *vm;
     214      201967 :   u32 index = ii - (vlib_main_t *) 0;
     215             : 
     216      201967 :   if (index >= vec_len (vlib_global_main.vlib_mains))
     217       95323 :     return 0;
     218             : 
     219      106644 :   *p = vm = vlib_global_main.vlib_mains[index];
     220      106644 :   ASSERT (index == 0 || vm->parked_at_barrier == 1);
     221      106644 :   return 1;
     222             : }
     223             : 
     224             : #define foreach_vlib_main()                                                   \
     225             :   for (vlib_main_t *ii = 0, *this_vlib_main;                                  \
     226             :        __foreach_vlib_main_helper (ii, &this_vlib_main); ii++)                \
     227             :     if (this_vlib_main)
     228             : 
     229             : #define foreach_sched_policy \
     230             :   _(SCHED_OTHER, OTHER, "other") \
     231             :   _(SCHED_BATCH, BATCH, "batch") \
     232             :   _(SCHED_IDLE, IDLE, "idle")   \
     233             :   _(SCHED_FIFO, FIFO, "fifo")   \
     234             :   _(SCHED_RR, RR, "rr")
     235             : 
     236             : typedef enum
     237             : {
     238             : #define _(v,f,s) SCHED_POLICY_##f = v,
     239             :   foreach_sched_policy
     240             : #undef _
     241             :     SCHED_POLICY_N,
     242             : } sched_policy_t;
     243             : 
     244             : typedef struct
     245             : {
     246             :   /* Link list of registrations, built by constructors */
     247             :   vlib_thread_registration_t *next;
     248             : 
     249             :   /* Vector of registrations, w/ non-data-structure clones at the top */
     250             :   vlib_thread_registration_t **registrations;
     251             : 
     252             :   uword *thread_registrations_by_name;
     253             : 
     254             :   vlib_worker_thread_t *worker_threads;
     255             : 
     256             :   int use_pthreads;
     257             : 
     258             :   /* Number of vlib_main / vnet_main clones */
     259             :   u32 n_vlib_mains;
     260             : 
     261             :   /* Number of thread stacks to create */
     262             :   u32 n_thread_stacks;
     263             : 
     264             :   /* Number of pthreads */
     265             :   u32 n_pthreads;
     266             : 
     267             :   /* Number of threads */
     268             :   u32 n_threads;
     269             : 
     270             :   /* Number of cores to skip, must match the core mask */
     271             :   u32 skip_cores;
     272             : 
     273             :   /* Thread prefix name */
     274             :   u8 *thread_prefix;
     275             : 
     276             :   /* main thread lcore */
     277             :   u32 main_lcore;
     278             : 
     279             :   /* Bitmap of available CPU cores */
     280             :   uword *cpu_core_bitmap;
     281             : 
     282             :   /* Bitmap of available CPU sockets (NUMA nodes) */
     283             :   uword *cpu_socket_bitmap;
     284             : 
     285             :   /* Worker handoff queues */
     286             :   vlib_frame_queue_main_t *frame_queue_mains;
     287             : 
     288             :   /* worker thread initialization barrier */
     289             :   volatile u32 worker_thread_release;
     290             : 
     291             :   /* scheduling policy */
     292             :   u32 sched_policy;
     293             : 
     294             :   /* scheduling policy priority */
     295             :   u32 sched_priority;
     296             : 
     297             :   /* NUMA-bound heap size */
     298             :   uword numa_heap_size;
     299             : 
     300             : } vlib_thread_main_t;
     301             : 
     302             : extern vlib_thread_main_t vlib_thread_main;
     303             : 
     304             : #include <vlib/global_funcs.h>
     305             : 
     306             : #define VLIB_REGISTER_THREAD(x,...)                     \
     307             :   __VA_ARGS__ vlib_thread_registration_t x;             \
     308             : static void __vlib_add_thread_registration_##x (void)   \
     309             :   __attribute__((__constructor__)) ;                    \
     310             : static void __vlib_add_thread_registration_##x (void)   \
     311             : {                                                       \
     312             :   vlib_thread_main_t * tm = &vlib_thread_main;          \
     313             :   x.next = tm->next;                                    \
     314             :   tm->next = &x;                                        \
     315             : }                                                       \
     316             : static void __vlib_rm_thread_registration_##x (void)    \
     317             :   __attribute__((__destructor__)) ;                     \
     318             : static void __vlib_rm_thread_registration_##x (void)    \
     319             : {                                                       \
     320             :   vlib_thread_main_t * tm = &vlib_thread_main;          \
     321             :   VLIB_REMOVE_FROM_LINKED_LIST (tm->next, &x, next);    \
     322             : }                                                       \
     323             : __VA_ARGS__ vlib_thread_registration_t x
     324             : 
     325             : always_inline u32
     326      397468 : vlib_num_workers ()
     327             : {
     328      397468 :   return vlib_thread_main.n_vlib_mains - 1;
     329             : }
     330             : 
     331             : always_inline u32
     332           9 : vlib_get_worker_thread_index (u32 worker_index)
     333             : {
     334           9 :   return worker_index + 1;
     335             : }
     336             : 
     337             : always_inline u32
     338           0 : vlib_get_worker_index (u32 thread_index)
     339             : {
     340           0 :   return thread_index - 1;
     341             : }
     342             : 
     343             : always_inline u32
     344        1558 : vlib_get_current_worker_index ()
     345             : {
     346        1558 :   return vlib_get_thread_index () - 1;
     347             : }
     348             : 
     349             : static inline void
     350    33357900 : vlib_worker_thread_barrier_check (void)
     351             : {
     352    33357900 :   if (PREDICT_FALSE (*vlib_worker_threads->wait_at_barrier))
     353             :     {
     354       41023 :       vlib_global_main_t *vgm = vlib_get_global_main ();
     355       40588 :       vlib_main_t *vm = vlib_get_main ();
     356       40042 :       u32 thread_index = vm->thread_index;
     357       40042 :       f64 t = vlib_time_now (vm);
     358             : 
     359       39740 :       if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
     360           0 :         clib_call_callbacks (vm->barrier_perf_callbacks, vm,
     361             :                              vm->clib_time.last_cpu_time, 0 /* enter */ );
     362             : 
     363       39740 :       if (PREDICT_FALSE (vlib_worker_threads->barrier_elog_enabled))
     364             :         {
     365           3 :           vlib_worker_thread_t *w = vlib_worker_threads + thread_index;
     366             :           /* *INDENT-OFF* */
     367             :           ELOG_TYPE_DECLARE (e) = {
     368             :             .format = "barrier-wait-thread-%d",
     369             :             .format_args = "i4",
     370             :           };
     371             :           /* *INDENT-ON* */
     372             : 
     373             :           struct
     374             :           {
     375             :             u32 thread_index;
     376             :           } __clib_packed *ed;
     377             : 
     378           3 :           ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
     379           3 :           ed->thread_index = thread_index;
     380             :         }
     381             : 
     382             :       if (CLIB_DEBUG > 0)
     383             :         {
     384       39740 :           vm = vlib_get_main ();
     385       39280 :           vm->parked_at_barrier = 1;
     386             :         }
     387       39280 :       clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, 1);
     388  1919840000 :       while (*vlib_worker_threads->wait_at_barrier)
     389             :         ;
     390             : 
     391             :       /*
     392             :        * Recompute the offset from thread-0 time.
     393             :        * Note that vlib_time_now adds vm->time_offset, so
     394             :        * clear it first. Save the resulting idea of "now", to
     395             :        * see how well we're doing. See show_clock_command_fn(...)
     396             :        */
     397             :       {
     398             :         f64 now;
     399       39280 :         vm->time_offset = 0.0;
     400       39280 :         now = vlib_time_now (vm);
     401       28133 :         vm->time_offset = vgm->vlib_mains[0]->time_last_barrier_release - now;
     402       28133 :         vm->time_last_barrier_release = vlib_time_now (vm);
     403             :       }
     404             : 
     405             :       if (CLIB_DEBUG > 0)
     406       21656 :         vm->parked_at_barrier = 0;
     407       21656 :       clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, -1);
     408             : 
     409       21656 :       if (PREDICT_FALSE (*vlib_worker_threads->node_reforks_required))
     410             :         {
     411         946 :           if (PREDICT_FALSE (vlib_worker_threads->barrier_elog_enabled))
     412             :             {
     413           0 :               t = vlib_time_now (vm) - t;
     414           0 :               vlib_worker_thread_t *w = vlib_worker_threads + thread_index;
     415             :               /* *INDENT-OFF* */
     416             :               ELOG_TYPE_DECLARE (e) = {
     417             :                 .format = "barrier-refork-thread-%d",
     418             :                 .format_args = "i4",
     419             :               };
     420             :               /* *INDENT-ON* */
     421             : 
     422             :               struct
     423             :               {
     424             :                 u32 thread_index;
     425             :               } __clib_packed *ed;
     426             : 
     427           0 :               ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e,
     428             :                                     w->elog_track);
     429           0 :               ed->thread_index = thread_index;
     430             :             }
     431             : 
     432         946 :           vlib_worker_thread_node_refork ();
     433        1051 :           clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required,
     434             :                                  -1);
     435   337280000 :           while (*vlib_worker_threads->node_reforks_required)
     436             :             ;
     437             :         }
     438       21761 :       if (PREDICT_FALSE (vlib_worker_threads->barrier_elog_enabled))
     439             :         {
     440           3 :           t = vlib_time_now (vm) - t;
     441           3 :           vlib_worker_thread_t *w = vlib_worker_threads + thread_index;
     442             :           /* *INDENT-OFF* */
     443             :           ELOG_TYPE_DECLARE (e) = {
     444             :             .format = "barrier-released-thread-%d: %dus",
     445             :             .format_args = "i4i4",
     446             :           };
     447             :           /* *INDENT-ON* */
     448             : 
     449             :           struct
     450             :           {
     451             :             u32 thread_index;
     452             :             u32 duration;
     453             :           } __clib_packed *ed;
     454             : 
     455           3 :           ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
     456           3 :           ed->thread_index = thread_index;
     457           3 :           ed->duration = (int) (1000000.0 * t);
     458             :         }
     459             : 
     460       21761 :       if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
     461           0 :         clib_call_callbacks (vm->barrier_perf_callbacks, vm,
     462             :                              vm->clib_time.last_cpu_time, 1 /* leave */ );
     463             :     }
     464    33338700 : }
     465             : 
     466             : always_inline vlib_main_t *
     467        1499 : vlib_get_worker_vlib_main (u32 worker_index)
     468             : {
     469             :   vlib_main_t *vm;
     470        1499 :   vlib_thread_main_t *tm = &vlib_thread_main;
     471        1499 :   ASSERT (worker_index < tm->n_vlib_mains - 1);
     472        1499 :   vm = vlib_get_main_by_index (worker_index + 1);
     473        1499 :   ASSERT (vm);
     474        1499 :   return vm;
     475             : }
     476             : 
     477             : static inline u8
     478         836 : vlib_thread_is_main_w_barrier (void)
     479             : {
     480         836 :   return (!vlib_num_workers ()
     481         848 :           || ((vlib_get_thread_index () == 0
     482          12 :                && vlib_worker_threads->wait_at_barrier[0])));
     483             : }
     484             : 
     485             : u8 *vlib_thread_stack_init (uword thread_index);
     486             : extern void *rpc_call_main_thread_cb_fn;
     487             : 
     488             : void
     489             : vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
     490             :                                      args);
     491             : void vlib_rpc_call_main_thread (void *function, u8 * args, u32 size);
     492             : void vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id);
     493             : vlib_thread_main_t *vlib_get_thread_main_not_inline (void);
     494             : 
     495             : /**
     496             :  * Force workers sync from within worker
     497             :  *
     498             :  * Must be paired with @ref vlib_workers_continue
     499             :  */
     500             : void vlib_workers_sync (void);
     501             : /**
     502             :  * Release barrier after workers sync
     503             :  */
     504             : void vlib_workers_continue (void);
     505             : 
     506             : #endif /* included_vlib_threads_h */
     507             : 
     508             : /*
     509             :  * fd.io coding-style-patch-verification: ON
     510             :  *
     511             :  * Local Variables:
     512             :  * eval: (c-set-style "gnu")
     513             :  * End:
     514             :  */

Generated by: LCOV version 1.14