vlib: improve summary vector-rate statistics 53/22453/4
authorDave Barach <dave@barachs.net>
Tue, 1 Oct 2019 17:34:23 +0000 (13:34 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Wed, 2 Oct 2019 20:44:02 +0000 (20:44 +0000)
Type: refactor

Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I4b77879b0a84fdec3c1518a972cf003d5135222d
Signed-off-by: Ole Troan <ot@cisco.com>
src/vlib/main.c
src/vlib/main.h
src/vlib/node_cli.c
src/vlib/threads.c
src/vlibmemory/vlib_api.c
src/vpp/conf/startup.conf
src/vpp/stats/stat_segment.c
src/vpp/stats/stat_segment.h

index f49790d..dc11128 100644 (file)
@@ -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 ();
index 2b50b4e..e230ddf 100644 (file)
@@ -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 *))
 {
index 58b63c3..5f0617d 100644 (file)
@@ -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;
index 7454d5a..07e1d79 100644 (file)
@@ -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++;
 
index e1a6bd1..afc2e40 100644 (file)
@@ -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)
        {
index 71058e2..b61e451 100644 (file)
@@ -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
+# }
index b978d37..f4758a7 100644 (file)
@@ -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* */
index eae6902..83d2334 100644 (file)
@@ -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;