#undef HAVE_MEMFD_CREATE
#include <vppinfra/linux/syscall.h>
#include <vpp-api/client/stat_client.h>
+#include <vppinfra/mheap.h>
+
stat_segment_main_t stat_segment_main;
/*
return clib_mem_set_heap (sm->heap);
}
-/* Name to vector index hash */
static u32
-lookup_or_create_hash_index (void *oldheap, char *name, u32 next_vector_index)
+lookup_or_create_hash_index (u8 * name, u32 next_vector_index)
{
stat_segment_main_t *sm = &stat_segment_main;
u32 index;
hash_pair_t *hp;
+ /* Must be called in the context of the main heap */
+ ASSERT (clib_mem_get_heap () != sm->heap);
+
hp = hash_get_pair (sm->directory_vector_by_name, name);
if (!hp)
{
- hash_set (sm->directory_vector_by_name, name, next_vector_index);
+ /* we allocate our private copy of 'name' */
+ hash_set (sm->directory_vector_by_name, format (0, "%s%c", name, 0),
+ next_vector_index);
index = next_vector_index;
}
else
cm->stat_segment_name ? cm->stat_segment_name : cm->name;
u32 next_vector_index = vec_len (sm->directory_vector);
clib_mem_set_heap (oldheap); /* Exit stats segment */
- u32 vector_index = lookup_or_create_hash_index (oldheap, stat_segment_name,
+ u32 vector_index = lookup_or_create_hash_index ((u8 *) stat_segment_name,
next_vector_index);
/* Back to stats segment */
clib_mem_set_heap (sm->heap); /* Re-enter stat segment */
}
void
-vlib_stats_register_error_index (u8 * name, u64 * em_vec, u64 index)
+vlib_stats_register_error_index (void *oldheap, u8 * name, u64 * em_vec,
+ u64 index)
{
stat_segment_main_t *sm = &stat_segment_main;
stat_segment_shared_header_t *shared_header = sm->shared_header;
stat_segment_directory_entry_t e;
- hash_pair_t *hp;
ASSERT (shared_header);
vlib_stat_segment_lock ();
+ u32 next_vector_index = vec_len (sm->directory_vector);
+ clib_mem_set_heap (oldheap); /* Exit stats segment */
- memcpy (e.name, name, vec_len (name));
- e.name[vec_len (name)] = '\0';
- e.type = STAT_DIR_TYPE_ERROR_INDEX;
- e.offset = index;
- e.offset_vector = 0;
- vec_add1 (sm->directory_vector, e);
+ u32 vector_index = lookup_or_create_hash_index (name,
+ next_vector_index);
- /* Warn clients to refresh any pointers they might be holding */
- shared_header->directory_offset =
- stat_segment_offset (shared_header, sm->directory_vector);
+ /* Back to stats segment */
+ clib_mem_set_heap (sm->heap); /* Re-enter stat segment */
+
+ if (next_vector_index == vector_index)
+ {
+ memcpy (e.name, name, vec_len (name));
+ e.name[vec_len (name)] = '\0';
+ e.type = STAT_DIR_TYPE_ERROR_INDEX;
+ e.offset = index;
+ e.offset_vector = 0;
+ vec_add1 (sm->directory_vector, e);
+
+ /* Warn clients to refresh any pointers they might be holding */
+ shared_header->directory_offset =
+ stat_segment_offset (shared_header, sm->directory_vector);
+ }
vlib_stat_segment_unlock ();
}
}
void
-vlib_stats_pop_heap2 (u64 * error_vector, u32 thread_index, void *oldheap)
+vlib_stats_pop_heap2 (u64 * error_vector, u32 thread_index, void *oldheap,
+ int lock)
{
stat_segment_main_t *sm = &stat_segment_main;
stat_segment_shared_header_t *shared_header = sm->shared_header;
ASSERT (shared_header);
- vlib_stat_segment_lock ();
+ if (lock)
+ vlib_stat_segment_lock ();
/* Reset the client hash table pointer, since it WILL change! */
- shared_header->error_offset =
+ vec_validate (sm->error_vector, thread_index);
+ sm->error_vector[thread_index] =
stat_segment_offset (shared_header, error_vector);
+
+ shared_header->error_offset =
+ stat_segment_offset (shared_header, sm->error_vector);
shared_header->directory_offset =
stat_segment_offset (shared_header, sm->directory_vector);
- vlib_stat_segment_unlock ();
+ if (lock)
+ vlib_stat_segment_unlock ();
clib_mem_set_heap (oldheap);
}
{
stat_segment_main_t *sm = &stat_segment_main;
stat_segment_shared_header_t *shared_header;
- stat_segment_directory_entry_t *ep;
void *oldheap;
ssize_t memory_size;
int mfd;
sm->directory_vector_by_name = hash_create_string (0, sizeof (uword));
sm->shared_header = shared_header = memaddr;
+
+ shared_header->version = STAT_SEGMENT_VERSION;
+
sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
clib_spinlock_init (sm->stat_segment_lockp);
clib_mem_set_heap (oldheap);
+ /* Total shared memory size */
+ clib_mem_usage_t usage;
+ mheap_usage (sm->heap, &usage);
+ sm->directory_vector[STAT_COUNTER_MEM_STATSEG_TOTAL].value =
+ usage.bytes_total;
+
return 0;
}
vlib_cli_command_t * cmd)
{
stat_segment_main_t *sm = &stat_segment_main;
- counter_t *counter;
- hash_pair_t *p;
- stat_segment_directory_entry_t *show_data, *this;
- int i, j;
+ stat_segment_directory_entry_t *show_data;
+ int i;
int verbose = 0;
- u8 *s;
if (unformat (input, "verbose"))
verbose = 1;
static inline void
update_node_counters (stat_segment_main_t * sm)
{
- vlib_main_t *vm = vlib_mains[0];
vlib_main_t **stat_vms = 0;
vlib_node_t ***node_dups = 0;
int i, j;
vlib_stat_segment_lock ();
stat_validate_counter_vector (&sm->directory_vector
- [STAT_COUNTER_NODE_CLOCKS], l);
+ [STAT_COUNTER_NODE_CLOCKS], l - 1);
stat_validate_counter_vector (&sm->directory_vector
- [STAT_COUNTER_NODE_VECTORS], l);
+ [STAT_COUNTER_NODE_VECTORS], l - 1);
stat_validate_counter_vector (&sm->directory_vector
- [STAT_COUNTER_NODE_CALLS], l);
+ [STAT_COUNTER_NODE_CALLS], l - 1);
stat_validate_counter_vector (&sm->directory_vector
- [STAT_COUNTER_NODE_SUSPENDS], l);
+ [STAT_COUNTER_NODE_SUSPENDS], l - 1);
- vec_validate (sm->nodes, l);
+ vec_validate (sm->nodes, l - 1);
stat_segment_directory_entry_t *ep;
ep = &sm->directory_vector[STAT_COUNTER_NODE_NAMES];
ep->offset = stat_segment_offset (shared_header, sm->nodes);
ep->offset_vector ? stat_segment_pointer (shared_header,
ep->offset_vector) : 0;
/* Update names dictionary */
- vec_validate (offset_vector, l);
+ vec_validate (offset_vector, l - 1);
vlib_node_t **nodes = node_dups[0];
+
for (i = 0; i < vec_len (nodes); i++)
{
vlib_node_t *n = nodes[i];
for (j = 0; j < vec_len (node_dups); j++)
{
vlib_node_t **nodes = node_dups[j];
- u32 l = vec_len (nodes);
for (i = 0; i < vec_len (nodes); i++)
{
static void
do_stat_segment_updates (stat_segment_main_t * sm)
{
+ stat_segment_shared_header_t *shared_header = sm->shared_header;
vlib_main_t *vm = vlib_mains[0];
f64 vector_rate;
- u64 input_packets, last_input_packets;
+ u64 input_packets;
f64 dt, now;
vlib_main_t *this_vlib_main;
int i, start;
+ counter_t **counters;
+ static int num_worker_threads_set;
+
+ /*
+ * Set once at the beginning of time.
+ * Can't do this from the init routine, which happens before
+ * start_workers sets up vlib_mains...
+ */
+ if (PREDICT_FALSE (num_worker_threads_set == 0))
+ {
+ sm->directory_vector[STAT_COUNTER_NUM_WORKER_THREADS].value =
+ vec_len (vlib_mains) > 1 ? vec_len (vlib_mains) - 1 : 1;
+
+ stat_validate_counter_vector (&sm->directory_vector
+ [STAT_COUNTER_VECTOR_RATE_PER_WORKER],
+ vec_len (vlib_mains));
+ num_worker_threads_set = 1;
+ }
/*
- * Compute the average vector rate across all workers
+ * Compute per-worker vector rates, and the average vector rate
+ * across all workers
*/
vector_rate = 0.0;
+ counters =
+ stat_segment_pointer (shared_header,
+ sm->directory_vector
+ [STAT_COUNTER_VECTOR_RATE_PER_WORKER].offset);
+
start = vec_len (vlib_mains) > 1 ? 1 : 0;
for (i = start; i < vec_len (vlib_mains); i++)
{
+
+ f64 this_vector_rate;
+
this_vlib_main = vlib_mains[i];
- vector_rate += vlib_last_vector_length_per_node (this_vlib_main);
+
+ this_vector_rate = vlib_last_vector_length_per_node (this_vlib_main);
+ vector_rate += this_vector_rate;
+
+ /* Set the per-worker rate */
+ counters[i - start][0] = this_vector_rate;
}
+
+ /* And set the system average rate */
vector_rate /= (f64) (i - start);
- sm->directory_vector[STAT_COUNTER_VECTOR_RATE].value =
- vector_rate / ((f64) (vec_len (vlib_mains) - start));
+ sm->directory_vector[STAT_COUNTER_VECTOR_RATE].value = vector_rate;
/*
* Compute the aggregate input rate
sm->directory_vector[STAT_COUNTER_LAST_STATS_CLEAR].value =
vm->node_main.time_last_runtime_stats_clear;
+ /* Stats segment memory heap counter */
+ clib_mem_usage_t usage;
+ mheap_usage (sm->heap, &usage);
+ sm->directory_vector[STAT_COUNTER_MEM_STATSEG_USED].value =
+ usage.bytes_used;
+
if (sm->node_counters_enabled)
update_node_counters (sm);
return 0;
}
-static void
+static clib_error_t *
stats_segment_socket_init (void)
{
stat_segment_main_t *sm = &stat_segment_main;
CLIB_SOCKET_F_ALLOW_GROUP_WRITE | CLIB_SOCKET_F_PASSCRED;
if ((error = clib_socket_init (s)))
- {
- clib_error_report (error);
- return;
- }
+ return error;
clib_file_t template = { 0 };
template.read_function = stats_socket_accept_ready;
clib_file_add (&file_main, &template);
sm->socket = s;
+
+ return 0;
}
static clib_error_t *
statseg_init (vlib_main_t * vm)
{
stat_segment_main_t *sm = &stat_segment_main;
- clib_error_t *error;
- /* dependent on unix_input_init */
- if ((error = vlib_call_init_function (vm, unix_input_init)))
- return error;
+ /* set default socket file name when statseg config stanza is empty. */
+ if (!vec_len (sm->socket_name))
+ sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
+ STAT_SEGMENT_SOCKET_FILENAME);
+ return stats_segment_socket_init ();
+}
- if (sm->socket_name)
- stats_segment_socket_init ();
+/* *INDENT-OFF* */
+VLIB_INIT_FUNCTION (statseg_init) =
+{
+ .runs_after = VLIB_INITS("unix_input_init"),
+};
+/* *INDENT-ON* */
- return 0;
-}
clib_error_t *
stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
stat_segment_shared_header_t *shared_header = sm->shared_header;
void *oldheap;
stat_segment_directory_entry_t e;
- u32 index;
stat_segment_gauges_pool_t *gauge;
ASSERT (shared_header);
+ u32 next_vector_index = vec_len (sm->directory_vector);
+ u32 vector_index = lookup_or_create_hash_index (name,
+ next_vector_index);
+
+ if (vector_index < next_vector_index) /* Already registered */
+ return clib_error_return (0, "%v is alreadty registered", name);
+
oldheap = vlib_stats_push_heap (NULL);
vlib_stat_segment_lock ();
e.type = STAT_DIR_TYPE_SCALAR_INDEX;
memcpy (e.name, name, vec_len (name));
- index = vec_len (sm->directory_vector);
vec_add1 (sm->directory_vector, e);
shared_header->directory_offset =
pool_get (sm->gauges, gauge);
gauge->fn = update_fn;
gauge->caller_index = caller_index;
- gauge->directory_index = index;
+ gauge->directory_index = next_vector_index;
return NULL;
}
{
stat_segment_main_t *sm = &stat_segment_main;
- /* set default socket file name when statseg config stanza is empty. */
- sm->socket_name = format (0, "%s", STAT_SEGMENT_SOCKET_FILE);
-
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "socket-name %s", &sm->socket_name))
;
+ /* DEPRECATE: default (does nothing) */
else if (unformat (input, "default"))
- sm->socket_name = format (0, "%s", STAT_SEGMENT_SOCKET_FILE);
- else
- if (unformat
- (input, "size %U", unformat_memory_size, &sm->memory_size))
+ ;
+ else if (unformat (input, "size %U",
+ unformat_memory_size, &sm->memory_size))
;
else if (unformat (input, "per-node-counters on"))
sm->node_counters_enabled = 1;
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
+
+ /*
+ * NULL-terminate socket name string
+ * clib_socket_init()->socket_config() use C str*
+ */
+ if (vec_len (sm->socket_name))
+ vec_terminate_c_string (sm->socket_name);
+
return 0;
}
return 0;
}
-VLIB_INIT_FUNCTION (statseg_init);
VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg");
VNET_SW_INTERFACE_ADD_DEL_FUNCTION (statseg_sw_interface_add_del);