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_stats_push_heap (void)
20 stats_main_t *sm = &stats_main;
21 ssvm_private_t *ssvmp = &sm->stat_segment;
22 ssvm_shared_header_t *shared_header;
24 ASSERT (ssvmp && ssvmp->sh);
26 shared_header = ssvmp->sh;
28 return ssvm_push_heap (shared_header);
32 vlib_stats_pop_heap (void *cm_arg, void *oldheap)
34 vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
35 stats_main_t *sm = &stats_main;
36 ssvm_private_t *ssvmp = &sm->stat_segment;
37 ssvm_shared_header_t *shared_header;
38 char *stat_segment_name;
39 stat_segment_directory_entry_t *ep;
42 ASSERT (ssvmp && ssvmp->sh);
44 shared_header = ssvmp->sh;
46 /* Not all counters have names / hash-table entries */
47 if (cm->name || cm->stat_segment_name)
52 stat_segment_name = cm->stat_segment_name ?
53 cm->stat_segment_name : cm->name;
55 clib_spinlock_lock (sm->stat_segment_lockp);
57 /* Update hash table. The name must be copied into the segment */
58 hp = hash_get_pair (sm->counter_vector_by_name, stat_segment_name);
61 name_copy = (u8 *) hp->key;
62 ep = (stat_segment_directory_entry_t *) (hp->value[0]);
63 hash_unset_mem (sm->counter_vector_by_name, stat_segment_name);
67 name_copy = format (0, "%s%c", stat_segment_name, 0);
68 ep = clib_mem_alloc (sizeof (*ep));
69 ep->type = STAT_DIR_TYPE_COUNTER_VECTOR;
70 ep->value = cm->counters;
71 hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
73 /* Reset the client hash table pointer, since it WILL change! */
74 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR]
75 = sm->counter_vector_by_name;
77 /* Warn clients to refresh any pointers they might be holding */
78 shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
79 ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
80 clib_spinlock_unlock (sm->stat_segment_lockp);
82 ssvm_pop_heap (oldheap);
86 vlib_stats_register_error_index (u8 * name, u64 index)
88 stats_main_t *sm = &stats_main;
89 ssvm_private_t *ssvmp = &sm->stat_segment;
90 ssvm_shared_header_t *shared_header;
91 stat_segment_directory_entry_t *ep;
96 ASSERT (ssvmp && ssvmp->sh);
98 shared_header = ssvmp->sh;
100 clib_spinlock_lock (sm->stat_segment_lockp);
102 /* Update hash table. The name must be copied into the segment */
103 hp = hash_get_pair (sm->counter_vector_by_name, name);
106 name_copy = (u8 *) hp->key;
107 ep = (stat_segment_directory_entry_t *) (hp->value[0]);
108 hash_unset_mem (sm->counter_vector_by_name, name);
109 vec_free (name_copy);
113 ep = clib_mem_alloc (sizeof (*ep));
114 ep->type = STAT_DIR_TYPE_ERROR_INDEX;
115 ep->value = (void *) index;
117 hash_set_mem (sm->counter_vector_by_name, name, ep);
119 /* Reset the client hash table pointer, since it WILL change! */
120 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
122 /* Warn clients to refresh any pointers they might be holding */
123 shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
124 ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
125 clib_spinlock_unlock (sm->stat_segment_lockp);
129 vlib_stats_pop_heap2 (u64 * counter_vector, u32 thread_index, void *oldheap)
131 stats_main_t *sm = &stats_main;
132 ssvm_private_t *ssvmp = &sm->stat_segment;
133 ssvm_shared_header_t *shared_header;
134 stat_segment_directory_entry_t *ep;
136 u8 *error_vector_name;
140 ASSERT (ssvmp && ssvmp->sh);
142 shared_header = ssvmp->sh;
144 clib_spinlock_lock (sm->stat_segment_lockp);
146 error_vector_name = format (0, "/err/%d/counter_vector%c", thread_index, 0);
148 /* Update hash table. The name must be copied into the segment */
149 hp = hash_get_pair (sm->counter_vector_by_name, error_vector_name);
152 name_copy = (u8 *) hp->key;
153 ep = (stat_segment_directory_entry_t *) (hp->value[0]);
154 hash_unset_mem (sm->counter_vector_by_name, error_vector_name);
155 vec_free (name_copy);
159 ep = clib_mem_alloc (sizeof (*ep));
160 ep->type = STAT_DIR_TYPE_VECTOR_POINTER;
161 ep->value = counter_vector;
163 hash_set_mem (sm->counter_vector_by_name, error_vector_name, ep);
165 /* Reset the client hash table pointer, since it WILL change! */
166 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
168 /* Warn clients to refresh any pointers they might be holding */
169 shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *)
170 ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1);
171 clib_spinlock_unlock (sm->stat_segment_lockp);
172 ssvm_pop_heap (oldheap);
175 static clib_error_t *
176 map_stat_segment_init (vlib_main_t * vm)
178 stats_main_t *sm = &stats_main;
179 ssvm_private_t *ssvmp = &sm->stat_segment;
180 ssvm_shared_header_t *shared_header;
181 stat_segment_directory_entry_t *ep;
188 ssvmp->ssvm_size = 32 << 20; /*$$$$$ CONFIG PARAM */
189 ssvmp->i_am_master = 1;
190 ssvmp->my_pid = getpid ();
191 ssvmp->name = format (0, "/stats%c", 0);
192 ssvmp->requested_va = 0;
194 rv = ssvm_master_init (ssvmp, SSVM_SEGMENT_MEMFD);
197 return clib_error_return (0, "stat segment ssvm init failure");
198 shared_header = ssvmp->sh;
200 oldheap = ssvm_push_heap (shared_header);
202 /* Set up the name to counter-vector hash table */
203 sm->counter_vector_by_name = hash_create_string (0, sizeof (uword));
205 sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
207 /* Save the hash table address in the shared segment, for clients */
208 clib_spinlock_init (sm->stat_segment_lockp);
209 shared_header->opaque[STAT_SEGMENT_OPAQUE_LOCK] = sm->stat_segment_lockp;
210 shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) 1;
212 /* Set up a few scalar stats */
214 scalar_data = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
215 CLIB_CACHE_LINE_BYTES);
216 sm->vector_rate_ptr = (scalar_data + 0);
217 sm->input_rate_ptr = (scalar_data + 1);
219 name = format (0, "vector_rate%c", 0);
220 ep = clib_mem_alloc (sizeof (*ep));
221 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
222 ep->value = sm->vector_rate_ptr;
224 hash_set_mem (sm->counter_vector_by_name, name, ep);
226 name = format (0, "input_rate%c", 0);
227 ep = clib_mem_alloc (sizeof (*ep));
228 ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
229 ep->value = sm->input_rate_ptr;
231 hash_set_mem (sm->counter_vector_by_name, name, ep);
233 /* Publish the hash table */
234 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name;
236 ssvm_pop_heap (oldheap);
241 VLIB_INIT_FUNCTION (map_stat_segment_init);
246 stat_segment_directory_entry_t *dir_entry;
247 } show_stat_segment_t;
250 name_sort_cmp (void *a1, void *a2)
252 show_stat_segment_t *n1 = a1;
253 show_stat_segment_t *n2 = a2;
255 return strcmp ((char *) n1->name, (char *) n2->name);
259 format_stat_dir_entry (u8 * s, va_list * args)
261 stat_segment_directory_entry_t *ep =
262 va_arg (*args, stat_segment_directory_entry_t *);
266 format_string = "%-10s %20llx";
270 case STAT_DIR_TYPE_SCALAR_POINTER:
271 type_name = "ScalarPtr";
274 case STAT_DIR_TYPE_VECTOR_POINTER:
275 type_name = "VectorPtr";
278 case STAT_DIR_TYPE_COUNTER_VECTOR:
279 type_name = "CMainPtr";
282 case STAT_DIR_TYPE_ERROR_INDEX:
283 type_name = "ErrIndex";
284 format_string = "%-10s %20lld";
288 type_name = "illegal!";
292 return format (s, format_string, type_name, ep->value);
297 static clib_error_t *
298 show_stat_segment_command_fn (vlib_main_t * vm,
299 unformat_input_t * input,
300 vlib_cli_command_t * cmd)
302 stats_main_t *sm = &stats_main;
303 ssvm_private_t *ssvmp = &sm->stat_segment;
304 ssvm_shared_header_t *shared_header;
307 show_stat_segment_t *show_data = 0;
308 show_stat_segment_t *this;
314 if (unformat (input, "verbose"))
317 clib_spinlock_lock (sm->stat_segment_lockp);
320 hash_foreach_pair (p, sm->counter_vector_by_name,
322 vec_add2 (show_data, this, 1);
324 this->name = (u8 *) (p->key);
325 this->dir_entry = (stat_segment_directory_entry_t *)(p->value[0]);
329 clib_spinlock_unlock (sm->stat_segment_lockp);
331 vec_sort_with_function (show_data, name_sort_cmp);
333 vlib_cli_output (vm, "%-60s %10s %20s", "Name", "Type", "Value");
335 for (i = 0; i < vec_len (show_data); i++)
337 this = vec_elt_at_index (show_data, i);
339 vlib_cli_output (vm, "%-60s %31U",
340 this->name, format_stat_dir_entry, this->dir_entry);
345 ASSERT (ssvmp && ssvmp->sh);
347 shared_header = ssvmp->sh;
349 vlib_cli_output (vm, "%U", format_mheap,
350 shared_header->heap, 0 /* verbose */ );
357 VLIB_CLI_COMMAND (show_stat_segment_command, static) =
359 .path = "show statistics segment",
360 .short_help = "show statistics segment [verbose]",
361 .function = show_stat_segment_command_fn,
366 stat_segment_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
370 u64 input_packets, last_input_packets;
371 f64 last_runtime, dt, now;
372 vlib_main_t *this_vlib_main;
373 stats_main_t *sm = &stats_main;
376 last_input_packets = 0;
379 last_input_packets = 0;
383 vlib_process_suspend (vm, 5.0);
386 * Compute the average vector rate across all workers
393 vector_rate += vlib_last_vector_length_per_node (vm);
397 *sm->vector_rate_ptr = vector_rate / ((f64) vec_len (vlib_mains));
398 now = vlib_time_now (vm);
399 dt = now - last_runtime;
400 input_packets = vnet_get_aggregate_rx_packets ();
401 *sm->input_rate_ptr = (f64) (input_packets - last_input_packets) / dt;
403 last_input_packets = input_packets;
406 return 0; /* not so much */
410 VLIB_REGISTER_NODE (stat_segment_node,static) =
412 .function = stat_segment_process,
413 .type = VLIB_NODE_TYPE_PROCESS,
414 .name = "stat-segment-process",
420 * fd.io coding-style-patch-verification: ON
423 * eval: (c-set-style "gnu")