stats: fix per-worker stat vector length
[vpp.git] / src / vpp / stats / stat_segment.c
index 1328ea8..b978d37 100644 (file)
@@ -358,6 +358,10 @@ format_stat_dir_entry (u8 * s, va_list * args)
       type_name = "ErrIndex";
       break;
 
+    case STAT_DIR_TYPE_NAME_VECTOR:
+      type_name = "NameVector";
+      break;
+
     default:
       type_name = "illegal!";
       break;
@@ -527,7 +531,10 @@ update_node_counters (stat_segment_main_t * sm)
          c[n->index] =
            n->stats_total.suspends - n->stats_last_clear.suspends;
        }
+      vec_free (node_dups[j]);
     }
+  vec_free (node_dups);
+  vec_free (stat_vms);
 }
 
 static void
@@ -550,13 +557,18 @@ do_stat_segment_updates (stat_segment_main_t * sm)
    */
   if (PREDICT_FALSE (num_worker_threads_set == 0))
     {
-      sm->directory_vector[STAT_COUNTER_NUM_WORKER_THREADS].value =
-       vec_len (vlib_mains) > 1 ? vec_len (vlib_mains) - 1 : 1;
+      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],
-                                   vec_len (vlib_mains));
+                                   workers);
       num_worker_threads_set = 1;
+      vlib_stat_segment_unlock ();
+      clib_mem_set_heap (oldheap);
     }
 
   /*
@@ -583,7 +595,7 @@ do_stat_segment_updates (stat_segment_main_t * sm)
       vector_rate += this_vector_rate;
 
       /* Set the per-worker rate */
-      counters[i - start][0] = this_vector_rate;
+      counters[0][i - start] = this_vector_rate;
     }
 
   /* And set the system average rate */
@@ -652,7 +664,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;
@@ -665,10 +677,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;
@@ -677,6 +686,8 @@ stats_segment_socket_init (void)
   clib_file_add (&file_main, &template);
 
   sm->socket = s;
+
+  return 0;
 }
 
 static clib_error_t *
@@ -714,10 +725,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%c", vlib_unix_get_runtime_dir (),
+                             STAT_SEGMENT_SOCKET_FILENAME, 0);
+  return stats_segment_socket_init ();
 }
 
 /* *INDENT-OFF* */
@@ -727,7 +739,6 @@ VLIB_INIT_FUNCTION (statseg_init) =
 };
 /* *INDENT-ON* */
 
-
 clib_error_t *
 stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
                             u32 caller_index)
@@ -771,6 +782,73 @@ stat_segment_register_gauge (u8 * name, stat_segment_update_fn update_fn,
   return NULL;
 }
 
+clib_error_t *
+stat_segment_register_state_counter (u8 * name, u32 * index)
+{
+  stat_segment_main_t *sm = &stat_segment_main;
+  stat_segment_shared_header_t *shared_header = sm->shared_header;
+  void *oldheap;
+  stat_segment_directory_entry_t e;
+
+  ASSERT (shared_header);
+  ASSERT (vlib_get_thread_index () == 0);
+
+  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 already registered", name);
+
+  oldheap = vlib_stats_push_heap (NULL);
+  vlib_stat_segment_lock ();
+
+  memset (&e, 0, sizeof (e));
+  e.type = STAT_DIR_TYPE_SCALAR_INDEX;
+
+  memcpy (e.name, name, vec_len (name));
+  vec_add1 (sm->directory_vector, e);
+
+  shared_header->directory_offset =
+    stat_segment_offset (shared_header, sm->directory_vector);
+
+  vlib_stat_segment_unlock ();
+  clib_mem_set_heap (oldheap);
+
+  *index = next_vector_index;
+  return 0;
+}
+
+clib_error_t *
+stat_segment_deregister_state_counter (u32 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;
+
+  ASSERT (shared_header);
+
+  if (index > vec_len (sm->directory_vector))
+    return clib_error_return (0, "%u index does not exist", index);
+
+  e = &sm->directory_vector[index];
+  if (e->type != STAT_DIR_TYPE_SCALAR_INDEX)
+    return clib_error_return (0, "%u index cannot be deleted", index);
+
+  hash_unset (sm->directory_vector_by_name, &e->name);
+  vec_del1 (sm->directory_vector, index);
+  return 0;
+}
+
+void
+stat_segment_set_state_counter (u32 index, u64 value)
+{
+  stat_segment_main_t *sm = &stat_segment_main;
+
+  ASSERT (index < vec_len (sm->directory_vector));
+  sm->directory_vector[index].index = value;
+}
+
 static clib_error_t *
 statseg_config (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -780,12 +858,9 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input)
     {
       if (unformat (input, "socket-name %s", &sm->socket_name))
        ;
+      /* DEPRECATE: default (does nothing) */
       else if (unformat (input, "default"))
-       {
-         vec_reset_length (sm->socket_name);
-         sm->socket_name = format (sm->socket_name, "%s",
-                                   STAT_SEGMENT_SOCKET_FILE);
-       }
+       ;
       else if (unformat (input, "size %U",
                         unformat_memory_size, &sm->memory_size))
        ;
@@ -798,15 +873,12 @@ statseg_config (vlib_main_t * vm, unformat_input_t * input)
                                  format_unformat_error, input);
     }
 
-  /* set default socket file name when statseg config stanza is empty. */
-  if (!vec_len (sm->socket_name))
-    sm->socket_name = format (sm->socket_name, "%s",
-                             STAT_SEGMENT_SOCKET_FILE);
   /*
    * NULL-terminate socket name string
    * clib_socket_init()->socket_config() use C str*
    */
-  vec_terminate_c_string (sm->socket_name);
+  if (vec_len (sm->socket_name))
+    vec_terminate_c_string (sm->socket_name);
 
   return 0;
 }