VPP API: Memory trace
[vpp.git] / src / vlib / cli.c
index 2d14111..a85fa93 100644 (file)
@@ -39,6 +39,8 @@
 
 #include <vlib/vlib.h>
 #include <vppinfra/cpu.h>
+#include <unistd.h>
+#include <ctype.h>
 
 /* Root of all show commands. */
 /* *INDENT-OFF* */
@@ -234,6 +236,108 @@ unformat_vlib_cli_sub_command (unformat_input_t * i, va_list * args)
   return is_unique;
 }
 
+static int
+vlib_cli_cmp_strings (void *a1, void *a2)
+{
+  u8 *c1 = *(u8 **) a1;
+  u8 *c2 = *(u8 **) a2;
+
+  return vec_cmp (c1, c2);
+}
+
+u8 **
+vlib_cli_get_possible_completions (u8 * str)
+{
+  vlib_cli_command_t *c;
+  vlib_cli_sub_command_t *sc;
+  vlib_main_t *vm = vlib_get_main ();
+  vlib_cli_main_t *vcm = &vm->cli_main;
+  uword *match_bitmap = 0;
+  uword index, is_unique, help_next_level;
+  u8 **result = 0;
+  unformat_input_t input;
+  unformat_init_vector (&input, vec_dup (str));
+  c = vec_elt_at_index (vcm->commands, 0);
+
+  /* remove trailing whitespace, except for one of them */
+  while (vec_len (input.buffer) >= 2 &&
+        isspace (input.buffer[vec_len (input.buffer) - 1]) &&
+        isspace (input.buffer[vec_len (input.buffer) - 2]))
+    {
+      vec_del1 (input.buffer, vec_len (input.buffer) - 1);
+    }
+
+  /* if input is empty, directly return list of root commands */
+  if (vec_len (input.buffer) == 0 ||
+      (vec_len (input.buffer) == 1 && isspace (input.buffer[0])))
+    {
+      vec_foreach (sc, c->sub_commands)
+      {
+       vec_add1 (result, (u8 *) sc->name);
+      }
+      goto done;
+    }
+
+  /* add a trailing '?' so that vlib_cli_sub_command_match can find
+   * all commands starting with the input string */
+  vec_add1 (input.buffer, '?');
+
+  while (1)
+    {
+      match_bitmap = vlib_cli_sub_command_match (c, &input);
+      /* no match: return no result */
+      if (match_bitmap == 0)
+       {
+         goto done;
+       }
+      is_unique = clib_bitmap_count_set_bits (match_bitmap) == 1;
+      /* unique match: try to step one subcommand level further */
+      if (is_unique)
+       {
+         /* stop if no more input */
+         if (input.index >= vec_len (input.buffer) - 1)
+           {
+             break;
+           }
+
+         index = clib_bitmap_first_set (match_bitmap);
+         c = get_sub_command (vcm, c, index);
+         clib_bitmap_free (match_bitmap);
+         continue;
+       }
+      /* multiple matches: stop here, return all matches */
+      break;
+    }
+
+  /* remove trailing '?' */
+  vec_del1 (input.buffer, vec_len (input.buffer) - 1);
+
+  /* if we have a space at the end of input, and a unique match,
+   * autocomplete the next level of subcommands */
+  help_next_level = (vec_len (str) == 0) || isspace (str[vec_len (str) - 1]);
+  /* *INDENT-OFF* */
+  clib_bitmap_foreach(index, match_bitmap, {
+    if (help_next_level && is_unique) {
+       c = get_sub_command (vcm, c, index);
+       vec_foreach (sc, c->sub_commands) {
+         vec_add1 (result, (u8*) sc->name);
+       }
+       goto done; /* break doesn't work in this macro-loop */
+    }
+    sc = &c->sub_commands[index];
+    vec_add1(result, (u8*) sc->name);
+  });
+  /* *INDENT-ON* */
+
+done:
+  clib_bitmap_free (match_bitmap);
+  unformat_free (&input);
+
+  if (result)
+    vec_sort_with_function (result, vlib_cli_cmp_strings);
+  return result;
+}
+
 static u8 *
 format_vlib_cli_command_help (u8 * s, va_list * args)
 {
@@ -595,11 +699,14 @@ vlib_cli_output (vlib_main_t * vm, char *fmt, ...)
   vec_free (s);
 }
 
