From: Dave Barach Date: Wed, 13 Jun 2018 13:26:05 +0000 (-0400) Subject: Stat segment / client: show run" works now X-Git-Tag: v18.07-rc1~180 X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commitdiff_plain;h=1ddbc0138b64486b8e51e5e12fcad21fba8b8b68 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 --- diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 635b4ef72ba..b9f08048651 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -3088,13 +3088,14 @@ static void vl_api_get_node_graph_reply_t_handler { hash_free (vam->graph_node_index_by_name); - for (i = 0; i < vec_len (vam->graph_nodes); i++) + for (i = 0; i < vec_len (vam->graph_nodes[0]); i++) { - node = vam->graph_nodes[i]; + node = vam->graph_nodes[0][i]; vec_free (node->name); vec_free (node->next_nodes); vec_free (node); } + vec_free (vam->graph_nodes[0]); vec_free (vam->graph_nodes); } @@ -3102,9 +3103,9 @@ static void vl_api_get_node_graph_reply_t_handler vam->graph_nodes = vlib_node_unserialize (pvt_copy); vec_free (pvt_copy); - for (i = 0; i < vec_len (vam->graph_nodes); i++) + for (i = 0; i < vec_len (vam->graph_nodes[0]); i++) { - node = vam->graph_nodes[i]; + node = vam->graph_nodes[0][i]; hash_set_mem (vam->graph_node_index_by_name, node->name, i); } } @@ -23389,15 +23390,15 @@ dump_node_table (vat_main_t * vam) return 0; } - for (i = 0; i < vec_len (vam->graph_nodes); i++) + for (i = 0; i < vec_len (vam->graph_nodes[0]); i++) { - node = vam->graph_nodes[i]; + node = vam->graph_nodes[0][i]; print (vam->ofp, "[%d] %s", i, node->name); for (j = 0; j < vec_len (node->next_nodes); j++) { if (node->next_nodes[j] != ~0) { - next_node = vam->graph_nodes[node->next_nodes[j]]; + next_node = vam->graph_nodes[0][node->next_nodes[j]]; print (vam->ofp, " [%d] %s", j, next_node->name); } } @@ -23492,13 +23493,13 @@ search_node_table (vat_main_t * vam) print (vam->ofp, "%s not found...", node_to_find); goto out; } - node = vam->graph_nodes[p[0]]; + node = vam->graph_nodes[0][p[0]]; print (vam->ofp, "[%d] %s", p[0], node->name); for (j = 0; j < vec_len (node->next_nodes); j++) { if (node->next_nodes[j] != ~0) { - next_node = vam->graph_nodes[node->next_nodes[j]]; + next_node = vam->graph_nodes[0][node->next_nodes[j]]; print (vam->ofp, " [%d] %s", j, next_node->name); } } diff --git a/src/vat/vat.h b/src/vat/vat.h index 19796b92ef3..c9384a1ce57 100644 --- a/src/vat/vat.h +++ b/src/vat/vat.h @@ -129,7 +129,7 @@ typedef struct /* Graph node table */ uword *graph_node_index_by_name; - vlib_node_t **graph_nodes; + vlib_node_t ***graph_nodes; /* ip tables */ ip_details_t *ip_details_by_sw_if_index[2]; diff --git a/src/vlib/cli.c b/src/vlib/cli.c index f684289ba75..ca8d2abc999 100644 --- a/src/vlib/cli.c +++ b/src/vlib/cli.c @@ -811,7 +811,7 @@ enable_disable_memory_trace (vlib_main_t * vm, while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (!unformat (line_input, "%U", unformat_vlib_enable_disable, &enable)) + if (unformat (line_input, "%U", unformat_vlib_enable_disable, &enable)) ; else if (unformat (line_input, "api-segment")) api_segment = 1; diff --git a/src/vlib/node.c b/src/vlib/node.c index cc1732bb90d..805c69e4f8b 100644 --- a/src/vlib/node.c +++ b/src/vlib/node.c @@ -563,20 +563,20 @@ vlib_register_all_static_nodes (vlib_main_t * vm) } } -vlib_node_t *** -vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats) +void +vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats, + int barrier_sync, vlib_node_t **** node_dupsp, + vlib_main_t *** stat_vmsp) { vlib_node_main_t *nm = &vm->node_main; vlib_node_t *n; - static vlib_node_t ***node_dups; + vlib_node_t ***node_dups = *node_dupsp; vlib_node_t **nodes; - static vlib_main_t **stat_vms; + vlib_main_t **stat_vms = *stat_vmsp; vlib_main_t *stat_vm; uword i, j; u32 threads_to_serialize; - vec_reset_length (node_dups); - if (vec_len (stat_vms) == 0) { for (i = 0; i < vec_len (vlib_mains); i++) @@ -589,11 +589,14 @@ vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats) threads_to_serialize = clib_min (max_threads, vec_len (stat_vms)); + vec_validate (node_dups, threads_to_serialize - 1); + /* * Barrier sync across stats scraping. * Otherwise, the counts will be grossly inaccurate. */ - vlib_worker_thread_barrier_sync (vm); + if (barrier_sync) + vlib_worker_thread_barrier_sync (vm); for (j = 0; j < threads_to_serialize; j++) { @@ -609,12 +612,17 @@ vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats) } } - nodes = vec_dup (nm->nodes); - vec_add1 (node_dups, nodes); + nodes = node_dups[j]; + vec_validate (nodes, vec_len (nm->nodes) - 1); + clib_memcpy (nodes, nm->nodes, vec_len (nm->nodes) * sizeof (nodes[0])); + node_dups[j] = nodes; } - vlib_worker_thread_barrier_release (vm); - return node_dups; + if (barrier_sync) + vlib_worker_thread_barrier_release (vm); + + *node_dupsp = node_dups; + *stat_vmsp = stat_vms; } clib_error_t * diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h index 547f09b7355..bb302f7abd9 100644 --- a/src/vlib/node_funcs.h +++ b/src/vlib/node_funcs.h @@ -1127,8 +1127,10 @@ vlib_node_add_named_next (vlib_main_t * vm, uword node, char *name) /** * Get list of nodes */ -vlib_node_t ***vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, - int include_stats); +void +vlib_node_get_nodes (vlib_main_t * vm, u32 max_threads, int include_stats, + int barrier_sync, vlib_node_t **** node_dupsp, + vlib_main_t *** stat_vmsp); /* Query node given name. */ vlib_node_t *vlib_get_node_by_name (vlib_main_t * vm, u8 * name); diff --git a/src/vlib/threads.c b/src/vlib/threads.c index bbe94c7f272..487c501db5f 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -1492,6 +1492,18 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm) } +void vlib_stat_segment_lock (void) __attribute__ ((weak)); +void +vlib_stat_segment_lock (void) +{ +} + +void vlib_stat_segment_unlock (void) __attribute__ ((weak)); +void +vlib_stat_segment_unlock (void) +{ +} + void vlib_worker_thread_barrier_release (vlib_main_t * vm) { @@ -1521,6 +1533,13 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) /* Update (all) node runtimes before releasing the barrier, if needed */ if (vm->need_vlib_worker_thread_node_runtime_update) { + /* + * Lock stat segment here, so we's safe when + * rebuilding the stat segment node clones from the + * stat thread... + */ + vlib_stat_segment_lock (); + /* Do stats elements on main thread */ worker_thread_node_runtime_update_internal (); vm->need_vlib_worker_thread_node_runtime_update = 0; @@ -1562,6 +1581,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) os_panic (); } } + vlib_stat_segment_unlock (); } t_closed_total = now - vm->barrier_epoch; diff --git a/src/vlibapi/api.h b/src/vlibapi/api.h index 48c3813452e..7238a31f2f3 100644 --- a/src/vlibapi/api.h +++ b/src/vlibapi/api.h @@ -117,7 +117,7 @@ void vl_msg_api_add_version (api_main_t * am, const char *string, /* node_serialize.c prototypes */ u8 *vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector, int include_nexts, int include_stats); -vlib_node_t **vlib_node_unserialize (u8 * vector); +vlib_node_t ***vlib_node_unserialize (u8 * vector); u32 vl_msg_api_get_msg_length (void *msg_arg); diff --git a/src/vlibapi/node_serialize.c b/src/vlibapi/node_serialize.c index 575de11b8cc..b50d79e2922 100644 --- a/src/vlibapi/node_serialize.c +++ b/src/vlibapi/node_serialize.c @@ -124,6 +124,7 @@ vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector, serialize_likely_small_unsigned_integer (sm, (u64) state_code); serialize_likely_small_unsigned_integer (sm, n->type); + serialize_likely_small_unsigned_integer (sm, n->flags); if (include_nexts) { @@ -152,7 +153,6 @@ vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector, else /* no stats */ serialize_likely_small_unsigned_integer (sm, 0); } - vec_free (nodes); } return (serialize_close_vector (sm)); } @@ -197,6 +197,7 @@ vlib_node_unserialize (u8 * vector) node->state_string = (u8 *) state_strings[state_code]; node->type = unserialize_likely_small_unsigned_integer (sm); + node->flags = unserialize_likely_small_unsigned_integer (sm); nnexts = unserialize_likely_small_unsigned_integer (sm); if (nnexts > 0) vec_validate (node->next_nodes, nnexts - 1); diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 8bb11c96066..8e24493c0ce 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -367,7 +367,8 @@ vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp) vlib_main_t *vm = vlib_get_main (); void *oldheap; vl_api_get_node_graph_reply_t *rmp; - vlib_node_t ***node_dups; + static vlib_node_t ***node_dups; + static vlib_main_t **stat_vms; pthread_mutex_lock (&am->vlib_rp->mutex); oldheap = svm_push_data_heap (am->vlib_rp); @@ -378,9 +379,10 @@ vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp) vec_validate (vector, 16384); vec_reset_length (vector); - /* $$$$ FIXME */ - node_dups = vlib_node_get_nodes (vm, (u32) ~ 0 /* all threads */ , - 1 /* include stats */ ); + vlib_node_get_nodes (vm, 0 /* main threads */ , + 0 /* include stats */ , + 1 /* barrier sync */ , + &node_dups, &stat_vms); vector = vlib_node_serialize (vm, node_dups, vector, 1 /* include nexts */ , 1 /* include stats */ ); diff --git a/src/vpp/app/stat_client.c b/src/vpp/app/stat_client.c index 610a6a5b98d..96c1bda2c8d 100644 --- a/src/vpp/app/stat_client.c +++ b/src/vpp/app/stat_client.c @@ -144,12 +144,17 @@ connect_to_vpp (stat_client_main_t * sm) #define foreach_cached_pointer \ _(vector_rate, SCALAR_POINTER, &stat_client_main.vector_rate_ptr) \ _(input_rate, SCALAR_POINTER, &stat_client_main.input_rate_ptr) \ +_(last_update, SCALAR_POINTER, &stat_client_main.last_runtime_ptr) \ +_(last_stats_clear, SCALAR_POINTER, \ + &stat_client_main.last_runtime_stats_clear_ptr) \ _(rx, COUNTER_VECTOR, &stat_client_main.intfc_rx_counters) \ _(tx, COUNTER_VECTOR, &stat_client_main.intfc_tx_counters) \ _(/err/0/counter_vector, VECTOR_POINTER, \ &stat_client_main.thread_0_error_counts) \ _(/err/IP4 source address matches local interface, ERROR_INDEX, \ - &stat_client_main.source_address_match_error_index) + &stat_client_main.source_address_match_error_index) \ +_(serialized_nodes, SERIALIZED_NODES, \ + &stat_client_main.serialized_nodes) typedef struct { @@ -213,9 +218,12 @@ stat_poll_loop (stat_client_main_t * sm) ssvm_private_t *ssvmp = &sm->stat_segment; ssvm_shared_header_t *shared_header; vlib_counter_t *thread0_rx_counters = 0, *thread0_tx_counters = 0; + vlib_node_t ***nodes_by_thread; + vlib_node_t **nodes; + vlib_node_t *n; f64 vector_rate, input_rate; u32 len; - int i; + int i, j; u32 source_address_match_errors; /* Wait until the stats segment is mapped */ @@ -290,6 +298,106 @@ stat_poll_loop (stat_client_main_t * sm) fformat (stdout, "%lld source address match errors\n", source_address_match_errors); + + if (sm->serialized_nodes) + { + nodes_by_thread = vlib_node_unserialize (sm->serialized_nodes); + + /* Across all threads... */ + for (i = 0; i < vec_len (nodes_by_thread); i++) + { + u64 n_input, n_output, n_drop, n_punt; + u64 n_internal_vectors, n_internal_calls; + u64 n_clocks, l, v, c; + f64 dt; + + nodes = nodes_by_thread[i]; + + fformat (stdout, "Thread %d -------------------------\n", i); + + n_input = n_output = n_drop = n_punt = n_clocks = 0; + n_internal_vectors = n_internal_calls = 0; + + /* Across all nodes */ + for (j = 0; j < vec_len (nodes); j++) + { + n = nodes[j]; + + /* Exactly stolen from node_cli.c... */ + l = n->stats_total.clocks - n->stats_last_clear.clocks; + n_clocks += l; + + v = n->stats_total.vectors - n->stats_last_clear.vectors; + c = n->stats_total.calls - n->stats_last_clear.calls; + + switch (n->type) + { + default: + continue; + + case VLIB_NODE_TYPE_INTERNAL: + n_output += + (n->flags & VLIB_NODE_FLAG_IS_OUTPUT) ? v : 0; + n_drop += (n->flags & VLIB_NODE_FLAG_IS_DROP) ? v : 0; + n_punt += (n->flags & VLIB_NODE_FLAG_IS_PUNT) ? v : 0; + if (!(n->flags & VLIB_NODE_FLAG_IS_OUTPUT)) + { + n_internal_vectors += v; + n_internal_calls += c; + } + if (n->flags & VLIB_NODE_FLAG_IS_HANDOFF) + n_input += v; + break; + + case VLIB_NODE_TYPE_INPUT: + n_input += v; + break; + } + + if (n->stats_total.calls) + { + fformat (stdout, + "%s (%s): clocks %lld calls %lld vectors %lld ", + n->name, + n->state_string, + n->stats_total.clocks, + n->stats_total.calls, n->stats_total.vectors); + if (n->stats_total.vectors) + fformat (stdout, "clocks/pkt %.2f\n", + (f64) n->stats_total.clocks / + (f64) n->stats_total.vectors); + else + fformat (stdout, "\n"); + } + vec_free (n->name); + vec_free (n->next_nodes); + vec_free (n); + } + + fformat (stdout, "average vectors/node %.2f\n", + (n_internal_calls > 0 + ? (f64) n_internal_vectors / (f64) n_internal_calls + : 0)); + + + dt = *sm->last_runtime_ptr - *sm->last_runtime_stats_clear_ptr; + + fformat (stdout, + " vectors rates in %.4e, out %.4e, drop %.4e, " + "punt %.4e\n", + (f64) n_input / dt, + (f64) n_output / dt, (f64) n_drop / dt, + (f64) n_punt / dt); + + vec_free (nodes); + } + vec_free (nodes_by_thread); + } + else + { + fformat (stdout, "serialized nodes NULL?\n"); + } + } } diff --git a/src/vpp/app/stat_client.h b/src/vpp/app/stat_client.h index 9cec1ee46f5..87e5409ed6f 100644 --- a/src/vpp/app/stat_client.h +++ b/src/vpp/app/stat_client.h @@ -31,6 +31,8 @@ typedef struct /* Cached pointers to scalar quantities, these wont change */ f64 *vector_rate_ptr; f64 *input_rate_ptr; + f64 *last_runtime_ptr; + f64 *last_runtime_stats_clear_ptr; volatile int segment_ready; @@ -40,6 +42,7 @@ typedef struct */ vlib_counter_t **intfc_rx_counters; vlib_counter_t **intfc_tx_counters; + u8 *serialized_nodes; u64 *thread_0_error_counts; u64 source_address_match_error_index; 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 +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__ */ /*