vlib: create unix runtime directory
[vpp.git] / src / vpp / stats / stat_segment.c
index 4cd00a2..303d704 100644 (file)
@@ -22,6 +22,7 @@
 #undef HAVE_MEMFD_CREATE
 #include <vppinfra/linux/syscall.h>
 #include <vpp-api/client/stat_client.h>
+#include <vppinfra/mheap.h>
 
 stat_segment_main_t stat_segment_main;
 
@@ -58,18 +59,22 @@ vlib_stats_push_heap (void *old)
   return clib_mem_set_heap (sm->heap);
 }
 
-/* Name to vector index hash */
 static u32
-lookup_or_create_hash_index (void *oldheap, char *name, u32 next_vector_index)
+lookup_or_create_hash_index (u8 * name, u32 next_vector_index)
 {
   stat_segment_main_t *sm = &stat_segment_main;
   u32 index;
   hash_pair_t *hp;
 
+  /* Must be called in the context of the main heap */
+  ASSERT (clib_mem_get_heap () != sm->heap);
+
   hp = hash_get_pair (sm->directory_vector_by_name, name);
   if (!hp)
     {
-      hash_set (sm->directory_vector_by_name, name, next_vector_index);
+      /* we allocate our private copy of 'name' */
+      hash_set (sm->directory_vector_by_name, format (0, "%s%c", name, 0),
+               next_vector_index);
       index = next_vector_index;
     }
   else
@@ -106,7 +111,7 @@ vlib_stats_pop_heap (void *cm_arg, void *oldheap, u32 cindex,
     cm->stat_segment_name ? cm->stat_segment_name : cm->name;
   u32 next_vector_index = vec_len (sm->directory_vector);
   clib_mem_set_heap (oldheap); /* Exit stats segment */
-  u32 vector_index = lookup_or_create_hash_index (oldheap, stat_segment_name,
+  u32 vector_index = lookup_or_create_hash_index ((u8 *) stat_segment_name,
                                                  next_vector_index);
   /* Back to stats segment */
   clib_mem_set_heap (sm->heap);        /* Re-enter stat segment */
@@ -153,27 +158,38 @@ vlib_stats_pop_heap (void *cm_arg, void *oldheap, u32 cindex,
 }
 
 void
-vlib_stats_register_error_index (u8 * name, u64 * em_vec, u64 index)
+vlib_stats_register_error_index (void *oldheap, u8 * name, u64 * em_vec,
+                                u64 index)
 {
   stat_segment_main_t *sm = &stat_segment_main;
   stat_segment_shared_header_t *shared_header = sm->shared_header;
   stat_segment_directory_entry_t e;
-  hash_pair_t *hp;
 
   ASSERT (shared_header);
 
   vlib_stat_segment_lock ();
+  u32 next_vector_index = vec_len (sm->directory_vector);
+  clib_mem_set_heap (oldheap); /* Exit stats segment */
 
-  memcpy (e.name, name, vec_len (name));
-  e.name[vec_len (name)] = '\0';
-  e.type = STAT_DIR_TYPE_ERROR_INDEX;
-  e.offset = index;
-  e.offset_vector = 0;
-  vec_add1 (sm->directory_vector, e);
+  u32 vector_index = lookup_or_create_hash_index (name,
+                                                 next_vector_index);
 
-  /* Warn clients to refresh any pointers they might be holding */
-  shared_header->directory_offset =
-    stat_segment_offset (shared_header, sm->directory_vector);
+  /* Back to stats segment */
+  clib_mem_set_heap (sm->heap);        /* Re-enter stat segment */
+
+  if (next_vector_index == vector_index)
+    {
+      memcpy (e.name, name, vec_len (name));
+      e.name[vec_len (name)] = '\0';
+      e.type = STAT_DIR_TYPE_ERROR_INDEX;
+      e.offset = index;
+      e.offset_vector = 0;
+      vec_add1 (sm->directory_vector, e);
+
+      /* Warn clients to refresh any pointers they might be holding */
+      shared_header->directory_offset =
+       stat_segment_offset (shared_header, sm->directory_vector);
+    }
 
   vlib_stat_segment_unlock ();
 }
@@ -232,7 +248,6 @@ vlib_map_stat_segment_init (void)
 {
   stat_segment_main_t *sm = &stat_segment_main;
   stat_segment_shared_header_t *shared_header;
-  stat_segment_directory_entry_t *ep;
   void *oldheap;
   ssize_t memory_size;
   int mfd;
@@ -274,6 +289,9 @@ vlib_map_stat_segment_init (void)
 
   sm->directory_vector_by_name = hash_create_string (0, sizeof (uword));
   sm->shared_header = shared_header = memaddr;
+
+  shared_header->version = STAT_SEGMENT_VERSION;
+
   sm->stat_segment_lockp = clib_mem_alloc (sizeof (clib_spinlock_t));
   clib_spinlock_init (sm->stat_segment_lockp);
 
@@ -285,7 +303,7 @@ vlib_map_stat_segment_init (void)
   shared_header->epoch = 1;
 
   /* Scalar stats and node counters */
-  vec_validate (sm->directory_vector, STAT_COUNTERS);
+  vec_validate (sm->directory_vector, STAT_COUNTERS - 1);
 #define _(E,t,n,p)                                                     \
   strcpy(sm->directory_vector[STAT_COUNTER_##E].name,  #p "/" #n); \
   sm->directory_vector[STAT_COUNTER_##E].type = STAT_DIR_TYPE_##t;
@@ -297,6 +315,12 @@ vlib_map_stat_segment_init (void)
 
   clib_mem_set_heap (oldheap);
 
+  /* Total shared memory size */
+  clib_mem_usage_t usage;
+  mheap_usage (sm->heap, &usage);
+  sm->directory_vector[STAT_COUNTER_MEM_STATSEG_TOTAL].value =
+    usage.bytes_total;
+
   return 0;
 }
 
@@ -348,13 +372,10 @@ show_stat_segment_command_fn (vlib_main_t * vm,
                              vlib_cli_command_t * cmd)
 {
   stat_segment_main_t *sm = &stat_segment_main;
-  counter_t *counter;
-  hash_pair_t *p;
-  stat_segment_directory_entry_t *show_data, *this;
-  int i, j;
+  stat_segment_directory_entry_t *show_data;
+  int i;
 
   int verbose = 0;
-  u8 *s;
 
   if (unformat (input, "verbose"))
     verbose = 1;
@@ -403,7 +424,6 @@ VLIB_CLI_COMMAND (show_stat_segment_command, static) =
 static inline void
 update_node_counters (stat_segment_main_t * sm)
 {
-  vlib_main_t *vm = vlib_mains[0];
   vlib_main_t **stat_vms = 0;
   vlib_node_t ***node_dups = 0;
   int i, j;
@@ -427,13 +447,13 @@ update_node_counters (stat_segment_main_t * sm)
       vlib_stat_segment_lock ();
 
       stat_validate_counter_vector (&sm->directory_vector
-                                   [STAT_COUNTER_NODE_CLOCKS], l);
+                                   [STAT_COUNTER_NODE_CLOCKS], l - 1);
       stat_validate_counter_vector (&sm->directory_vector
-                                   [STAT_COUNTER_NODE_VECTORS], l);
+                                   [STAT_COUNTER_NODE_VECTORS], l - 1);
       stat_validate_counter_vector (&sm->directory_vector
-                                   [STAT_COUNTER_NODE_CALLS], l);
+                                   [STAT_COUNTER_NODE_CALLS], l - 1);
       stat_validate_counter_vector (&sm->directory_vector
-                                   [STAT_COUNTER_NODE_SUSPENDS], l);
+                                   [STAT_COUNTER_NODE_SUSPENDS], l - 1);
 
       vec_validate (sm->nodes, l - 1);
       stat_segment_directory_entry_t *ep;
@@ -471,7 +491,6 @@ update_node_counters (stat_segment_main_t * sm)
   for (j = 0; j < vec_len (node_dups); j++)
     {
       vlib_node_t **nodes = node_dups[j];
-      u32 l = vec_len (nodes);
 
       for (i = 0; i < vec_len (nodes); i++)
        {
@@ -517,7 +536,7 @@ 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, last_input_packets;
+  u64 input_packets;
   f64 dt, now;
   vlib_main_t *this_vlib_main;
   int i, start;
@@ -585,6 +604,12 @@ do_stat_segment_updates (stat_segment_main_t * sm)
   sm->directory_vector[STAT_COUNTER_LAST_STATS_CLEAR].value =
     vm->node_main.time_last_runtime_stats_clear;
 
+  /* Stats segment memory heap counter */
+  clib_mem_usage_t usage;
+  mheap_usage (sm->heap, &usage);
+  sm->directory_vector[STAT_COUNTER_MEM_STATSEG_USED].value =
+    usage.bytes_used;
+
   if (sm->node_counters_enabled)
     update_node_counters (sm);
 
@@ -627,7 +652,7 @@ stats_socket_accept_ready (clib_file_t * uf)
   return 0;
 }
 
-static void
+static clib_error_t *
 stats_segment_socket_init (void)
 {
   stat_segment_main_t *sm = &stat_segment_main;
@@ -640,10 +665,7 @@ stats_segment_socket_init (void)
     CLIB_SOCKET_F_ALLOW_GROUP_WRITE | CLIB_SOCKET_F_PASSCRED;
 
   if ((error = clib_socket_init (s)))
-    {
-      clib_error_report (error);
-      return;
-    }
+    return error;
 
   clib_file_t template = { 0 };
   template.read_function = stats_socket_accept_ready;
@@ -652,6 +674,8 @@ stats_segment_socket_init (void)
   clib_file_add (&file_main, &template);
 
   sm->socket = s;
+
+  return 0;
 }
 
 static clib_error_t *
@@ -689,10 +713,11 @@ statseg_init (vlib_main_t * vm)
 {
   stat_segment_main_t *sm = &stat_segment_main;
 
-  if (sm->socket_name)
-    stats_segment_socket_init ();
-
-  return 0;
+  /* set default socket file name when statseg config stanza is empty. */
+  if (!vec_len (sm->socket_name))
+    sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
+                             STAT_SEGMENT_SOCKET_FILENAME);
+  return stats_segment_socket_init ();
 }
 
 /* *INDENT-OFF* */
@@ -711,11 +736,17 @@ stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
   stat_segment_shared_header_t *shared_header = sm->shared_header;
   void *oldheap;
   stat_segment_directory_entry_t e;
-  u32 index;
   stat_segment_gauges_pool_t *gauge;
 
   ASSERT (shared_header);
 
+  u32 next_vector_index = vec_len (sm->directory_vector);
+  u32 vector_index = lookup_or_create_hash_index (name,
+                                                 next_vector_index);
+
+  if (vector_index < next_vector_index)        /* Already registered */
+    return clib_error_return (0, "%v is alreadty registered", name);
+
   oldheap = vlib_stats_push_heap (NULL);
   vlib_stat_segment_lock ();
 
@@ -723,7 +754,6 @@ stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
   e.type = STAT_DIR_TYPE_SCALAR_INDEX;
 
   memcpy (e.name, name, vec_len (name));
-  index = vec_len (sm->directory_vector);
   vec_add1 (sm->directory_vector, e);
 
   shared_header->directory_offset =
@@ -736,7 +766,7 @@ stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
   pool_get (sm->gauges, gauge);
   gauge->fn = update_fn;
   gauge->caller_index = caller_index;
-  gauge->directory_index = index;
+  gauge->directory_index = next_vector_index;
 
   return NULL;
 }
@@ -746,23 +776,15 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input)
 {
   stat_segment_main_t *sm = &stat_segment_main;
 
-  /* set default socket file name when statseg config stanza is empty. */
-  sm->socket_name = format (0, "%s", STAT_SEGMENT_SOCKET_FILE);
-  /*
-   * NULL-terminate socket name string
-   * clib_socket_init()->socket_config() use C str*
-   */
-  vec_add1 (sm->socket_name, 0);
-
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "socket-name %s", &sm->socket_name))
        ;
+      /* DEPRECATE: default (does nothing) */
       else if (unformat (input, "default"))
-       sm->socket_name = format (0, "%s", STAT_SEGMENT_SOCKET_FILE);
-      else
-       if (unformat
-           (input, "size %U", unformat_memory_size, &sm->memory_size))
+       ;
+      else if (unformat (input, "size %U",
+                        unformat_memory_size, &sm->memory_size))
        ;
       else if (unformat (input, "per-node-counters on"))
        sm->node_counters_enabled = 1;
@@ -772,6 +794,14 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input)
        return clib_error_return (0, "unknown input `%U'",
                                  format_unformat_error, input);
     }
+
+  /*
+   * NULL-terminate socket name string
+   * clib_socket_init()->socket_config() use C str*
+   */
+  if (vec_len (sm->socket_name))
+    vec_terminate_c_string (sm->socket_name);
+
   return 0;
 }