perfmon: new perfmon plugin
[vpp.git] / src / vlib / main.h
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 /*
16  * main.h: VLIB main data structure
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #ifndef included_vlib_main_h
41 #define included_vlib_main_h
42
43 #include <vppinfra/callback_data.h>
44 #include <vppinfra/elog.h>
45 #include <vppinfra/format.h>
46 #include <vppinfra/longjmp.h>
47 #include <vppinfra/pool.h>
48 #include <vppinfra/random_buffer.h>
49 #include <vppinfra/time.h>
50 #include <vppinfra/pcap.h>
51
52 #include <pthread.h>
53
54
55 /* By default turn off node/error event logging.
56    Override with -DVLIB_ELOG_MAIN_LOOP */
57 #ifndef VLIB_ELOG_MAIN_LOOP
58 #define VLIB_ELOG_MAIN_LOOP 0
59 #endif
60
61 typedef struct
62 {
63   /* Trace RX pkts */
64   u8 pcap_rx_enable;
65   /* Trace TX pkts */
66   u8 pcap_tx_enable;
67   /* Trace drop pkts */
68   u8 pcap_drop_enable;
69   u8 pad1;
70   u32 max_bytes_per_pkt;
71   u32 pcap_sw_if_index;
72   pcap_main_t pcap_main;
73   u32 filter_classify_table_index;
74 } vnet_pcap_t;
75
76 typedef struct
77 {
78   u8 trace_filter_enable;
79   u32 classify_table_index;
80 } vlib_trace_filter_t;
81
82 typedef enum
83 {
84   VLIB_NODE_RUNTIME_PERF_BEFORE,
85   VLIB_NODE_RUNTIME_PERF_AFTER,
86   VLIB_NODE_RUNTIME_PERF_RESET,
87 } vlib_node_runtime_perf_call_type_t;
88
89 typedef struct
90 {
91   struct vlib_main_t *vm;
92   vlib_node_runtime_t *node;
93   vlib_frame_t *frame;
94   uword packets;
95   u64 cpu_time_now;
96   vlib_node_runtime_perf_call_type_t call_type;
97 } vlib_node_runtime_perf_callback_args_t;
98
99 struct vlib_node_runtime_perf_callback_data_t;
100
101 typedef void (*vlib_node_runtime_perf_callback_fp_t)
102   (struct vlib_node_runtime_perf_callback_data_t * data,
103    vlib_node_runtime_perf_callback_args_t * args);
104
105 typedef struct vlib_node_runtime_perf_callback_data_t
106 {
107   vlib_node_runtime_perf_callback_fp_t fp;
108   union
109   {
110     void *v;
111     u64 u;
112   } u[3];
113 } vlib_node_runtime_perf_callback_data_t;
114
115 clib_callback_data_typedef (vlib_node_runtime_perf_callback_set_t,
116                             vlib_node_runtime_perf_callback_data_t);
117
118 typedef struct vlib_main_t
119 {
120   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
121   /* Instruction level timing state. */
122   clib_time_t clib_time;
123   /* Offset from main thread time */
124   f64 time_offset;
125   f64 time_last_barrier_release;
126
127   /* Time stamp of last node dispatch. */
128   u64 cpu_time_last_node_dispatch;
129
130   /* Time stamp when main loop was entered (time 0). */
131   u64 cpu_time_main_loop_start;
132
133   /* Incremented once for each main loop. */
134   volatile u32 main_loop_count;
135
136   /* Count of vectors processed this main loop. */
137   u32 main_loop_vectors_processed;
138   u32 main_loop_nodes_processed;
139
140   /* Internal node vectors, calls */
141   u64 internal_node_vectors;
142   u64 internal_node_calls;
143   u64 internal_node_vectors_last_clear;
144   u64 internal_node_calls_last_clear;
145
146   /* Instantaneous vector rate */
147   u32 internal_node_last_vectors_per_main_loop;
148
149   /* Main loop hw / sw performance counters */
150   vlib_node_runtime_perf_callback_set_t vlib_node_runtime_perf_callbacks;
151
152   /* dispatch wrapper function */
153   vlib_node_function_t *dispatch_wrapper_fn;
154
155   /* Every so often we switch to the next counter. */
156 #define VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE 7
157
158   /* Jump target to exit main loop with given code. */
159   u32 main_loop_exit_set;
160   /* Set e.g. in the SIGTERM signal handler, checked in a safe place... */
161   volatile u32 main_loop_exit_now;
162   clib_longjmp_t main_loop_exit;
163 #define VLIB_MAIN_LOOP_EXIT_NONE 0
164 #define VLIB_MAIN_LOOP_EXIT_PANIC 1
165   /* Exit via CLI. */
166 #define VLIB_MAIN_LOOP_EXIT_CLI 2
167
168   /* Error marker to use when exiting main loop. */
169   clib_error_t *main_loop_error;
170
171   /* Name for e.g. syslog. */
172   char *name;
173
174   /* Start of the heap. */
175   void *heap_base;
176
177   /* Truncated version, to create frame indices */
178   void *heap_aligned_base;
179
180   /* Size of the heap */
181   uword heap_size;
182
183   /* buffer main structure. */
184   vlib_buffer_main_t *buffer_main;
185
186   /* physical memory main structure. */
187   vlib_physmem_main_t physmem_main;
188
189   /* Node graph main structure. */
190   vlib_node_main_t node_main;
191
192   /* Command line interface. */
193   vlib_cli_main_t cli_main;
194
195   /* Packet trace buffer. */
196   vlib_trace_main_t trace_main;
197
198   /* Pcap dispatch trace main */
199   pcap_main_t dispatch_pcap_main;
200   uword dispatch_pcap_enable;
201   uword dispatch_pcap_postmortem;
202   u32 *dispatch_buffer_trace_nodes;
203   u8 *pcap_buffer;
204
205   /* pcap rx / tx tracing */
206   vnet_pcap_t pcap;
207
208   /* Packet trace capture filter */
209   vlib_trace_filter_t trace_filter;
210
211   /* Error handling. */
212   vlib_error_main_t error_main;
213
214   /* Punt packets to underlying operating system for when fast switching
215      code does not know what to do. */
216   void (*os_punt_frame) (struct vlib_main_t * vm,
217                          struct vlib_node_runtime_t * node,
218                          vlib_frame_t * frame);
219
220   /* Stream index to use for distribution when MC is enabled. */
221   u32 mc_stream_index;
222
223   vlib_one_time_waiting_process_t *procs_waiting_for_mc_stream_join;
224
225   /* Event logger. */
226   elog_main_t elog_main;
227   u32 configured_elog_ring_size;
228
229   /* Event logger trace flags */
230   int elog_trace_api_messages;
231   int elog_trace_cli_commands;
232   int elog_trace_graph_dispatch;
233   int elog_trace_graph_circuit;
234   u32 elog_trace_graph_circuit_node_index;
235
236   /* Node call and return event types. */
237   elog_event_type_t *node_call_elog_event_types;
238   elog_event_type_t *node_return_elog_event_types;
239
240   elog_event_type_t *error_elog_event_types;
241
242   /* Seed for random number generator. */
243   uword random_seed;
244
245   /* Buffer of random data for various uses. */
246   clib_random_buffer_t random_buffer;
247
248   /* Hash table to record which init functions have been called. */
249   uword *init_functions_called;
250
251   /* thread, cpu and numa_node indices */
252   u32 thread_index;
253   u32 cpu_id;
254   u32 numa_node;
255
256   /* List of init functions to call, setup by constructors */
257   _vlib_init_function_list_elt_t *init_function_registrations;
258   _vlib_init_function_list_elt_t *worker_init_function_registrations;
259   _vlib_init_function_list_elt_t *main_loop_enter_function_registrations;
260   _vlib_init_function_list_elt_t *main_loop_exit_function_registrations;
261   _vlib_init_function_list_elt_t *api_init_function_registrations;
262   vlib_config_function_runtime_t *config_function_registrations;
263
264   /* control-plane API queue signal pending, length indication */
265   volatile u32 queue_signal_pending;
266   volatile u32 api_queue_nonempty;
267   void (*queue_signal_callback) (struct vlib_main_t *);
268   u8 **argv;
269
270   /* Top of (worker) dispatch loop callback */
271   void (**volatile worker_thread_main_loop_callbacks)
272     (struct vlib_main_t *, u64 t);
273   void (**volatile worker_thread_main_loop_callback_tmp)
274     (struct vlib_main_t *, u64 t);
275   clib_spinlock_t worker_thread_main_loop_callback_lock;
276
277   /* debugging */
278   volatile int parked_at_barrier;
279
280   /* Attempt to do a post-mortem elog dump */
281   int elog_post_mortem_dump;
282
283   /*
284    * Need to call vlib_worker_thread_node_runtime_update before
285    * releasing worker thread barrier. Only valid in vlib_global_main.
286    */
287   int need_vlib_worker_thread_node_runtime_update;
288
289   /* Dispatch loop time accounting */
290   u64 loops_this_reporting_interval;
291   f64 loop_interval_end;
292   f64 loop_interval_start;
293   f64 loops_per_second;
294   f64 seconds_per_loop;
295   f64 damping_constant;
296
297   /*
298    * Barrier epoch - Set to current time, each time barrier_sync or
299    * barrier_release is called with zero recursion.
300    */
301   f64 barrier_epoch;
302
303   /* Earliest barrier can be closed again */
304   f64 barrier_no_close_before;
305
306   /* Barrier counter callback */
307   void (**volatile barrier_perf_callbacks)
308     (struct vlib_main_t *, u64 t, int leave);
309   void (**volatile barrier_perf_callbacks_tmp)
310     (struct vlib_main_t *, u64 t, int leave);
311
312   /* Need to check the frame queues */
313   volatile uword check_frame_queues;
314
315   /* RPC requests, main thread only */
316   uword *pending_rpc_requests;
317   uword *processing_rpc_requests;
318   clib_spinlock_t pending_rpc_lock;
319
320   /* buffer fault injector */
321   u32 buffer_alloc_success_seed;
322   f64 buffer_alloc_success_rate;
323
324 #ifdef CLIB_SANITIZE_ADDR
325   /* address sanitizer stack save */
326   void *asan_stack_save;
327 #endif
328 } vlib_main_t;
329
330 /* Global main structure. */
331 extern vlib_main_t vlib_global_main;
332
333 void vlib_worker_loop (vlib_main_t * vm);
334
335 always_inline f64
336 vlib_time_now (vlib_main_t * vm)
337 {
338 #if CLIB_DEBUG > 0
339   extern __thread uword __os_thread_index;
340 #endif
341   /*
342    * Make sure folks don't pass &vlib_global_main from a worker thread.
343    */
344   ASSERT (vm->thread_index == __os_thread_index);
345   return clib_time_now (&vm->clib_time) + vm->time_offset;
346 }
347
348 always_inline f64
349 vlib_time_now_ticks (vlib_main_t * vm, u64 n)
350 {
351   return clib_time_now_internal (&vm->clib_time, n);
352 }
353
354 /* Busy wait for specified time. */
355 always_inline void
356 vlib_time_wait (vlib_main_t * vm, f64 wait)
357 {
358   f64 t = vlib_time_now (vm);
359   f64 limit = t + wait;
360   while (t < limit)
361     t = vlib_time_now (vm);
362 }
363
364 /* Time a piece of code. */
365 #define vlib_time_code(vm,body)                 \
366 do {                                            \
367     f64 _t[2];                                  \
368     _t[0] = vlib_time_now (vm);                 \
369     do { body; } while (0);                     \
370     _t[1] = vlib_time_now (vm);                 \
371     clib_warning ("%.7e", _t[1] - _t[0]);       \
372 } while (0)
373
374 #define vlib_wait_with_timeout(vm,suspend_time,timeout_time,test)       \
375 ({                                                                      \
376     uword __vlib_wait_with_timeout = 0;                                 \
377     f64 __vlib_wait_time = 0;                                           \
378     while (! (__vlib_wait_with_timeout = (test))                        \
379            && __vlib_wait_time < (timeout_time))                        \
380       {                                                                 \
381         vlib_process_suspend (vm, suspend_time);                        \
382         __vlib_wait_time += suspend_time;                               \
383       }                                                                 \
384     __vlib_wait_with_timeout;                                           \
385 })
386
387 always_inline void
388 vlib_panic_with_error (vlib_main_t * vm, clib_error_t * error)
389 {
390   vm->main_loop_error = error;
391   clib_longjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_PANIC);
392 }
393
394 #define vlib_panic_with_msg(vm,args...) \
395   vlib_panic_with_error (vm, clib_error_return (0, args))
396
397 always_inline void
398 vlib_panic (vlib_main_t * vm)
399 {
400   vlib_panic_with_error (vm, 0);
401 }
402
403
404 always_inline f64
405 vlib_internal_node_vector_rate (vlib_main_t * vm)
406 {
407   u64 vectors;
408   u64 calls;
409
410   calls = vm->internal_node_calls - vm->internal_node_calls_last_clear;
411
412   if (PREDICT_FALSE (calls == 0))
413     return 0.0;
414
415   vectors = vm->internal_node_vectors - vm->internal_node_vectors_last_clear;
416
417   return (f64) vectors / (f64) calls;
418 }
419
420 always_inline void
421 vlib_clear_internal_node_vector_rate (vlib_main_t * vm)
422 {
423   vm->internal_node_calls_last_clear = vm->internal_node_calls;
424   vm->internal_node_vectors_last_clear = vm->internal_node_vectors;
425 }
426
427 always_inline void
428 vlib_increment_main_loop_counter (vlib_main_t * vm)
429 {
430   vm->main_loop_count++;
431   vm->internal_node_last_vectors_per_main_loop = 0;
432
433   if (PREDICT_FALSE (vm->main_loop_exit_now))
434     clib_longjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_CLI);
435 }
436
437 always_inline u32
438 vlib_last_vectors_per_main_loop (vlib_main_t * vm)
439 {
440   return vm->internal_node_last_vectors_per_main_loop;
441 }
442
443 always_inline void
444 vlib_node_runtime_perf_counter (vlib_main_t * vm, vlib_node_runtime_t * node,
445                                 vlib_frame_t * frame, uword n, u64 t,
446                                 vlib_node_runtime_perf_call_type_t call_type)
447 {
448   vlib_node_runtime_perf_callback_data_t *v =
449     clib_callback_data_check_and_get (&vm->vlib_node_runtime_perf_callbacks);
450   if (vec_len (v))
451     {
452       vlib_node_runtime_perf_callback_args_t args = {
453         .vm = vm,
454         .node = node,
455         .frame = frame,
456         .packets = n,
457         .cpu_time_now = t,
458         .call_type = call_type,
459       };
460       clib_callback_data_call_vec (v, &args);
461     }
462 }
463
464 always_inline void vlib_set_queue_signal_callback
465   (vlib_main_t * vm, void (*fp) (vlib_main_t *))
466 {
467   vm->queue_signal_callback = fp;
468 }
469
470 /* Main routine. */
471 int vlib_main (vlib_main_t * vm, unformat_input_t * input);
472
473 /* Thread stacks, for os_get_thread_index */
474 extern u8 **vlib_thread_stacks;
475
476 /* Number of thread stacks that the application needs */
477 u32 vlib_app_num_thread_stacks_needed (void) __attribute__ ((weak));
478
479 extern void vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n);
480
481 #define VLIB_PCAP_MAJOR_VERSION 1
482 #define VLIB_PCAP_MINOR_VERSION 0
483
484 typedef struct
485 {
486   u8 *filename;
487   int enable;
488   int status;
489   int post_mortem;
490   u32 packets_to_capture;
491   u32 buffer_trace_node_index;
492   u32 buffer_traces_to_capture;
493 } vlib_pcap_dispatch_trace_args_t;
494
495 int vlib_pcap_dispatch_trace_configure (vlib_pcap_dispatch_trace_args_t *);
496 vlib_main_t *vlib_get_main_not_inline (void);
497 elog_main_t *vlib_get_elog_main_not_inline ();
498
499 #endif /* included_vlib_main_h */
500
501 /*
502  * fd.io coding-style-patch-verification: ON
503  *
504  * Local Variables:
505  * eval: (c-set-style "gnu")
506  * End:
507  */