diff options
Diffstat (limited to 'src/vlib/stats/collector.c')
-rw-r--r-- | src/vlib/stats/collector.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/vlib/stats/collector.c b/src/vlib/stats/collector.c new file mode 100644 index 00000000000..cc348bbf3ad --- /dev/null +++ b/src/vlib/stats/collector.c @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2022 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vlib/unix/unix.h> +#include <vlib/stats/stats.h> + +static void +stat_validate_counter_vector2 (vlib_stats_entry_t *ep, u32 max1, u32 max2) +{ + counter_t **counters = ep->data; + int i; + vec_validate_aligned (counters, max1, CLIB_CACHE_LINE_BYTES); + for (i = 0; i <= max1; i++) + vec_validate_aligned (counters[i], max2, CLIB_CACHE_LINE_BYTES); + + ep->data = counters; +} + +static void +stat_validate_counter_vector (vlib_stats_entry_t *ep, u32 max) +{ + vlib_thread_main_t *tm = vlib_get_thread_main (); + ASSERT (tm->n_vlib_mains > 0); + stat_validate_counter_vector2 (ep, tm->n_vlib_mains, max); +} + +static inline void +update_node_counters (vlib_stats_segment_t *sm) +{ + vlib_main_t **stat_vms = 0; + vlib_node_t ***node_dups = 0; + int i, j; + static u32 no_max_nodes = 0; + + vlib_node_get_nodes (0 /* vm, for barrier sync */, + (u32) ~0 /* all threads */, 1 /* include stats */, + 0 /* barrier sync */, &node_dups, &stat_vms); + + u32 l = vec_len (node_dups[0]); + u8 *symlink_name = 0; + + /* + * Extend performance nodes if necessary + */ + if (l > no_max_nodes) + { + void *oldheap = clib_mem_set_heap (sm->heap); + vlib_stats_segment_lock (); + + stat_validate_counter_vector ( + &sm->directory_vector[STAT_COUNTER_NODE_CLOCKS], l - 1); + stat_validate_counter_vector ( + &sm->directory_vector[STAT_COUNTER_NODE_VECTORS], l - 1); + stat_validate_counter_vector ( + &sm->directory_vector[STAT_COUNTER_NODE_CALLS], l - 1); + stat_validate_counter_vector ( + &sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS], l - 1); + + vec_validate (sm->nodes, l - 1); + vlib_stats_entry_t *ep; + ep = &sm->directory_vector[STAT_COUNTER_NODE_NAMES]; + ep->data = sm->nodes; + + /* Update names dictionary */ + vlib_node_t **nodes = node_dups[0]; + int i; + for (i = 0; i < vec_len (nodes); i++) + { + vlib_node_t *n = nodes[i]; + u8 *s = format (0, "%v%c", n->name, 0); + if (sm->nodes[n->index]) + vec_free (sm->nodes[n->index]); + sm->nodes[n->index] = s; + + oldheap = clib_mem_set_heap (oldheap); +#define _(E, t, name, p) \ + vlib_stats_add_symlink (STAT_COUNTER_##E, n->index, "/nodes/%U/" #name, \ + format_vlib_stats_symlink, s); + foreach_stat_segment_node_counter_name +#undef _ + oldheap = clib_mem_set_heap (oldheap); + } + + vlib_stats_segment_unlock (); + clib_mem_set_heap (oldheap); + no_max_nodes = l; + } + + for (j = 0; j < vec_len (node_dups); j++) + { + vlib_node_t **nodes = node_dups[j]; + + for (i = 0; i < vec_len (nodes); i++) + { + counter_t **counters; + counter_t *c; + vlib_node_t *n = nodes[i]; + + if (j == 0) + { + if (strncmp ((char *) sm->nodes[n->index], (char *) n->name, + strlen ((char *) sm->nodes[n->index]))) + { + u32 vector_index; + void *oldheap = clib_mem_set_heap (sm->heap); + vlib_stats_segment_lock (); + u8 *s = format (0, "%v%c", n->name, 0); + clib_mem_set_heap (oldheap); +#define _(E, t, name, p) \ + vec_reset_length (symlink_name); \ + symlink_name = format (symlink_name, "/nodes/%U/" #name, \ + format_vlib_stats_symlink, sm->nodes[n->index]); \ + vector_index = vlib_stats_find_entry_index ("%v", symlink_name); \ + ASSERT (vector_index != -1); \ + vlib_stats_rename_symlink (vector_index, "/nodes/%U/" #name, \ + format_vlib_stats_symlink, s); + foreach_stat_segment_node_counter_name +#undef _ + vec_free (symlink_name); + clib_mem_set_heap (sm->heap); + vec_free (sm->nodes[n->index]); + sm->nodes[n->index] = s; + vlib_stats_segment_unlock (); + clib_mem_set_heap (oldheap); + } + } + + counters = sm->directory_vector[STAT_COUNTER_NODE_CLOCKS].data; + c = counters[j]; + c[n->index] = n->stats_total.clocks - n->stats_last_clear.clocks; + + counters = sm->directory_vector[STAT_COUNTER_NODE_VECTORS].data; + c = counters[j]; + c[n->index] = n->stats_total.vectors - n->stats_last_clear.vectors; + + counters = sm->directory_vector[STAT_COUNTER_NODE_CALLS].data; + c = counters[j]; + c[n->index] = n->stats_total.calls - n->stats_last_clear.calls; + + counters = sm->directory_vector[STAT_COUNTER_NODE_SUSPENDS].data; + c = counters[j]; + c[n->index] = n->stats_total.suspends - n->stats_last_clear.suspends; + } + vec_free (node_dups[j]); + } + vec_free (node_dups); + vec_free (stat_vms); +} + +static void +do_stat_segment_updates (vlib_main_t *vm, vlib_stats_segment_t *sm) +{ + if (sm->node_counters_enabled) + update_node_counters (sm); + + vlib_stats_collector_t *c; + pool_foreach (c, sm->collectors) + { + vlib_stats_collector_data_t data = { + .entry_index = c->entry_index, + .vector_index = c->vector_index, + .private_data = c->private_data, + .entry = sm->directory_vector + c->entry_index, + }; + c->fn (&data); + } + + /* Heartbeat, so clients detect we're still here */ + sm->directory_vector[STAT_COUNTER_HEARTBEAT].value++; +} + +static uword +stat_segment_collector_process (vlib_main_t *vm, vlib_node_runtime_t *rt, + vlib_frame_t *f) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + + while (1) + { + do_stat_segment_updates (vm, sm); + vlib_process_suspend (vm, sm->update_interval); + } + return 0; /* or not */ +} + +VLIB_REGISTER_NODE (stat_segment_collector, static) = { + .function = stat_segment_collector_process, + .name = "statseg-collector-process", + .type = VLIB_NODE_TYPE_PROCESS, +}; |