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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <vpp/stats/stats.h>
18 vlib_stat_segment_lock (void)
20 stats_main_t *sm = &stats_main;
21 clib_spinlock_lock (sm->stat_segment_lockp);
25 vlib_stat_segment_unlock (void)
27 stats_main_t *sm = &stats_main;
28 clib_spinlock_unlock (sm->stat_segment_lockp);
32 vlib_stats_push_heap (void)
34 stats_main_t *sm = &stats_main;
35 ssvm_private_t *ssvmp = &sm->stat_segment;
36 ssvm_shared_header_t *shared_header;
38 ASSERT (ssvmp && ssvmp->sh);
40 shared_header = ssvmp->sh;
42 return ssvm_push_heap (shared_header);
46 vlib_stats_pop_heap (void *cm_arg, void *oldheap)
48 vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
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;
53 stat_segment_directory_entry_t *ep;
56 ASSERT (ssvmp && ssvmp->sh);
58 shared_header = ssvmp->sh;
60 /* Not all counters have names / hash-table entries */
61 if (cm->name || cm->stat_segment_name)
66 stat_segment_name = cm->stat_segment_name ?
67 cm->stat_segment_name : cm->name;
69 clib_spinlock_lock (sm->stat_segment_lockp);
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);
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);
81 name_copy = format (0, "%s%c", stat_segment_name, 0);
82 ep = clib_mem_alloc (sizeof (*ep));
83 ep->type = STAT_DIR_TYPE_COUNTER_VECTOR;
84 ep->value = cm->counters;
85 hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
87 /* Reset the client hash table pointer, since it WILL change! */
88 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
89 = sm->counter_vector_by_name;
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);
94 clib_spinlock_unlock (sm->stat_segment_lockp);
96 ssvm_pop_heap (oldheap);
100 vlib_stats_register_error_index (u8 * name, u64 index)
102 stats_main_t *sm = &stats_main;
103 ssvm_private_t *ssvmp = &sm->stat_segment;
104 ssvm_shared_header_t *shared_header;
105 stat_segment_directory_entry_t *ep;
110 ASSERT (ssvmp && ssvmp->sh);
112 shared_header = ssvmp->sh;
114 clib_spinlock_lock (sm->stat_segment_lockp);
116 /* Update hash table. The name must be copied into the segment */
117 hp = hash_get_pair (sm->counter_vector_by_name, name);
120 name_copy = (u8 *) hp->key;
121 ep = (stat_segment_directory_entry_t *) (hp->value[0]);
122 hash_unset_mem (sm->counter_vector_by_name, name);
123 vec_free (name_copy);
127 ep = clib_mem_alloc (sizeof (*ep));
128 ep->type = STAT_DIR_TYPE_ERROR_INDEX;
129 ep->value = (void *) index;
131 hash_set_mem (sm->counter_vector_by_name, name, ep);
133 /* Reset the client hash table pointer, since it WILL change! */
134 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
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);
139 clib_spinlock_unlock (sm->stat_segment_lockp);
143 vlib_stats_pop_heap2 (u64 * counter_vector, u32 thread_index, void *oldheap)
145 stats_main_t *sm = &stats_main;
146 ssvm_private_t *ssvmp = &sm->stat_segment;
147 ssvm_shared_header_t *shared_header;
148 stat_segment_directory_entry_t *ep;
150 u8 *error_vector_name;
154 ASSERT (ssvmp && ssvmp->sh);
156 shared_header = ssvmp->sh;
158 clib_spinlock_lock (sm->stat_segment_lockp);
160 error_vector_name = format (0, "/err/%d/counter_vector%c", thread_index, 0);
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);
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);
173 ep = clib_mem_alloc (sizeof (*ep));
174 ep->type = STAT_DIR_TYPE_VECTOR_POINTER;
175 ep->value = counter_vector;
177 hash_set_mem (sm->counter_vector_by_name, error_vector_name, ep);
179 /* Reset the client hash table pointer, since it WILL change! */
180 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
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);
185 clib_spinlock_unlock (sm->stat_segment_lockp);
186 ssvm_pop_heap (oldheap);
190 vlib_map_stat_segment_init (void)
192 stats_main_t *sm = &stats_main;
193 ssvm_private_t *ssvmp = &sm->stat_segment;
194 ssvm_shared_header_t *shared_header;
195 stat_segment_directory_entry_t *ep;
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;
208 rv = ssvm_master_init (ssvmp, SSVM_SEGMENT_MEMFD);
211 return clib_error_return (0, "stat segment ssvm init failure");
212 shared_header = ssvmp->sh;
214 oldheap = ssvm_push_heap (shared_header);
216 /* Set up the name to counter-vector hash table */
217 sm->counter_vector_by_name = hash_create_string (0, sizeof (uword));
219 sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
221 /* Save the hash table address in the shared segment, for clients */
222 clib_spinlock_init (sm->stat_segment_lockp);
223 shared_header->opaque[STAT_SEGMENT_OPAQUE_LOCK] = sm->stat_segment_lockp;
224 shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) 1;
226 /* Set up a few scalar stats */
228 scalar_data = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
229 CLIB_CACHE_LINE_BYTES);
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);
235 name = format (0, "/sys/vector_rate%c", 0);
236 ep = clib_mem_alloc (sizeof (*ep));
237 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
238 ep->value = sm->vector_rate_ptr;
240 hash_set_mem (sm->counter_vector_by_name, name, ep);
242 name = format (0, "/sys/input_rate%c", 0);
243 ep = clib_mem_alloc (sizeof (*ep));
244 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
245 ep->value = sm->input_rate_ptr;
247 hash_set_mem (sm->counter_vector_by_name, name, ep);
249 name = format (0, "/sys/last_update%c", 0);
250 ep = clib_mem_alloc (sizeof (*ep));
251 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
252 ep->value = sm->last_runtime_ptr;
254 hash_set_mem (sm->counter_vector_by_name, name, ep);
256 name = format (0, "/sys/last_stats_clear%c", 0);
257 ep = clib_mem_alloc (sizeof (*ep));
258 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
259 ep->value = sm->last_runtime_stats_clear_ptr;
261 hash_set_mem (sm->counter_vector_by_name, name, ep);
264 /* Publish the hash table */
265 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
267 ssvm_pop_heap (oldheap);
275 stat_segment_directory_entry_t *dir_entry;
276 } show_stat_segment_t;
279 name_sort_cmp (void *a1, void *a2)
281 show_stat_segment_t *n1 = a1;
282 show_stat_segment_t *n2 = a2;
284 return strcmp ((char *) n1->name, (char *) n2->name);
288 format_stat_dir_entry (u8 * s, va_list * args)
290 stat_segment_directory_entry_t *ep =
291 va_arg (*args, stat_segment_directory_entry_t *);
295 format_string = "%-10s %20llx";
299 case STAT_DIR_TYPE_SCALAR_POINTER:
300 type_name = "ScalarPtr";
303 case STAT_DIR_TYPE_VECTOR_POINTER:
304 type_name = "VectorPtr";
307 case STAT_DIR_TYPE_COUNTER_VECTOR:
308 type_name = "CMainPtr";
311 case STAT_DIR_TYPE_SERIALIZED_NODES:
312 type_name = "SerNodesPtr";
315 case STAT_DIR_TYPE_ERROR_INDEX:
316 type_name = "ErrIndex";
317 format_string = "%-10s %20lld";
321 type_name = "illegal!";
325 return format (s, format_string, type_name, ep->value);
328 static clib_error_t *
329 show_stat_segment_command_fn (vlib_main_t * vm,
330 unformat_input_t * input,
331 vlib_cli_command_t * cmd)
333 stats_main_t *sm = &stats_main;
334 ssvm_private_t *ssvmp = &sm->stat_segment;
335 ssvm_shared_header_t *shared_header;
338 show_stat_segment_t *show_data = 0;
339 show_stat_segment_t *this;
345 if (unformat (input, "verbose"))
348 clib_spinlock_lock (sm->stat_segment_lockp);
351 hash_foreach_pair (p, sm->counter_vector_by_name,
353 vec_add2 (show_data, this, 1);
355 this->name = (u8 *) (p->key);
356 this->dir_entry = (stat_segment_directory_entry_t *)(p->value[0]);
360 clib_spinlock_unlock (sm->stat_segment_lockp);
362 vec_sort_with_function (show_data, name_sort_cmp);
364 vlib_cli_output (vm, "%-60s %10s %20s", "Name", "Type", "Value");
366 for (i = 0; i < vec_len (show_data); i++)
368 this = vec_elt_at_index (show_data, i);
370 vlib_cli_output (vm, "%-60s %31U",
371 this->name, format_stat_dir_entry, this->dir_entry);
376 ASSERT (ssvmp && ssvmp->sh);
378 shared_header = ssvmp->sh;
380 vlib_cli_output (vm, "%U", format_mheap,
381 shared_header->heap, 0 /* verbose */ );
388 VLIB_CLI_COMMAND (show_stat_segment_command, static) =
390 .path = "show statistics segment",
391 .short_help = "show statistics segment [verbose]",
392 .function = show_stat_segment_command_fn,
397 update_serialized_nodes (stats_main_t * sm)
400 vlib_main_t *vm = vlib_mains[0];
401 ssvm_private_t *ssvmp = &sm->stat_segment;
402 ssvm_shared_header_t *shared_header;
404 stat_segment_directory_entry_t *ep;
408 ASSERT (ssvmp && ssvmp->sh);
410 vec_reset_length (sm->serialized_nodes);
412 shared_header = ssvmp->sh;
414 oldheap = ssvm_push_heap (shared_header);
416 clib_spinlock_lock (sm->stat_segment_lockp);
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);
424 sm->serialized_nodes = vlib_node_serialize (vm, sm->node_dups,
425 sm->serialized_nodes,
426 0 /* include nexts */ ,
427 1 /* include stats */ );
429 hp = hash_get_pair (sm->counter_vector_by_name, "serialized_nodes");
432 name_copy = (u8 *) hp->key;
433 ep = (stat_segment_directory_entry_t *) (hp->value[0]);
435 if (ep->value != sm->serialized_nodes)
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);
445 name_copy = format (0, "%s%c", "serialized_nodes", 0);
446 ep = clib_mem_alloc (sizeof (*ep));
447 ep->type = STAT_DIR_TYPE_SERIALIZED_NODES;
448 ep->value = sm->serialized_nodes;
449 hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
451 /* Reset the client hash table pointer */
452 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
453 = sm->counter_vector_by_name;
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);
460 clib_spinlock_unlock (sm->stat_segment_lockp);
461 ssvm_pop_heap (oldheap);
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.
471 do_stat_segment_updates (stats_main_t * sm)
473 vlib_main_t *vm = vlib_mains[0];
475 u64 input_packets, last_input_packets;
477 vlib_main_t *this_vlib_main;
481 * Compute the average vector rate across all workers
485 start = vec_len (vlib_mains) > 1 ? 1 : 0;
487 for (i = start; i < vec_len (vlib_mains); i++)
489 this_vlib_main = vlib_mains[i];
490 vector_rate += vlib_last_vector_length_per_node (this_vlib_main);
492 vector_rate /= (f64) (i - start);
494 *sm->vector_rate_ptr = vector_rate / ((f64) (vec_len (vlib_mains) - start));
497 * Compute the aggregate input rate
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;
505 sm->last_runtime_stats_clear_ptr[0] =
506 vm->node_main.time_last_runtime_stats_clear;
508 update_serialized_nodes (sm);
513 * fd.io coding-style-patch-verification: ON
516 * eval: (c-set-style "gnu")