vlib: improve summary vector-rate statistics
Type: refactor Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I4b77879b0a84fdec3c1518a972cf003d5135222d Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:
committed by
Florin Coras
parent
eacc8c5943
commit
a8df85ce1f
+6
-3
@@ -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 ();
|
||||
|
||||
+32
-58
@@ -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 *))
|
||||
{
|
||||
|
||||
+15
-16
@@ -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;
|
||||
|
||||
+1
-1
@@ -1429,7 +1429,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++;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -151,3 +151,12 @@ cpu {
|
||||
# plugin dpdk_plugin.so { disable }
|
||||
# plugin acl_plugin.so { disable }
|
||||
# }
|
||||
|
||||
## Statistics Segment
|
||||
# statseg {
|
||||
# socket-name <filename>, name of the stats segment socket
|
||||
# defaults to /run/vpp/stats.sock
|
||||
# size <nnn>[KMG], size of the stats segment, defaults to 32mb
|
||||
# per-node-counters on | off, defaults to none
|
||||
# update-interval <f64-seconds>, sets the segment scrape / update interval
|
||||
# }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -703,19 +709,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)
|
||||
{
|
||||
@@ -868,6 +879,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);
|
||||
@@ -883,6 +896,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)
|
||||
{
|
||||
@@ -951,7 +966,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* */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user