From cefa74829acab2426a0d984f754d2efd6d4a65a4 Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Tue, 1 Oct 2019 13:34:23 -0400 Subject: vlib: improve summary vector-rate statistics Type: refactor Signed-off-by: Dave Barach Change-Id: I4b77879b0a84fdec3c1518a972cf003d5135222d Signed-off-by: Ole Troan (cherry picked from commit a8df85ce1fe957efa8301bd5b5ac3c03737d31f1) --- src/vlib/main.c | 9 +++-- src/vlib/main.h | 90 ++++++++++++++++---------------------------- src/vlib/node_cli.c | 31 ++++++++------- src/vlib/threads.c | 2 +- src/vlibmemory/vlib_api.c | 2 +- src/vpp/conf/startup.conf | 9 +++++ src/vpp/stats/stat_segment.c | 62 ++++++++++++++++++------------ src/vpp/stats/stat_segment.h | 3 ++ 8 files changed, 105 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/vlib/main.c b/src/vlib/main.c index f49790d28b5..dc11128476b 100644 --- a/src/vlib/main.c +++ b/src/vlib/main.c @@ -52,8 +52,6 @@ CJ_GLOBAL_LOG_PROTOTYPE; speculative vector enqueues which overflow vector data in next frame. */ #define VLIB_FRAME_SIZE_ALLOC (VLIB_FRAME_SIZE + 4) -u32 wraps; - always_inline u32 vlib_frame_bytes (u32 n_scalar_bytes, u32 n_vector_bytes) { @@ -1376,6 +1374,12 @@ dispatch_pending_node (vlib_main_t * vm, uword pending_frame_index, VLIB_NODE_TYPE_INTERNAL, VLIB_NODE_STATE_POLLING, f, last_time_stamp); + /* Internal node vector-rate accounting, for summary stats */ + vm->internal_node_vectors += f->n_vectors; + vm->internal_node_calls++; + vm->internal_node_last_vectors_per_main_loop = + (f->n_vectors > vm->internal_node_last_vectors_per_main_loop) ? + f->n_vectors : vm->internal_node_last_vectors_per_main_loop; f->frame_flags &= ~(VLIB_FRAME_PENDING | VLIB_FRAME_NO_APPEND); @@ -1915,7 +1919,6 @@ vlib_main_or_worker_loop (vlib_main_t * vm, int is_main) } } vlib_increment_main_loop_counter (vm); - /* Record time stamp in case there are no enabled nodes and above calls do not update time stamp. */ cpu_time_now = clib_cpu_time_now (); diff --git a/src/vlib/main.h b/src/vlib/main.h index 2b50b4e4712..e230ddf8419 100644 --- a/src/vlib/main.h +++ b/src/vlib/main.h @@ -95,11 +95,14 @@ typedef struct vlib_main_t u32 main_loop_vectors_processed; u32 main_loop_nodes_processed; - /* Circular buffer of input node vector counts. - Indexed by low bits of - (main_loop_count >> VLIB_LOG2_INPUT_VECTORS_PER_MAIN_LOOP). */ - u32 vector_counts_per_main_loop[2]; - u32 node_counts_per_main_loop[2]; + /* Internal node vectors, calls */ + u64 internal_node_vectors; + u64 internal_node_calls; + u64 internal_node_vectors_last_clear; + u64 internal_node_calls_last_clear; + + /* Instantaneous vector rate */ + u32 internal_node_last_vectors_per_main_loop; /* Main loop hw / sw performance counters */ void (**vlib_node_runtime_perf_counter_cbs) (struct vlib_main_t *, @@ -323,75 +326,46 @@ vlib_panic (vlib_main_t * vm) vlib_panic_with_error (vm, 0); } -always_inline u32 -vlib_vector_input_stats_index (vlib_main_t * vm, word delta) -{ - u32 i; - i = vm->main_loop_count >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE; - ASSERT (is_pow2 (ARRAY_LEN (vm->vector_counts_per_main_loop))); - return (i + delta) & (ARRAY_LEN (vm->vector_counts_per_main_loop) - 1); -} - -/* Estimate input rate based on previous - 2^VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE - samples. */ -always_inline u32 -vlib_last_vectors_per_main_loop (vlib_main_t * vm) -{ - u32 i = vlib_vector_input_stats_index (vm, -1); - u32 n = vm->vector_counts_per_main_loop[i]; - return n >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE; -} -/* Total ave vector count per iteration of main loop. */ always_inline f64 -vlib_last_vectors_per_main_loop_as_f64 (vlib_main_t * vm) +vlib_internal_node_vector_rate (vlib_main_t * vm) { - u32 i = vlib_vector_input_stats_index (vm, -1); - u32 v = vm->vector_counts_per_main_loop[i]; - return (f64) v / (f64) (1 << VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE); + u64 vectors; + u64 calls; + + calls = vm->internal_node_calls - vm->internal_node_calls_last_clear; + + if (PREDICT_FALSE (calls == 0)) + return 0.0; + + vectors = vm->internal_node_vectors - vm->internal_node_vectors_last_clear; + + return (f64) vectors / (f64) calls; } -/* Total ave vectors/node count per iteration of main loop. */ -always_inline f64 -vlib_last_vector_length_per_node (vlib_main_t * vm) +always_inline void +vlib_clear_internal_node_vector_rate (vlib_main_t * vm) { - u32 i = vlib_vector_input_stats_index (vm, -1); - u32 v = vm->vector_counts_per_main_loop[i]; - u32 n = vm->node_counts_per_main_loop[i]; - return n == 0 ? 0 : (f64) v / (f64) n; + vm->internal_node_calls_last_clear = vm->internal_node_calls; + vm->internal_node_vectors_last_clear = vm->internal_node_vectors; } -extern u32 wraps; - always_inline void vlib_increment_main_loop_counter (vlib_main_t * vm) { - u32 i, c, n, v, is_wrap; - - c = vm->main_loop_count++; - - is_wrap = (c & pow2_mask (VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE)) == 0; - - if (is_wrap) - wraps++; - - i = vlib_vector_input_stats_index (vm, /* delta */ is_wrap); - - v = is_wrap ? 0 : vm->vector_counts_per_main_loop[i]; - n = is_wrap ? 0 : vm->node_counts_per_main_loop[i]; - - v += vm->main_loop_vectors_processed; - n += vm->main_loop_nodes_processed; - vm->main_loop_vectors_processed = 0; - vm->main_loop_nodes_processed = 0; - vm->vector_counts_per_main_loop[i] = v; - vm->node_counts_per_main_loop[i] = n; + vm->main_loop_count++; + vm->internal_node_last_vectors_per_main_loop = 0; if (PREDICT_FALSE (vm->main_loop_exit_now)) clib_longjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_CLI); } +always_inline u32 +vlib_last_vectors_per_main_loop (vlib_main_t * vm) +{ + return vm->internal_node_last_vectors_per_main_loop; +} + always_inline void vlib_set_queue_signal_callback (vlib_main_t * vm, void (*fp) (vlib_main_t *)) { diff --git a/src/vlib/node_cli.c b/src/vlib/node_cli.c index 58b63c366bf..5f0617d7eae 100644 --- a/src/vlib/node_cli.c +++ b/src/vlib/node_cli.c @@ -299,6 +299,13 @@ format_vlib_node_stats (u8 * s, va_list * va) return s; } +f64 vlib_get_stat_segment_update_rate (void) __attribute__ ((weak)); +f64 +vlib_get_stat_segment_update_rate (void) +{ + return 1e70; +} + static clib_error_t * show_node_runtime (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -308,8 +315,7 @@ show_node_runtime (vlib_main_t * vm, f64 time_now; u32 node_index; vlib_node_t ***node_dups = 0; - f64 *vectors_per_main_loop = 0; - f64 *last_vector_length_per_node = 0; + f64 *internal_node_vector_rates = 0; time_now = vlib_time_now (vm); @@ -367,10 +373,8 @@ show_node_runtime (vlib_main_t * vm, nodes = vec_dup (nm->nodes); vec_add1 (node_dups, nodes); - vec_add1 (vectors_per_main_loop, - vlib_last_vectors_per_main_loop_as_f64 (stat_vm)); - vec_add1 (last_vector_length_per_node, - vlib_last_vector_length_per_node (stat_vm)); + vec_add1 (internal_node_vector_rates, + vlib_internal_node_vector_rate (stat_vm)); } vlib_worker_thread_barrier_release (vm); @@ -434,15 +438,11 @@ show_node_runtime (vlib_main_t * vm, dt = time_now - nm->time_last_runtime_stats_clear; vlib_cli_output (vm, - "Time %.1f, average vectors/node %.2f, last %d main loops %.2f per node %.2f" - "\n vector rates in %.4e, out %.4e, drop %.4e, punt %.4e", + "Time %.1f, %f sec internal node vector rate %.2f \n" + " vector rates in %.4e, out %.4e, drop %.4e, punt %.4e", dt, - (n_internal_calls > 0 - ? (f64) n_internal_vectors / (f64) n_internal_calls - : 0), - 1 << VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE, - vectors_per_main_loop[j], - last_vector_length_per_node[j], + vlib_get_stat_segment_update_rate (), + internal_node_vector_rates[j], (f64) n_input / dt, (f64) n_output / dt, (f64) n_drop / dt, (f64) n_punt / dt); @@ -465,8 +465,7 @@ show_node_runtime (vlib_main_t * vm, } vec_free (stat_vms); vec_free (node_dups); - vec_free (vectors_per_main_loop); - vec_free (last_vector_length_per_node); + vec_free (internal_node_vector_rates); } return 0; diff --git a/src/vlib/threads.c b/src/vlib/threads.c index 49b6e811240..d5f247abb95 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -1432,7 +1432,7 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) for (i = 1; i < vec_len (vlib_mains); i++) max_vector_rate = clib_max (max_vector_rate, - vlib_last_vectors_per_main_loop_as_f64 (vlib_mains[i])); + (f64) vlib_last_vectors_per_main_loop (vlib_mains[i])); vlib_worker_threads[0].barrier_sync_count++; diff --git a/src/vlibmemory/vlib_api.c b/src/vlibmemory/vlib_api.c index e1a6bd18d55..afc2e401cd9 100644 --- a/src/vlibmemory/vlib_api.c +++ b/src/vlibmemory/vlib_api.c @@ -319,7 +319,7 @@ vl_api_clnt_process (vlib_main_t * vm, vlib_node_runtime_t * node, * of the application to process the request, the client will * sit and wait for Godot... */ - vector_rate = vlib_last_vector_length_per_node (vm); + vector_rate = (f64) vlib_last_vectors_per_main_loop (vm); start_time = vlib_time_now (vm); while (1) { diff --git a/src/vpp/conf/startup.conf b/src/vpp/conf/startup.conf index 71058e21cf5..b61e4514e13 100644 --- a/src/vpp/conf/startup.conf +++ b/src/vpp/conf/startup.conf @@ -151,3 +151,12 @@ cpu { # plugin dpdk_plugin.so { disable } # plugin acl_plugin.so { disable } # } + +## Statistics Segment +# statseg { + # socket-name , name of the stats segment socket + # defaults to /run/vpp/stats.sock + # size [KMG], size of the stats segment, defaults to 32mb + # per-node-counters on | off, defaults to none + # update-interval , sets the segment scrape / update interval +# } diff --git a/src/vpp/stats/stat_segment.c b/src/vpp/stats/stat_segment.c index 78b34ed8265..f48b2d05062 100644 --- a/src/vpp/stats/stat_segment.c +++ b/src/vpp/stats/stat_segment.c @@ -216,6 +216,21 @@ stat_validate_counter_vector (stat_segment_directory_entry_t * ep, u32 max) ep->offset_vector = stat_segment_offset (shared_header, offset_vector); } +always_inline void +stat_set_simple_counter (stat_segment_directory_entry_t * ep, + u32 thread_index, u32 index, u64 value) +{ + stat_segment_main_t *sm = &stat_segment_main; + stat_segment_shared_header_t *shared_header = sm->shared_header; + + ASSERT (shared_header); + counter_t *offset_vector = + stat_segment_pointer (sm->shared_header, ep->offset_vector); + counter_t *cb = + stat_segment_pointer (sm->shared_header, offset_vector[thread_index]); + cb[index] = value; +} + void vlib_stats_pop_heap2 (u64 * error_vector, u32 thread_index, void *oldheap, int lock) @@ -540,14 +555,12 @@ update_node_counters (stat_segment_main_t * sm) 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; f64 dt, now; vlib_main_t *this_vlib_main; - int i, start; - counter_t **counters; + int i; static int num_worker_threads_set; /* @@ -558,14 +571,10 @@ do_stat_segment_updates (stat_segment_main_t * sm) if (PREDICT_FALSE (num_worker_threads_set == 0)) { void *oldheap = clib_mem_set_heap (sm->heap); - int workers = clib_max (1, vec_len (vlib_mains) - 1); vlib_stat_segment_lock (); - sm->directory_vector[STAT_COUNTER_NUM_WORKER_THREADS].value = workers; - stat_validate_counter_vector (&sm->directory_vector - [STAT_COUNTER_VECTOR_RATE_PER_WORKER], - workers); + [STAT_COUNTER_VECTOR_RATE_PER_WORKER], 0); num_worker_threads_set = 1; vlib_stat_segment_unlock (); clib_mem_set_heap (oldheap); @@ -577,29 +586,26 @@ do_stat_segment_updates (stat_segment_main_t * sm) */ 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++) + for (i = 0; i < vec_len (vlib_mains); i++) { f64 this_vector_rate; this_vlib_main = vlib_mains[i]; - this_vector_rate = vlib_last_vector_length_per_node (this_vlib_main); + this_vector_rate = vlib_internal_node_vector_rate (this_vlib_main); + vlib_clear_internal_node_vector_rate (this_vlib_main); + vector_rate += this_vector_rate; /* Set the per-worker rate */ - counters[0][i - start] = this_vector_rate; + stat_set_simple_counter (&sm->directory_vector + [STAT_COUNTER_VECTOR_RATE_PER_WORKER], i, 0, + this_vector_rate); } /* And set the system average rate */ - vector_rate /= (f64) (i - start); + vector_rate /= (f64) (i > 1 ? i - 1 : 1); sm->directory_vector[STAT_COUNTER_VECTOR_RATE].value = vector_rate; @@ -704,19 +710,23 @@ stats_segment_socket_exit (vlib_main_t * vm) VLIB_MAIN_LOOP_EXIT_FUNCTION (stats_segment_socket_exit); +/* Overrides weak reference in vlib:node_cli.c */ +f64 +vlib_get_stat_segment_update_rate (void) +{ + return stat_segment_main.update_interval; +} + static uword stat_segment_collector_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { stat_segment_main_t *sm = &stat_segment_main; - /* Wait for Godot... */ - f64 sleep_duration = 10; - while (1) { do_stat_segment_updates (sm); - vlib_process_suspend (vm, sleep_duration); + vlib_process_suspend (vm, sm->update_interval); } return 0; /* or not */ } @@ -853,6 +863,7 @@ static clib_error_t * statseg_config (vlib_main_t * vm, unformat_input_t * input) { stat_segment_main_t *sm = &stat_segment_main; + sm->update_interval = 10.0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -871,6 +882,8 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input) sm->node_counters_enabled = 1; else if (unformat (input, "per-node-counters off")) sm->node_counters_enabled = 0; + else if (unformat (input, "update-interval %f", &sm->update_interval)) + ; else return clib_error_return (0, "unknown input `%U'", format_unformat_error, input); @@ -889,6 +902,8 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input) return 0; } +VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg"); + static clib_error_t * statseg_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) { @@ -957,7 +972,6 @@ statseg_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) return 0; } -VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg"); VNET_SW_INTERFACE_ADD_DEL_FUNCTION (statseg_sw_interface_add_del); /* *INDENT-OFF* */ diff --git a/src/vpp/stats/stat_segment.h b/src/vpp/stats/stat_segment.h index eae6902dc75..83d233479a8 100644 --- a/src/vpp/stats/stat_segment.h +++ b/src/vpp/stats/stat_segment.h @@ -90,6 +90,9 @@ typedef struct u8 **interfaces; u8 **nodes; + /* Update interval */ + f64 update_interval; + clib_spinlock_t *stat_segment_lockp; clib_socket_t *socket; u8 *socket_name; -- cgit 1.2.3-korg