FD.io VPP  v18.07-rc0-415-g6c78436
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;
201 
202  ssvmp->ssvm_size = 32 << 20; /*$$$$$ CONFIG PARAM */
203  ssvmp->i_am_master = 1;
204  ssvmp->my_pid = getpid ();
205  ssvmp->name = format (0, "/stats%c", 0);
206  ssvmp->requested_va = 0;
207 
208  rv = ssvm_master_init (ssvmp, SSVM_SEGMENT_MEMFD);
209 
210  if (rv)
211  return clib_error_return (0, "stat segment ssvm init failure");
212  shared_header = ssvmp->sh;
213 
214  oldheap = ssvm_push_heap (shared_header);
215 
216  /* Set up the name to counter-vector hash table */
217  sm->counter_vector_by_name = hash_create_string (0, sizeof (uword));
218 
220 
221  /* Save the hash table address in the shared segment, for clients */
223  shared_header->opaque[STAT_SEGMENT_OPAQUE_LOCK] = sm->stat_segment_lockp;
224  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) 1;
225 
226  /* Set up a few scalar stats */
227 
230  sm->vector_rate_ptr = (scalar_data + 0);
231  sm->input_rate_ptr = (scalar_data + 1);
232  sm->last_runtime_ptr = (scalar_data + 2);
233  sm->last_runtime_stats_clear_ptr = (scalar_data + 3);
234 
235  name = format (0, "/sys/vector_rate%c", 0);
236  ep = clib_mem_alloc (sizeof (*ep));
238  ep->value = sm->vector_rate_ptr;
239 
240  hash_set_mem (sm->counter_vector_by_name, name, ep);
241 
242  name = format (0, "/sys/input_rate%c", 0);
243  ep = clib_mem_alloc (sizeof (*ep));
245  ep->value = sm->input_rate_ptr;
246 
247  hash_set_mem (sm->counter_vector_by_name, name, ep);
248 
249  name = format (0, "/sys/last_update%c", 0);
250  ep = clib_mem_alloc (sizeof (*ep));
252  ep->value = sm->last_runtime_ptr;
253 
254  hash_set_mem (sm->counter_vector_by_name, name, ep);
255 
256  name = format (0, "/sys/last_stats_clear%c", 0);
257  ep = clib_mem_alloc (sizeof (*ep));
260 
261  hash_set_mem (sm->counter_vector_by_name, name, ep);
262 
263 
264  /* Publish the hash table */
266 
267  ssvm_pop_heap (oldheap);
268 
269  return 0;
270 }
271 
272 typedef struct
273 {
277 
278 static int
279 name_sort_cmp (void *a1, void *a2)
280 {
281  show_stat_segment_t *n1 = a1;
282  show_stat_segment_t *n2 = a2;
283 
284  return strcmp ((char *) n1->name, (char *) n2->name);
285 }
286 
287 static u8 *
288 format_stat_dir_entry (u8 * s, va_list * args)
289 {
291  va_arg (*args, stat_segment_directory_entry_t *);
292  char *type_name;
293  char *format_string;
294 
295  format_string = "%-10s %20llx";
296 
297  switch (ep->type)
298  {
300  type_name = "ScalarPtr";
301  break;
302 
304  type_name = "VectorPtr";
305  break;
306 
308  type_name = "CMainPtr";
309  break;
310 
312  type_name = "SerNodesPtr";
313  break;
314 
316  type_name = "ErrIndex";
317  format_string = "%-10s %20lld";
318  break;
319 
320  default:
321  type_name = "illegal!";
322  break;
323  }
324 
325  return format (s, format_string, type_name, ep->value);
326 }
327 
328 static clib_error_t *
330  unformat_input_t * input,
331  vlib_cli_command_t * cmd)
332 {
333  stats_main_t *sm = &stats_main;
334  ssvm_private_t *ssvmp = &sm->stat_segment;
335  ssvm_shared_header_t *shared_header;
336  counter_t *counter;
337  hash_pair_t *p;
338  show_stat_segment_t *show_data = 0;
339  show_stat_segment_t *this;
340  int i;
341 
342  int verbose = 0;
343  u8 *s;
344 
345  if (unformat (input, "verbose"))
346  verbose = 1;
347 
349 
350  /* *INDENT-OFF* */
352  ({
353  vec_add2 (show_data, this, 1);
354 
355  this->name = (u8 *) (p->key);
356  this->dir_entry = (stat_segment_directory_entry_t *)(p->value[0]);
357  }));
358  /* *INDENT-ON* */
359 
361 
363 
364  vlib_cli_output (vm, "%-60s %10s %20s", "Name", "Type", "Value");
365 
366  for (i = 0; i < vec_len (show_data); i++)
367  {
368  this = vec_elt_at_index (show_data, i);
369 
370  vlib_cli_output (vm, "%-60s %31U",
371  this->name, format_stat_dir_entry, this->dir_entry);
372  }
373 
374  if (verbose)
375  {
376  ASSERT (ssvmp && ssvmp->sh);
377 
378  shared_header = ssvmp->sh;
379 
380  vlib_cli_output (vm, "%U", format_mheap,
381  shared_header->heap, 0 /* verbose */ );
382  }
383 
384  return 0;
385 }
386 
387 /* *INDENT-OFF* */
388 VLIB_CLI_COMMAND (show_stat_segment_command, static) =
389 {
390  .path = "show statistics segment",
391  .short_help = "show statistics segment [verbose]",
392  .function = show_stat_segment_command_fn,
393 };
394 /* *INDENT-ON* */
395 
396 static inline void
398 {
399  int i;
400  vlib_main_t *vm = vlib_mains[0];
401  ssvm_private_t *ssvmp = &sm->stat_segment;
402  ssvm_shared_header_t *shared_header;
403  void *oldheap;
405  hash_pair_t *hp;
406  u8 *name_copy;
407 
408  ASSERT (ssvmp && ssvmp->sh);
409 
411 
412  shared_header = ssvmp->sh;
413 
414  oldheap = ssvm_push_heap (shared_header);
415 
417 
418  vlib_node_get_nodes (0 /* vm, for barrier sync */ ,
419  (u32) ~ 0 /* all threads */ ,
420  1 /* include stats */ ,
421  0 /* barrier sync */ ,
422  &sm->node_dups, &sm->stat_vms);
423 
425  sm->serialized_nodes,
426  0 /* include nexts */ ,
427  1 /* include stats */ );
428 
429  hp = hash_get_pair (sm->counter_vector_by_name, "serialized_nodes");
430  if (hp)
431  {
432  name_copy = (u8 *) hp->key;
433  ep = (stat_segment_directory_entry_t *) (hp->value[0]);
434 
435  if (ep->value != sm->serialized_nodes)
436  {
437  ep->value = sm->serialized_nodes;
438  /* Warn clients to refresh any pointers they might be holding */
439  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
440  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
441  }
442  }
443  else
444  {
445  name_copy = format (0, "%s%c", "serialized_nodes", 0);
446  ep = clib_mem_alloc (sizeof (*ep));
448  ep->value = sm->serialized_nodes;
449  hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
450 
451  /* Reset the client hash table pointer */
452  shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
454 
455  /* Warn clients to refresh any pointers they might be holding */
456  shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
457  ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
458  }
459 
461  ssvm_pop_heap (oldheap);
462 }
463 
464 /*
465  * Called by stats_thread_fn, in stats.c, which runs in a
466  * separate pthread, which won't halt the parade
467  * in single-forwarding-core cases.
468  */
469 
470 void
472 {
473  vlib_main_t *vm = vlib_mains[0];
474  f64 vector_rate;
475  u64 input_packets, last_input_packets;
476  f64 dt, now;
477  vlib_main_t *this_vlib_main;
478  int i, start;
479 
480  /*
481  * Compute the average vector rate across all workers
482  */
483  vector_rate = 0.0;
484 
485  start = vec_len (vlib_mains) > 1 ? 1 : 0;
486 
487  for (i = start; i < vec_len (vlib_mains); i++)
488  {
489  this_vlib_main = vlib_mains[i];
490  vector_rate += vlib_last_vector_length_per_node (this_vlib_main);
491  }
492  vector_rate /= (f64) (i - start);
493 
494  *sm->vector_rate_ptr = vector_rate / ((f64) (vec_len (vlib_mains) - start));
495 
496  /*
497  * Compute the aggregate input rate
498  */
499  now = vlib_time_now (vm);
500  dt = now - sm->last_runtime_ptr[0];
501  input_packets = vnet_get_aggregate_rx_packets ();
502  *sm->input_rate_ptr = (f64) (input_packets - sm->last_input_packets) / dt;
503  sm->last_runtime_ptr[0] = now;
504  sm->last_input_packets = input_packets;
507 
509 }
510 
511 
512 /*
513  * fd.io coding-style-patch-verification: ON
514  *
515  * Local Variables:
516  * eval: (c-set-style "gnu")
517  * End:
518  */
u64 ssvm_size
Definition: ssvm.h:84
Definition: stats.h:212
#define STAT_SEGMENT_OPAQUE_DIR
Definition: stats.h:199
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:397
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:175
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:1162
#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:174
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:275
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:375
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
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:288
void vlib_stat_segment_unlock(void)
Definition: stat_segment.c:25
struct _unformat_input_t unformat_input_t
vlib_node_t *** node_dups
Definition: stats.h:181
#define STAT_SEGMENT_OPAQUE_LOCK
Definition: stats.h:198
#define STAT_SEGMENT_OPAQUE_EPOCH
Definition: stats.h:200
void do_stat_segment_updates(stats_main_t *sm)
Definition: stat_segment.c:471
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:173
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
void * value
Definition: stats.h:215
char * stat_segment_name
Name in stat segment directory.
Definition: counter.h:66
u64 last_input_packets
Definition: stats.h:176
#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:180
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:961
static int name_sort_cmp(void *a1, void *a2)
Definition: stat_segment.c:279
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:329
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:120
counter_t ** counters
Per-thread u64 non-atomic counters.
Definition: counter.h:60
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:179
stat_directory_type_t type
Definition: stats.h:214
f64 * input_rate_ptr
Definition: stats.h:172