FD.io VPP  v18.07-34-g55fbdb9
Vector Packet Processing
stat_segment.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 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 #include <vpp/stats/stats.h>
16 
17 void
19 {
20  stats_main_t *sm = &stats_main;
22 }
23 
24 void
26 {
27  stats_main_t *sm = &stats_main;
29 }
30 
31 void *
33 {
34  stats_main_t *sm = &stats_main;
35  ssvm_private_t *ssvmp = &sm->stat_segment;
36  ssvm_shared_header_t *shared_header;
37 
38  ASSERT (ssvmp && ssvmp->sh);
39 
40  shared_header = ssvmp->sh;
41 
42  return ssvm_push_heap (shared_header);
43 }
44 
45 void
46 vlib_stats_pop_heap (void *cm_arg, void *oldheap)
47 {
49  stats_main_t *sm = &stats_main;
50  ssvm_private_t *ssvmp = &sm->stat_segment;
51  ssvm_shared_header_t *shared_header;
52  char *stat_segment_name;
54  uword *p;
55 
56  ASSERT (ssvmp && ssvmp->sh);
57 
58  shared_header = ssvmp->sh;
59 
60  /* Not all counters have names / hash-table entries */
61  if (cm->name || cm->stat_segment_name)
62  {
63  hash_pair_t *hp;
64  u8 *name_copy;
65 
66  stat_segment_name = cm->stat_segment_name ?
67  cm->stat_segment_name : cm->name;
68 
70 
71  /* Update hash table. The name must be copied into the segment */
72  hp = hash_get_pair (sm->counter_vector_by_name, stat_segment_name);
73  if (hp)
74  {
75  name_copy = (u8 *) hp->key;
76  ep = (stat_segment_directory_entry_t *) (hp->value[0]);
77  hash_unset_mem (sm->counter_vector_by_name, stat_segment_name);
78  vec_free (name_copy);
79  clib_mem_free (ep);
80  }
81  name_copy = format (0, "%s%c", stat_segment_name, 0);
82  ep = clib_mem_alloc (sizeof (*ep));
84  ep->value = cm->counters;
85  hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
86 
87  /* Reset the client hash table pointer, since it WILL change! */
88  shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
90 
91  /* Warn clients to refresh any pointers they might be holding */
92  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
93  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
95  }
96  ssvm_pop_heap (oldheap);
97 }
98 
99 void
101 {
102  stats_main_t *sm = &stats_main;
103  ssvm_private_t *ssvmp = &sm->stat_segment;
104  ssvm_shared_header_t *shared_header;
106  hash_pair_t *hp;
107  u8 *name_copy;
108  uword *p;
109 
110  ASSERT (ssvmp && ssvmp->sh);
111 
112  shared_header = ssvmp->sh;
113 
115 
116  /* Update hash table. The name must be copied into the segment */
117  hp = hash_get_pair (sm->counter_vector_by_name, name);
118  if (hp)
119  {
120  name_copy = (u8 *) hp->key;
121  ep = (stat_segment_directory_entry_t *) (hp->value[0]);
123  vec_free (name_copy);
124  clib_mem_free (ep);
125  }
126 
127  ep = clib_mem_alloc (sizeof (*ep));
129  ep->value = (void *) index;
130 
131  hash_set_mem (sm->counter_vector_by_name, name, ep);
132 
133  /* Reset the client hash table pointer, since it WILL change! */
135 
136  /* Warn clients to refresh any pointers they might be holding */
137  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
138  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
140 }
141 
142 void
143 vlib_stats_pop_heap2 (u64 * counter_vector, u32 thread_index, void *oldheap)
144 {
145  stats_main_t *sm = &stats_main;
146  ssvm_private_t *ssvmp = &sm->stat_segment;
147  ssvm_shared_header_t *shared_header;
149  hash_pair_t *hp;
150  u8 *error_vector_name;
151  u8 *name_copy;
152  uword *p;
153 
154  ASSERT (ssvmp && ssvmp->sh);
155 
156  shared_header = ssvmp->sh;
157 
159 
160  error_vector_name = format (0, "/err/%d/counter_vector%c", thread_index, 0);
161 
162  /* Update hash table. The name must be copied into the segment */
163  hp = hash_get_pair (sm->counter_vector_by_name, error_vector_name);
164  if (hp)
165  {
166  name_copy = (u8 *) hp->key;
167  ep = (stat_segment_directory_entry_t *) (hp->value[0]);
168  hash_unset_mem (sm->counter_vector_by_name, error_vector_name);
169  vec_free (name_copy);
170  clib_mem_free (ep);
171  }
172 
173  ep = clib_mem_alloc (sizeof (*ep));
175  ep->value = counter_vector;
176 
177  hash_set_mem (sm->counter_vector_by_name, error_vector_name, ep);
178 
179  /* Reset the client hash table pointer, since it WILL change! */
181 
182  /* Warn clients to refresh any pointers they might be holding */
183  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
184  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
186  ssvm_pop_heap (oldheap);
187 }
188 
189 clib_error_t *
191 {
192  stats_main_t *sm = &stats_main;
193  ssvm_private_t *ssvmp = &sm->stat_segment;
194  ssvm_shared_header_t *shared_header;
196  f64 *scalar_data;
197  u8 *name;
198  void *oldheap;
199  u32 *lock;
200  int rv;
202 
203  memory_size = sm->memory_size;
204  if (memory_size == 0)
205  memory_size = STAT_SEGMENT_DEFAULT_SIZE;
206 
207  ssvmp->ssvm_size = memory_size;
208  ssvmp->i_am_master = 1;
209  ssvmp->my_pid = getpid ();
210  ssvmp->name = format (0, "/stats%c", 0);
211  ssvmp->requested_va = 0;
212 
213  rv = ssvm_master_init (ssvmp, SSVM_SEGMENT_MEMFD);
214 
215  if (rv)
216  return clib_error_return (0, "stat segment ssvm init failure");
217  shared_header = ssvmp->sh;
218 
219  oldheap = ssvm_push_heap (shared_header);
220 
221  /* Set up the name to counter-vector hash table */
222  sm->counter_vector_by_name = hash_create_string (0, sizeof (uword));
223 
225 
226  /* Save the hash table address in the shared segment, for clients */
228  shared_header->opaque[STAT_SEGMENT_OPAQUE_LOCK] = sm->stat_segment_lockp;
229  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) 1;
230 
231  /* Set up a few scalar stats */
232 
235  sm->vector_rate_ptr = (scalar_data + 0);
236  sm->input_rate_ptr = (scalar_data + 1);
237  sm->last_runtime_ptr = (scalar_data + 2);
238  sm->last_runtime_stats_clear_ptr = (scalar_data + 3);
239 
240  name = format (0, "/sys/vector_rate%c", 0);
241  ep = clib_mem_alloc (sizeof (*ep));
243  ep->value = sm->vector_rate_ptr;
244 
245  hash_set_mem (sm->counter_vector_by_name, name, ep);
246 
247  name = format (0, "/sys/input_rate%c", 0);
248  ep = clib_mem_alloc (sizeof (*ep));
250  ep->value = sm->input_rate_ptr;
251 
252  hash_set_mem (sm->counter_vector_by_name, name, ep);
253 
254  name = format (0, "/sys/last_update%c", 0);
255  ep = clib_mem_alloc (sizeof (*ep));
257  ep->value = sm->last_runtime_ptr;
258 
259  hash_set_mem (sm->counter_vector_by_name, name, ep);
260 
261  name = format (0, "/sys/last_stats_clear%c", 0);
262  ep = clib_mem_alloc (sizeof (*ep));
265 
266  hash_set_mem (sm->counter_vector_by_name, name, ep);
267 
268 
269  /* Publish the hash table */
271 
272  ssvm_pop_heap (oldheap);
273 
274  return 0;
275 }
276 
277 typedef struct
278 {
282 
283 static int
284 name_sort_cmp (void *a1, void *a2)
285 {
286  show_stat_segment_t *n1 = a1;
287  show_stat_segment_t *n2 = a2;
288 
289  return strcmp ((char *) n1->name, (char *) n2->name);
290 }
291 
292 static u8 *
293 format_stat_dir_entry (u8 * s, va_list * args)
294 {
296  va_arg (*args, stat_segment_directory_entry_t *);
297  char *type_name;
298  char *format_string;
299 
300  format_string = "%-10s %20llx";
301 
302  switch (ep->type)
303  {
305  type_name = "ScalarPtr";
306  break;
307 
309  type_name = "VectorPtr";
310  break;
311 
313  type_name = "CMainPtr";
314  break;
315 
317  type_name = "SerNodesPtr";
318  break;
319 
321  type_name = "ErrIndex";
322  format_string = "%-10s %20lld";
323  break;
324 
325  default:
326  type_name = "illegal!";
327  break;
328  }
329 
330  return format (s, format_string, type_name, ep->value);
331 }
332 
333 static clib_error_t *
335  unformat_input_t * input,
336  vlib_cli_command_t * cmd)
337 {
338  stats_main_t *sm = &stats_main;
339  ssvm_private_t *ssvmp = &sm->stat_segment;
340  ssvm_shared_header_t *shared_header;
341  counter_t *counter;
342  hash_pair_t *p;
343  show_stat_segment_t *show_data = 0;
344  show_stat_segment_t *this;
345  int i;
346 
347  int verbose = 0;
348  u8 *s;
349 
350  if (unformat (input, "verbose"))
351  verbose = 1;
352 
354 
355  /* *INDENT-OFF* */
357  ({
358  vec_add2 (show_data, this, 1);
359 
360  this->name = (u8 *) (p->key);
361  this->dir_entry = (stat_segment_directory_entry_t *)(p->value[0]);
362  }));
363  /* *INDENT-ON* */
364 
366 
368 
369  vlib_cli_output (vm, "%-60s %10s %20s", "Name", "Type", "Value");
370 
371  for (i = 0; i < vec_len (show_data); i++)
372  {
373  this = vec_elt_at_index (show_data, i);
374 
375  vlib_cli_output (vm, "%-60s %31U",
376  this->name, format_stat_dir_entry, this->dir_entry);
377  }
378 
379  if (verbose)
380  {
381  ASSERT (ssvmp && ssvmp->sh);
382 
383  shared_header = ssvmp->sh;
384 
385  vlib_cli_output (vm, "%U", format_mheap,
386  shared_header->heap, 0 /* verbose */ );
387  }
388 
389  return 0;
390 }
391 
392 /* *INDENT-OFF* */
393 VLIB_CLI_COMMAND (show_stat_segment_command, static) =
394 {
395  .path = "show statistics segment",
396  .short_help = "show statistics segment [verbose]",
397  .function = show_stat_segment_command_fn,
398 };
399 /* *INDENT-ON* */
400 
401 static inline void
403 {
404  int i;
405  vlib_main_t *vm = vlib_mains[0];
406  ssvm_private_t *ssvmp = &sm->stat_segment;
407  ssvm_shared_header_t *shared_header;
408  void *oldheap;
410  hash_pair_t *hp;
411  u8 *name_copy;
412 
413  ASSERT (ssvmp && ssvmp->sh);
414 
416 
417  shared_header = ssvmp->sh;
418 
419  oldheap = ssvm_push_heap (shared_header);
420 
422 
423  vlib_node_get_nodes (0 /* vm, for barrier sync */ ,
424  (u32) ~ 0 /* all threads */ ,
425  1 /* include stats */ ,
426  0 /* barrier sync */ ,
427  &sm->node_dups, &sm->stat_vms);
428 
430  sm->serialized_nodes,
431  0 /* include nexts */ ,
432  1 /* include stats */ );
433 
434  hp = hash_get_pair (sm->counter_vector_by_name, "serialized_nodes");
435  if (hp)
436  {
437  name_copy = (u8 *) hp->key;
438  ep = (stat_segment_directory_entry_t *) (hp->value[0]);
439 
440  if (ep->value != sm->serialized_nodes)
441  {
442  ep->value = sm->serialized_nodes;
443  /* Warn clients to refresh any pointers they might be holding */
444  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
445  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
446  }
447  }
448  else
449  {
450  name_copy = format (0, "%s%c", "serialized_nodes", 0);
451  ep = clib_mem_alloc (sizeof (*ep));
453  ep->value = sm->serialized_nodes;
454  hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
455 
456  /* Reset the client hash table pointer */
457  shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
459 
460  /* Warn clients to refresh any pointers they might be holding */
461  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
462  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
463  }
464 
466  ssvm_pop_heap (oldheap);
467 }
468 
469 /*
470  * Called by stats_thread_fn, in stats.c, which runs in a
471  * separate pthread, which won't halt the parade
472  * in single-forwarding-core cases.
473  */
474 
475 void
477 {
478  vlib_main_t *vm = vlib_mains[0];
479  f64 vector_rate;
480  u64 input_packets, last_input_packets;
481  f64 dt, now;
482  vlib_main_t *this_vlib_main;
483  int i, start;
484 
485  /*
486  * Compute the average vector rate across all workers
487  */
488  vector_rate = 0.0;
489 
490  start = vec_len (vlib_mains) > 1 ? 1 : 0;
491 
492  for (i = start; i < vec_len (vlib_mains); i++)
493  {
494  this_vlib_main = vlib_mains[i];
495  vector_rate += vlib_last_vector_length_per_node (this_vlib_main);
496  }
497  vector_rate /= (f64) (i - start);
498 
499  *sm->vector_rate_ptr = vector_rate / ((f64) (vec_len (vlib_mains) - start));
500 
501  /*
502  * Compute the aggregate input rate
503  */
504  now = vlib_time_now (vm);
505  dt = now - sm->last_runtime_ptr[0];
506  input_packets = vnet_get_aggregate_rx_packets ();
507  *sm->input_rate_ptr = (f64) (input_packets - sm->last_input_packets) / dt;
508  sm->last_runtime_ptr[0] = now;
509  sm->last_input_packets = input_packets;
512 
513  if (sm->serialize_nodes)
515 }
516 
517 static clib_error_t *
519 {
520  stats_main_t *sm = &stats_main;
521  uword ms;
522 
524  {
525  if (unformat (input, "size %U", unformat_memory_size, &sm->memory_size))
526  ;
527  else if (unformat (input, "serialize-nodes on"))
528  sm->serialize_nodes = 1;
529  else if (unformat (input, "serialize-nodes off"))
530  sm->serialize_nodes = 0;
531  else
532  return clib_error_return (0, "unknown input `%U'",
533  format_unformat_error, input);
534  }
535 
536  return 0;
537 }
538 
540 
541 /*
542  * fd.io coding-style-patch-verification: ON
543  *
544  * Local Variables:
545  * eval: (c-set-style "gnu")
546  * End:
547  */
static clib_error_t * statseg_config(vlib_main_t *vm, unformat_input_t *input)
Definition: stat_segment.c:518
u64 ssvm_size
Definition: ssvm.h:84
Definition: stats.h:217
#define STAT_SEGMENT_OPAQUE_DIR
Definition: stats.h:204
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:89
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:74
void vlib_stats_pop_heap(void *cm_arg, void *oldheap)
Definition: stat_segment.c:46
uword requested_va
Definition: ssvm.h:87
static void update_serialized_nodes(stats_main_t *sm)
Definition: stat_segment.c:402
static u64 vnet_get_aggregate_rx_packets(void)
Definition: devices.h:98
unsigned long u64
Definition: types.h:89
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:225
f64 * vector_rate_ptr
Definition: stats.h:177
void * opaque[SSVM_N_OPAQUE]
Definition: ssvm.h:73
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:275
ssvm_shared_header_t * sh
Definition: ssvm.h:83
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u8 * vlib_node_serialize(vlib_main_t *vm, vlib_node_t ***node_dups, u8 *vector, int include_nexts, int include_stats)
vlib_main_t ** vlib_mains
Definition: buffer.c:303
unsigned char u8
Definition: types.h:56
u8 * format_mheap(u8 *s, va_list *va)
Definition: mheap.c:1178
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
uword value[0]
Definition: hash.h:165
static f64 vlib_last_vector_length_per_node(vlib_main_t *vm)
Definition: main.h:316
f64 * last_runtime_stats_clear_ptr
Definition: stats.h:176
void vlib_stats_register_error_index(u8 *name, u64 index)
Definition: stat_segment.c:100
stat_segment_directory_entry_t * dir_entry
Definition: stat_segment.c:280
void vlib_node_get_nodes(vlib_main_t *vm, u32 max_threads, int include_stats, int barrier_sync, vlib_node_t ****node_dupsp, vlib_main_t ***stat_vmsp)
Get list of nodes.
Definition: node.c:567
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static void * ssvm_push_heap(ssvm_shared_header_t *sh)
Definition: ssvm.h:144
#define clib_error_return(e, args...)
Definition: error.h:99
#define hash_get_pair(h, key)
Definition: hash.h:252
unsigned int u32
Definition: types.h:88
A collection of simple counters.
Definition: counter.h:58
int ssvm_master_init(ssvm_private_t *ssvm, ssvm_segment_type_t type)
Definition: ssvm.c:379
static void ssvm_pop_heap(void *oldheap)
Definition: ssvm.h:152
void * vlib_stats_push_heap(void)
Definition: stat_segment.c:32
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
stats_main_t stats_main
Definition: stats.c:28
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:57
char * name
The counter collection&#39;s name.
Definition: counter.h:65
#define hash_unset_mem(h, key)
Definition: hash.h:291
uword * counter_vector_by_name
Definition: stats.h:166
uword memory_size
Definition: stats.h:170
f64 time_last_runtime_stats_clear
Definition: node.h:738
static u8 * format_stat_dir_entry(u8 *s, va_list *args)
Definition: stat_segment.c:293
void vlib_stat_segment_unlock(void)
Definition: stat_segment.c:25
struct _unformat_input_t unformat_input_t
u64 memory_size
Definition: vhost_user.h:110
vlib_node_t *** node_dups
Definition: stats.h:183
#define STAT_SEGMENT_OPAQUE_LOCK
Definition: stats.h:203
#define STAT_SEGMENT_OPAQUE_EPOCH
Definition: stats.h:205
void do_stat_segment_updates(stats_main_t *sm)
Definition: stat_segment.c:476
#define VLIB_EARLY_CONFIG_FUNCTION(x, n,...)
Definition: init.h:195
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
void vlib_stat_segment_lock(void)
Definition: stat_segment.c:18
clib_spinlock_t * stat_segment_lockp
Definition: stats.h:167
f64 * last_runtime_ptr
Definition: stats.h:175
u32 my_pid
Definition: ssvm.h:85
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define ASSERT(truth)
static void clib_mem_free(void *p)
Definition: mem.h:179
u64 counter_t
64bit counters
Definition: counter.h:54
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
u8 * name
Definition: ssvm.h:86
#define STAT_SEGMENT_DEFAULT_SIZE
Definition: stats.h:201
void * value
Definition: stats.h:220
char * stat_segment_name
Name in stat segment directory.
Definition: counter.h:66
u64 last_input_packets
Definition: stats.h:178
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define hash_foreach_pair(p, v, body)
Iterate over hash pairs.
Definition: hash.h:373
vlib_node_main_t node_main
Definition: main.h:132
vlib_main_t ** stat_vms
Definition: stats.h:182
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:982
static int name_sort_cmp(void *a1, void *a2)
Definition: stat_segment.c:284
void vlib_stats_pop_heap2(u64 *counter_vector, u32 thread_index, void *oldheap)
Definition: stat_segment.c:143
static clib_error_t * show_stat_segment_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: stat_segment.c:334
unformat_function_t unformat_memory_size
Definition: format.h:295
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:120
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
counter_t ** counters
Per-thread u64 non-atomic counters.
Definition: counter.h:60
u8 serialize_nodes
Definition: stats.h:171
ssvm_private_t stat_segment
Definition: stats.h:165
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
clib_error_t * vlib_map_stat_segment_init(void)
Definition: stat_segment.c:190
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:681
int i_am_master
Definition: ssvm.h:88
uword key
Definition: hash.h:162
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u8 * serialized_nodes
Definition: stats.h:181
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
stat_directory_type_t type
Definition: stats.h:219
f64 * input_rate_ptr
Definition: stats.h:174