diff options
Diffstat (limited to 'src/vlib/stats/stats.c')
-rw-r--r-- | src/vlib/stats/stats.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/src/vlib/stats/stats.c b/src/vlib/stats/stats.c new file mode 100644 index 00000000000..19edaf0866d --- /dev/null +++ b/src/vlib/stats/stats.c @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2022 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vlib/stats/stats.h> + +vlib_stats_main_t vlib_stats_main; + +/* + * Used only by VPP writers + */ + +void +vlib_stats_segment_lock (void) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + clib_spinlock_lock (sm->stat_segment_lockp); + sm->shared_header->in_progress = 1; +} + +void +vlib_stats_segment_unlock (void) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + sm->shared_header->epoch++; + sm->shared_header->in_progress = 0; + clib_spinlock_unlock (sm->stat_segment_lockp); +} + +/* + * Change heap to the stats shared memory segment + */ +void * +vlib_stats_set_heap () +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + + ASSERT (sm && sm->shared_header); + return clib_mem_set_heap (sm->heap); +} + +u32 +vlib_stats_find_entry_index (char *fmt, ...) +{ + u8 *name; + va_list va; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + vec_add1 (name, 0); + + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + hash_pair_t *hp = hash_get_pair (sm->directory_vector_by_name, name); + vec_free (name); + return hp ? hp->value[0] : STAT_SEGMENT_INDEX_INVALID; +} + +static void +hash_set_str_key_alloc (uword **h, const char *key, uword v) +{ + int size = strlen (key) + 1; + void *copy = clib_mem_alloc (size); + clib_memcpy_fast (copy, key, size); + hash_set_mem (*h, copy, v); +} + +static void +hash_unset_str_key_free (uword **h, const char *key) +{ + hash_pair_t *hp = hash_get_pair_mem (*h, key); + if (hp) + { + void *_k = uword_to_pointer (hp->key, void *); + hash_unset_mem (*h, _k); + clib_mem_free (_k); + } +} + +u32 +vlib_stats_create_counter (vlib_stats_entry_t *e) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + void *oldheap; + u32 index = ~0; + int i; + + oldheap = clib_mem_set_heap (sm->heap); + vec_foreach_index_backwards (i, sm->directory_vector) + if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY) + { + index = i; + break; + } + + index = index == ~0 ? vec_len (sm->directory_vector) : index; + + vec_validate (sm->directory_vector, index); + sm->directory_vector[index] = *e; + + clib_mem_set_heap (oldheap); + hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, index); + + return index; +} + +void +vlib_stats_remove_entry (u32 entry_index) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index); + void *oldheap; + counter_t **c; + u32 i; + + if (entry_index >= vec_len (sm->directory_vector)) + return; + + oldheap = clib_mem_set_heap (sm->heap); + + switch (e->type) + { + case STAT_DIR_TYPE_NAME_VECTOR: + for (i = 0; i < vec_len (e->string_vector); i++) + vec_free (e->string_vector[i]); + vec_free (e->string_vector); + break; + + case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE: + c = e->data; + e->data = 0; + for (i = 0; i < vec_len (c); i++) + vec_free (c[i]); + vec_free (c); + break; + + case STAT_DIR_TYPE_SCALAR_INDEX: + case STAT_DIR_TYPE_SYMLINK: + break; + default: + ASSERT (0); + } + + clib_mem_set_heap (oldheap); + hash_unset_str_key_free (&sm->directory_vector_by_name, e->name); + + memset (e, 0, sizeof (*e)); + e->type = STAT_DIR_TYPE_EMPTY; +} + +static void +vlib_stats_set_entry_name (vlib_stats_entry_t *e, char *s) +{ + u32 i, len = VLIB_STATS_MAX_NAME_SZ - 1; + + for (i = 0; i < len; i++) + { + e->name[i] = s[i]; + if (s[i] == 0) + return; + } + ASSERT (i < VLIB_STATS_MAX_NAME_SZ - 1); + s[i] = 0; +} + +void +vlib_stats_update_counter (void *cm_arg, u32 cindex, + stat_directory_type_t type) +{ + vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg; + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_shared_header_t *shared_header = sm->shared_header; + char *stat_segment_name; + vlib_stats_entry_t e = { 0 }; + + /* Not all counters have names / hash-table entries */ + if (!cm->name && !cm->stat_segment_name) + return; + + ASSERT (shared_header); + + vlib_stats_segment_lock (); + + /* Lookup hash-table is on the main heap */ + stat_segment_name = cm->stat_segment_name ? cm->stat_segment_name : cm->name; + + u32 vector_index = vlib_stats_find_entry_index ("%s", stat_segment_name); + + /* Update the vector */ + if (vector_index == STAT_SEGMENT_INDEX_INVALID) + { + vlib_stats_set_entry_name (&e, stat_segment_name); + e.type = type; + vector_index = vlib_stats_create_counter (&e); + } + + vlib_stats_entry_t *ep = &sm->directory_vector[vector_index]; + ep->data = cm->counters; + + /* Reset the client hash table pointer, since it WILL change! */ + shared_header->directory_vector = sm->directory_vector; + + vlib_stats_segment_unlock (); +} + +void +vlib_stats_register_error_index (u64 *em_vec, u64 index, char *fmt, ...) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_shared_header_t *shared_header = sm->shared_header; + vlib_stats_entry_t e = {}; + va_list va; + u8 *name; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + + ASSERT (shared_header); + + vlib_stats_segment_lock (); + u32 vector_index = vlib_stats_find_entry_index ("%v", name); + + if (vector_index == STAT_SEGMENT_INDEX_INVALID) + { + vec_add1 (name, 0); + vlib_stats_set_entry_name (&e, (char *) name); + e.type = STAT_DIR_TYPE_ERROR_INDEX; + e.index = index; + vector_index = vlib_stats_create_counter (&e); + + /* Warn clients to refresh any pointers they might be holding */ + shared_header->directory_vector = sm->directory_vector; + } + + vlib_stats_segment_unlock (); + vec_free (name); +} + +void +vlib_stats_update_error_vector (u64 *error_vector, u32 thread_index, int lock) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_shared_header_t *shared_header = sm->shared_header; + void *oldheap = clib_mem_set_heap (sm->heap); + + ASSERT (shared_header); + + if (lock) + vlib_stats_segment_lock (); + + /* Reset the client hash table pointer, since it WILL change! */ + vec_validate (sm->error_vector, thread_index); + sm->error_vector[thread_index] = error_vector; + + shared_header->error_vector = sm->error_vector; + shared_header->directory_vector = sm->directory_vector; + + if (lock) + vlib_stats_segment_unlock (); + clib_mem_set_heap (oldheap); +} + +void +vlib_stats_delete_cm (void *cm_arg) +{ + vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg; + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_entry_t *e; + + /* Not all counters have names / hash-table entries */ + if (!cm->name && !cm->stat_segment_name) + return; + + vlib_stats_segment_lock (); + + /* Lookup hash-table is on the main heap */ + char *stat_segment_name = + cm->stat_segment_name ? cm->stat_segment_name : cm->name; + u32 index = vlib_stats_find_entry_index ("%s", stat_segment_name); + + e = &sm->directory_vector[index]; + + hash_unset_str_key_free (&sm->directory_vector_by_name, e->name); + + memset (e, 0, sizeof (*e)); + e->type = STAT_DIR_TYPE_EMPTY; + + vlib_stats_segment_unlock (); +} + +static u32 +vlib_stats_new_entry_internal (stat_directory_type_t t, u8 *name) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_shared_header_t *shared_header = sm->shared_header; + vlib_stats_entry_t e = { .type = t }; + + ASSERT (shared_header); + + u32 vector_index = vlib_stats_find_entry_index ("%v", name); + if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */ + { + vector_index = ~0; + goto done; + } + + vec_add1 (name, 0); + vlib_stats_set_entry_name (&e, (char *) name); + + vlib_stats_segment_lock (); + vector_index = vlib_stats_create_counter (&e); + + shared_header->directory_vector = sm->directory_vector; + + vlib_stats_segment_unlock (); + +done: + vec_free (name); + return vector_index; +} + +u32 +vlib_stats_add_gauge (char *fmt, ...) +{ + va_list va; + u8 *name; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name); +} + +void +vlib_stats_set_gauge (u32 index, u64 value) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + + ASSERT (index < vec_len (sm->directory_vector)); + sm->directory_vector[index].value = value; +} + +u32 +vlib_stats_add_timestamp (char *fmt, ...) +{ + va_list va; + u8 *name; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + return vlib_stats_new_entry_internal (STAT_DIR_TYPE_SCALAR_INDEX, name); +} + +void +vlib_stats_set_timestamp (u32 entry_index, f64 value) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + + ASSERT (entry_index < vec_len (sm->directory_vector)); + sm->directory_vector[entry_index].value = value; +} + +u32 +vlib_stats_add_string_vector (char *fmt, ...) +{ + va_list va; + u8 *name; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + return vlib_stats_new_entry_internal (STAT_DIR_TYPE_NAME_VECTOR, name); +} + +void +vlib_stats_set_string_vector (u32 entry_index, u32 vector_index, char *fmt, + ...) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index); + va_list va; + void *oldheap; + + oldheap = clib_mem_set_heap (sm->heap); + vlib_stats_segment_lock (); + + vec_validate (e->string_vector, vector_index); + vec_reset_length (e->string_vector[vector_index]); + + va_start (va, fmt); + e->string_vector[vector_index] = + va_format (e->string_vector[vector_index], fmt, &va); + va_end (va); + + vlib_stats_segment_unlock (); + clib_mem_set_heap (oldheap); +} + +u32 +vlib_stats_add_counter_vector (char *fmt, ...) +{ + va_list va; + u8 *name; + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + return vlib_stats_new_entry_internal (STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE, + name); +} + +void +vlib_stats_validate_counter_vector (u32 entry_index, u32 vector_index) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index); + void *oldheap; + counter_t **c = e->data; + + if (vec_len (c) > 0 && vec_len (c[0]) > vector_index) + return; + + oldheap = clib_mem_set_heap (sm->heap); + vlib_stats_segment_lock (); + + vec_validate_aligned (c, 0, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned (c[0], vector_index, CLIB_CACHE_LINE_BYTES); + e->data = c; + + vlib_stats_segment_unlock (); + clib_mem_set_heap (oldheap); +} + +u32 +vlib_stats_add_symlink (u32 entry_index, u32 vector_index, char *fmt, ...) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_shared_header_t *shared_header = sm->shared_header; + vlib_stats_entry_t e; + va_list va; + u8 *name; + + ASSERT (shared_header); + ASSERT (entry_index < vec_len (sm->directory_vector)); + + va_start (va, fmt); + name = va_format (0, fmt, &va); + va_end (va); + + if (vlib_stats_find_entry_index ("%v", name) == STAT_SEGMENT_INDEX_INVALID) + { + vec_add1 (name, 0); + vlib_stats_set_entry_name (&e, (char *) name); + e.type = STAT_DIR_TYPE_SYMLINK; + e.index1 = entry_index; + e.index2 = vector_index; + vector_index = vlib_stats_create_counter (&e); + + /* Warn clients to refresh any pointers they might be holding */ + shared_header->directory_vector = sm->directory_vector; + } + else + vector_index = ~0; + + vec_free (name); + return vector_index; +} + +void +vlib_stats_rename_symlink (u64 entry_index, char *fmt, ...) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_entry_t *e = vlib_stats_get_entry (sm, entry_index); + va_list va; + u8 *new_name; + + hash_unset_str_key_free (&sm->directory_vector_by_name, e->name); + + va_start (va, fmt); + new_name = va_format (0, fmt, &va); + va_end (va); + + vec_add1 (new_name, 0); + vlib_stats_set_entry_name (e, (char *) new_name); + hash_set_str_key_alloc (&sm->directory_vector_by_name, e->name, entry_index); + vec_free (new_name); +} + +f64 +vlib_stats_get_segment_update_rate (void) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + return sm->update_interval; +} + +void +vlib_stats_register_collector_fn (vlib_stats_collector_reg_t *reg) +{ + vlib_stats_segment_t *sm = vlib_stats_get_segment (); + vlib_stats_collector_t *c; + + ASSERT (reg->entry_index != ~0); + + pool_get_zero (sm->collectors, c); + c->fn = reg->collect_fn; + c->entry_index = reg->entry_index; + c->vector_index = reg->vector_index; + c->private_data = reg->private_data; + + return; +} |