diff options
author | Dave Barach <dave@barachs.net> | 2018-06-13 09:26:05 -0400 |
---|---|---|
committer | Dave Barach <dave@barachs.net> | 2018-06-13 09:26:41 -0400 |
commit | 1ddbc0138b64486b8e51e5e12fcad21fba8b8b68 (patch) | |
tree | af95c33e6e1681498a49b130119103b60f64db08 /src/vpp/stats | |
parent | c7d50970d4ed8a4889b4374e6a1559aef7d3dcc0 (diff) |
Stat segment / client: show run" works now
Seems to have minimal-to-zero performance consequences. Data appears
accurate: result match the debug CLI output. Checked at low rates, 27
MPPS sprayed across two worker threads.
Change-Id: I09ede5150b88a91547feeee448a2854997613004
Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'src/vpp/stats')
-rw-r--r-- | src/vpp/stats/stat_segment.c | 185 | ||||
-rw-r--r-- | src/vpp/stats/stats.c | 8 | ||||
-rw-r--r-- | src/vpp/stats/stats.h | 19 |
3 files changed, 161 insertions, 51 deletions
diff --git a/src/vpp/stats/stat_segment.c b/src/vpp/stats/stat_segment.c index f1db684fecd..6fb9c83a369 100644 --- a/src/vpp/stats/stat_segment.c +++ b/src/vpp/stats/stat_segment.c @@ -14,6 +14,20 @@ */ #include <vpp/stats/stats.h> +void +vlib_stat_segment_lock (void) +{ + stats_main_t *sm = &stats_main; + clib_spinlock_lock (sm->stat_segment_lockp); +} + +void +vlib_stat_segment_unlock (void) +{ + stats_main_t *sm = &stats_main; + clib_spinlock_unlock (sm->stat_segment_lockp); +} + void * vlib_stats_push_heap (void) { @@ -215,6 +229,8 @@ map_stat_segment_init (vlib_main_t * vm) CLIB_CACHE_LINE_BYTES); sm->vector_rate_ptr = (scalar_data + 0); sm->input_rate_ptr = (scalar_data + 1); + sm->last_runtime_ptr = (scalar_data + 2); + sm->last_runtime_stats_clear_ptr = (scalar_data + 3); name = format (0, "vector_rate%c", 0); ep = clib_mem_alloc (sizeof (*ep)); @@ -230,6 +246,21 @@ map_stat_segment_init (vlib_main_t * vm) hash_set_mem (sm->counter_vector_by_name, name, ep); + name = format (0, "last_update%c", 0); + ep = clib_mem_alloc (sizeof (*ep)); + ep->type = STAT_DIR_TYPE_SCALAR_POINTER; + ep->value = sm->last_runtime_ptr; + + hash_set_mem (sm->counter_vector_by_name, name, ep); + + name = format (0, "last_stats_clear%c", 0); + ep = clib_mem_alloc (sizeof (*ep)); + ep->type = STAT_DIR_TYPE_SCALAR_POINTER; + ep->value = sm->last_runtime_stats_clear_ptr; + + hash_set_mem (sm->counter_vector_by_name, name, ep); + + /* Publish the hash table */ shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] = sm->counter_vector_by_name; @@ -279,6 +310,10 @@ format_stat_dir_entry (u8 * s, va_list * args) type_name = "CMainPtr"; break; + case STAT_DIR_TYPE_SERIALIZED_NODES: + type_name = "SerNodesPtr"; + break; + case STAT_DIR_TYPE_ERROR_INDEX: type_name = "ErrIndex"; format_string = "%-10s %20lld"; @@ -292,8 +327,6 @@ format_stat_dir_entry (u8 * s, va_list * args) return format (s, format_string, type_name, ep->value); } - - static clib_error_t * show_stat_segment_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -362,62 +395,120 @@ VLIB_CLI_COMMAND (show_stat_segment_command, static) = }; /* *INDENT-ON* */ -static uword -stat_segment_process (vlib_main_t * vm, vlib_node_runtime_t * rt, - vlib_frame_t * f) +static inline void +update_serialized_nodes (stats_main_t * sm) { - f64 vector_rate; - u64 input_packets, last_input_packets; - f64 last_runtime, dt, now; - vlib_main_t *this_vlib_main; - stats_main_t *sm = &stats_main; int i; + vlib_main_t *vm = vlib_mains[0]; + ssvm_private_t *ssvmp = &sm->stat_segment; + ssvm_shared_header_t *shared_header; + void *oldheap; + stat_segment_directory_entry_t *ep; + hash_pair_t *hp; + u8 *name_copy; - last_runtime = 0.0; - last_input_packets = 0; + ASSERT (ssvmp && ssvmp->sh); - last_runtime = 0.0; - last_input_packets = 0; + vec_reset_length (sm->serialized_nodes); - while (1) + shared_header = ssvmp->sh; + + oldheap = ssvm_push_heap (shared_header); + + clib_spinlock_lock (sm->stat_segment_lockp); + + vlib_node_get_nodes (0 /* vm, for barrier sync */ , + (u32) ~ 0 /* all threads */ , + 1 /* include stats */ , + 0 /* barrier sync */ , + &sm->node_dups, &sm->stat_vms); + + sm->serialized_nodes = vlib_node_serialize (vm, sm->node_dups, + sm->serialized_nodes, + 0 /* include nexts */ , + 1 /* include stats */ ); + + hp = hash_get_pair (sm->counter_vector_by_name, "serialized_nodes"); + if (hp) + { + name_copy = (u8 *) hp->key; + ep = (stat_segment_directory_entry_t *) (hp->value[0]); + + if (ep->value != sm->serialized_nodes) + { + ep->value = sm->serialized_nodes; + /* Warn clients to refresh any pointers they might be holding */ + shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) + ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1); + } + } + else { - vlib_process_suspend (vm, 5.0); - - /* - * Compute the average vector rate across all workers - */ - vector_rate = 0.0; - - /* *INDENT-OFF* */ - for (i = 0; i < vec_len (vlib_mains); i++) - { - this_vlib_main = vlib_mains[i]; - vector_rate += vlib_last_vector_length_per_node (vm); - } - vector_rate /= (f64) i; - - /* *INDENT-ON* */ - - *sm->vector_rate_ptr = vector_rate / ((f64) vec_len (vlib_mains)); - now = vlib_time_now (vm); - dt = now - last_runtime; - input_packets = vnet_get_aggregate_rx_packets (); - *sm->input_rate_ptr = (f64) (input_packets - last_input_packets) / dt; - last_runtime = now; - last_input_packets = input_packets; + name_copy = format (0, "%s%c", "serialized_nodes", 0); + ep = clib_mem_alloc (sizeof (*ep)); + ep->type = STAT_DIR_TYPE_SERIALIZED_NODES; + ep->value = sm->serialized_nodes; + hash_set_mem (sm->counter_vector_by_name, name_copy, ep); + + /* Reset the client hash table pointer */ + shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR] + = sm->counter_vector_by_name; + + /* Warn clients to refresh any pointers they might be holding */ + shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] = (void *) + ((u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH] + 1); } - return 0; /* not so much */ + clib_spinlock_unlock (sm->stat_segment_lockp); + ssvm_pop_heap (oldheap); } -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (stat_segment_node,static) = +/* + * Called by stats_thread_fn, in stats.c, which runs in a + * separate pthread, which won't halt the parade + * in single-forwarding-core cases. + */ + +void +do_stat_segment_updates (stats_main_t * sm) { - .function = stat_segment_process, - .type = VLIB_NODE_TYPE_PROCESS, - .name = "stat-segment-process", -}; -/* *INDENT-ON* */ + vlib_main_t *vm = vlib_mains[0]; + f64 vector_rate; + u64 input_packets, last_input_packets; + f64 dt, now; + vlib_main_t *this_vlib_main; + int i, start; + + /* + * Compute the average vector rate across all workers + */ + vector_rate = 0.0; + + start = vec_len (vlib_mains) > 1 ? 1 : 0; + + for (i = start; i < vec_len (vlib_mains); i++) + { + this_vlib_main = vlib_mains[i]; + vector_rate += vlib_last_vector_length_per_node (this_vlib_main); + } + vector_rate /= (f64) (i - start); + + *sm->vector_rate_ptr = vector_rate / ((f64) (vec_len (vlib_mains) - start)); + + /* + * Compute the aggregate input rate + */ + now = vlib_time_now (vm); + dt = now - sm->last_runtime_ptr[0]; + input_packets = vnet_get_aggregate_rx_packets (); + *sm->input_rate_ptr = (f64) (input_packets - sm->last_input_packets) / dt; + sm->last_runtime_ptr[0] = now; + sm->last_input_packets = input_packets; + sm->last_runtime_stats_clear_ptr[0] = + vm->node_main.time_last_runtime_stats_clear; + + update_serialized_nodes (sm); +} /* diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c index f1c40e630d2..31cfc336aca 100644 --- a/src/vpp/stats/stats.c +++ b/src/vpp/stats/stats.c @@ -2340,10 +2340,12 @@ stats_thread_fn (void *arg) ip46_fib_stats_delay (sm, sm->stats_poll_interval_in_seconds, 0 /* nsec */ ); + /* Always update stats segment data */ + do_stat_segment_updates (sm); + if (!(sm->enable_poller)) - { - continue; - } + continue; + if (pool_elts (sm->stats_registrations[IDX_PER_INTERFACE_COMBINED_COUNTERS])) do_combined_per_interface_counters (sm); diff --git a/src/vpp/stats/stats.h b/src/vpp/stats/stats.h index fd1ab271f78..262304e81ed 100644 --- a/src/vpp/stats/stats.h +++ b/src/vpp/stats/stats.h @@ -163,9 +163,23 @@ typedef struct uword *counter_vector_by_name; clib_spinlock_t *stat_segment_lockp; - /* Pointers to scalar stats maintained by the stat segment process */ + /* Pointers to scalar stats maintained by the stat thread */ f64 *input_rate_ptr; + f64 *last_runtime_ptr; + f64 *last_runtime_stats_clear_ptr; f64 *vector_rate_ptr; + u64 last_input_packets; + + /* Pointers to vector stats maintained by the stat thread */ + u8 *serialized_nodes; + vlib_main_t **stat_vms; + vlib_node_t ***node_dups; + + f64 *vectors_per_node; + f64 *vector_rate_in; + f64 *vector_rate_out; + f64 *vector_rate_drop; + f64 *vector_rate_punt; /* convenience */ vlib_main_t *vlib_main; @@ -187,6 +201,7 @@ typedef enum STAT_DIR_TYPE_VECTOR_POINTER, STAT_DIR_TYPE_COUNTER_VECTOR, STAT_DIR_TYPE_ERROR_INDEX, + STAT_DIR_TYPE_SERIALIZED_NODES, } stat_directory_type_t; typedef struct @@ -195,6 +210,8 @@ typedef struct void *value; } stat_segment_directory_entry_t; +void do_stat_segment_updates (stats_main_t * sm); + #endif /* __included_stats_h__ */ /* |