STATS: stat_client updates.
[vpp.git] / src / vpp / stats / stat_segment.c
index 795e347..8459138 100644 (file)
  */
 #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)
 {
@@ -29,7 +43,7 @@ vlib_stats_push_heap (void)
 }
 
 void
-vlib_stats_pop_heap (void *cm_arg, void *oldheap)
+vlib_stats_pop_heap (void *cm_arg, void *oldheap, stat_directory_type_t type)
 {
   vlib_simple_counter_main_t *cm = (vlib_simple_counter_main_t *) cm_arg;
   stats_main_t *sm = &stats_main;
@@ -66,7 +80,7 @@ vlib_stats_pop_heap (void *cm_arg, void *oldheap)
        }
       name_copy = format (0, "%s%c", stat_segment_name, 0);
       ep = clib_mem_alloc (sizeof (*ep));
-      ep->type = STAT_DIR_TYPE_COUNTER_VECTOR;
+      ep->type = type;
       ep->value = cm->counters;
       hash_set_mem (sm->counter_vector_by_name, name_copy, ep);
 
@@ -172,8 +186,8 @@ vlib_stats_pop_heap2 (u64 * counter_vector, u32 thread_index, void *oldheap)
   ssvm_pop_heap (oldheap);
 }
 
-static clib_error_t *
-map_stat_segment_init (vlib_main_t * vm)
+clib_error_t *
+vlib_map_stat_segment_init (void)
 {
   stats_main_t *sm = &stats_main;
   ssvm_private_t *ssvmp = &sm->stat_segment;
@@ -184,8 +198,13 @@ map_stat_segment_init (vlib_main_t * vm)
   void *oldheap;
   u32 *lock;
   int rv;
+  u64 memory_size;
+
+  memory_size = sm->memory_size;
+  if (memory_size == 0)
+    memory_size = STAT_SEGMENT_DEFAULT_SIZE;
 
-  ssvmp->ssvm_size = 32 << 20; /*$$$$$ CONFIG PARAM */
+  ssvmp->ssvm_size = memory_size;
   ssvmp->i_am_master = 1;
   ssvmp->my_pid = getpid ();
   ssvmp->name = format (0, "/stats%c", 0);
@@ -215,21 +234,46 @@ 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);
+  sm->heartbeat_ptr = (scalar_data + 4);
 
-  name = format (0, "vector_rate%c", 0);
+  name = format (0, "/sys/vector_rate%c", 0);
   ep = clib_mem_alloc (sizeof (*ep));
   ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
   ep->value = sm->vector_rate_ptr;
 
   hash_set_mem (sm->counter_vector_by_name, name, ep);
 
-  name = format (0, "input_rate%c", 0);
+  name = format (0, "/sys/input_rate%c", 0);
   ep = clib_mem_alloc (sizeof (*ep));
   ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
   ep->value = sm->input_rate_ptr;
 
   hash_set_mem (sm->counter_vector_by_name, name, ep);
 
+  name = format (0, "/sys/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, "/sys/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);
+
+  name = format (0, "/sys/heartbeat%c", 0);
+  ep = clib_mem_alloc (sizeof (*ep));
+  ep->type = STAT_DIR_TYPE_SCALAR_POINTER;
+  ep->value = sm->heartbeat_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;
 
@@ -238,8 +282,6 @@ map_stat_segment_init (vlib_main_t * vm)
   return 0;
 }
 
-VLIB_INIT_FUNCTION (map_stat_segment_init);
-
 typedef struct
 {
   u8 *name;
@@ -275,10 +317,15 @@ format_stat_dir_entry (u8 * s, va_list * args)
       type_name = "VectorPtr";
       break;
 
-    case STAT_DIR_TYPE_COUNTER_VECTOR:
+    case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
+    case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
       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 +339,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,59 +407,148 @@ 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)
+{
+  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;
+
+  ASSERT (ssvmp && ssvmp->sh);
+
+  vec_reset_length (sm->serialized_nodes);
+
+  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
+    {
+      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);
+    }
+
+  clib_spinlock_unlock (sm->stat_segment_lockp);
+  ssvm_pop_heap (oldheap);
+}
+
+/*
+ * 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)
 {
+  vlib_main_t *vm = vlib_mains[0];
   f64 vector_rate;
   u64 input_packets, last_input_packets;
-  f64 last_runtime, dt, now;
+  f64 dt, now;
   vlib_main_t *this_vlib_main;
-  stats_main_t *sm = &stats_main;
+  int i, start;
 
-  last_runtime = 0.0;
-  last_input_packets = 0;
+  /*
+   * Compute the average vector rate across all workers
+   */
+  vector_rate = 0.0;
 
-  last_runtime = 0.0;
-  last_input_packets = 0;
+  start = vec_len (vlib_mains) > 1 ? 1 : 0;
 
-  while (1)
+  for (i = start; i < vec_len (vlib_mains); i++)
     {
-      vlib_process_suspend (vm, 5.0);
-
-      /*
-       * Compute the average vector rate across all workers
-       */
-      vector_rate = 0.0;
-
-      /* *INDENT-OFF* */
-      foreach_vlib_main
-      ({
-        vector_rate += vlib_last_vector_length_per_node (vm);
-      });
-      /* *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;
+      this_vlib_main = vlib_mains[i];
+      vector_rate += vlib_last_vector_length_per_node (this_vlib_main);
     }
-
-  return 0;                    /* not so much */
+  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;
+
+  if (sm->serialize_nodes)
+    update_serialized_nodes (sm);
+
+  /* Heartbeat, so clients detect we're still here */
+  (*sm->heartbeat_ptr)++;
 }
 
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (stat_segment_node,static) =
+static clib_error_t *
+statseg_config (vlib_main_t * vm, unformat_input_t * input)
 {
-  .function = stat_segment_process,
-  .type = VLIB_NODE_TYPE_PROCESS,
-  .name = "stat-segment-process",
-};
-/* *INDENT-ON* */
+  stats_main_t *sm = &stats_main;
+  uword ms;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "size %U", unformat_memory_size, &sm->memory_size))
+       ;
+      else if (unformat (input, "serialize-nodes on"))
+       sm->serialize_nodes = 1;
+      else if (unformat (input, "serialize-nodes off"))
+       sm->serialize_nodes = 0;
+      else
+       return clib_error_return (0, "unknown input `%U'",
+                                 format_unformat_error, input);
+    }
+
+  return 0;
+}
 
+VLIB_EARLY_CONFIG_FUNCTION (statseg_config, "statseg");
 
 /*
  * fd.io coding-style-patch-verification: ON