+void *vl_msg_push_heap (void) __attribute__ ((weak));
+void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak));
+
 static clib_error_t *
 show_memory_usage (vlib_main_t * vm,
                   unformat_input_t * input, vlib_cli_command_t * cmd)
 {
-  int verbose = 0;
+  int verbose = 0, api_segment = 0;
   clib_error_t *error;
   u32 index = 0;
 
@@ -607,6 +714,8 @@ show_memory_usage (vlib_main_t * vm,
     {
       if (unformat (input, "verbose"))
        verbose = 1;
+      else if (unformat (input, "api-segment"))
+       api_segment = 1;
       else
        {
          error = clib_error_return (0, "unknown input `%U'",
@@ -615,6 +724,23 @@ show_memory_usage (vlib_main_t * vm,
        }
     }
 
+  if (api_segment)
+    {
+      void *oldheap = vl_msg_push_heap ();
+      u8 *s_in_svm =
+       format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1);
+      vl_msg_pop_heap (oldheap);
+      u8 *s = vec_dup (s_in_svm);
+
+      oldheap = vl_msg_push_heap ();
+      vec_free (s_in_svm);
+      vl_msg_pop_heap (oldheap);
+      vlib_cli_output (vm, "API segment start:");
+      vlib_cli_output (vm, "%v", s);
+      vlib_cli_output (vm, "API segment end:");
+      vec_free (s);
+    }
+
   /* *INDENT-OFF* */
   foreach_vlib_main (
   ({
@@ -629,7 +755,7 @@ show_memory_usage (vlib_main_t * vm,
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (show_memory_usage_command, static) = {
   .path = "show memory",
-  .short_help = "Show current memory usage",
+  .short_help = "[verbose | api-segment] Show current memory usage",
   .function = show_memory_usage,
 };
 /* *INDENT-ON* */
@@ -667,30 +793,48 @@ VLIB_CLI_COMMAND (show_cpu_command, static) = {
 };
 
 /* *INDENT-ON* */
+
 static clib_error_t *
 enable_disable_memory_trace (vlib_main_t * vm,
                             unformat_input_t * input,
                             vlib_cli_command_t * cmd)
 {
-  clib_error_t *error = 0;
+  unformat_input_t _line_input, *line_input = &_line_input;
   int enable;
+  int api_segment = 0;
+  void *oldheap;
 
-  if (!unformat_user (input, unformat_vlib_enable_disable, &enable))
+
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      error = clib_error_return (0, "expecting enable/on or disable/off");
-      goto done;
+      if (!unformat (line_input, "%U", unformat_vlib_enable_disable, &enable))
+       ;
+      else if (unformat (line_input, "api-segment"))
+       api_segment = 1;
+      else
+       {
+         unformat_free (line_input);
+         return clib_error_return (0, "invalid input");
+       }
     }
+  unformat_free (line_input);
 
+  if (api_segment)
+    oldheap = vl_msg_push_heap ();
   clib_mem_trace (enable);
+  if (api_segment)
+    vl_msg_pop_heap (oldheap);
 
-done:
-  return error;
+  return 0;
 }
 
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
   .path = "memory-trace",
-  .short_help = "Enable/disable memory allocation trace",
+  .short_help = "on|off [api-segment] Enable/disable memory allocation trace",
   .function = enable_disable_memory_trace,
 };
 /* *INDENT-ON* */
@@ -708,7 +852,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
     {
         /* *INDENT-OFF* */
         foreach_vlib_main({
-          heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
+          heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
           mheap = mheap_header(heap);
           mheap->flags |= MHEAP_FLAG_VALIDATE;
           // Turn off small object cache because it delays detection of errors
@@ -721,7 +865,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
     {
         /* *INDENT-OFF* */
         foreach_vlib_main({
-          heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
+          heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
           mheap = mheap_header(heap);
           mheap->flags &= ~MHEAP_FLAG_VALIDATE;
           mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE;
@@ -732,7 +876,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input,
     {
         /* *INDENT-OFF* */
         foreach_vlib_main({
-          heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index];
+          heap = clib_per_cpu_mheaps[this_vlib_main->thread_index];
           mheap = mheap_header(heap);
           mheap_validate(heap);
         });
@@ -757,6 +901,25 @@ VLIB_CLI_COMMAND (cmd_test_heap_validate,static) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
+               vlib_cli_command_t * cmd)
+{
+  char *newenviron[] = { NULL };
+
+  execve (vm->name, (char **) vm->argv, newenviron);
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (restart_cmd,static) = {
+    .path = "restart",
+    .short_help = "restart process",
+    .function = restart_cmd_fn,
+};
+/* *INDENT-ON* */
+
 #ifdef TEST_CODE
 /*
  * A trivial test harness to verify the per-process output_function
@@ -1143,6 +1306,55 @@ done:
 }
 #endif
 
+static int
+cli_path_compare (void *a1, void *a2)
+{
+  u8 **s1 = a1;
+  u8 **s2 = a2;
+
+  if ((vec_len (*s1) < vec_len (*s2)) &&
+      memcmp ((char *) *s1, (char *) *s2, vec_len (*s1)) == 0)
+    return -1;
+
+
+  if ((vec_len (*s1) > vec_len (*s2)) &&
+      memcmp ((char *) *s1, (char *) *s2, vec_len (*s2)) == 0)
+    return 1;
+
+  return vec_cmp (*s1, *s2);
+}
+
+static clib_error_t *
+show_cli_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
+                vlib_cli_command_t * cmd)
+{
+  vlib_cli_main_t *cm = &vm->cli_main;
+  vlib_cli_command_t *cli;
+  u8 **paths = 0, **s;
+
+  /* *INDENT-OFF* */
+  vec_foreach (cli, cm->commands)
+    if (vec_len (cli->path) > 0)
+      vec_add1 (paths, (u8 *) cli->path);
+
+  vec_sort_with_function (paths, cli_path_compare);
+
+  vec_foreach (s, paths)
+    vlib_cli_output (vm, "%v", *s);
+  /* *INDENT-ON* */
+
+  vec_free (paths);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_cli_command, static) = {
+  .path = "show cli",
+  .short_help = "Show cli commands",
+  .function = show_cli_cmd_fn,
+};
+/* *INDENT-ON* */
+
 static clib_error_t *
 vlib_cli_init (vlib_main_t * vm)
 {