STATS: Separate socket for fd exchange.
[vpp.git] / src / vpp / app / stat_client.c
index 610a6a5..0ee78d2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *------------------------------------------------------------------
- * api_format.c
+ * stat_client.c
  *
  * Copyright (c) 2018 Cisco and/or its affiliates.
  * Licensed under the Apache License, Version 2.0 (the "License");
 
 #include <vpp/app/stat_client.h>
 
-#include <vpp/api/vpe_msg_enum.h>
-
-#define vl_typedefs            /* define message structures */
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_typedefs
-
-#define vl_endianfun           /* define endian fcns */
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_endianfun
-
-/* instantiate all the print functions we know about */
-#define vl_print(handle, ...) fformat (handle, __VA_ARGS__)
-#define vl_printfun
-#include <vpp/api/vpe_all_api_h.h>
-#undef vl_printfun
-
 stat_client_main_t stat_client_main;
 
-static void vl_api_map_stats_segment_reply_t_handler
-  (vl_api_map_stats_segment_reply_t * mp)
+static int
+stat_segment_connect (stat_client_main_t * sm)
 {
-  stat_client_main_t *sm = &stat_client_main;
   ssvm_private_t *ssvmp = &sm->stat_segment;
   ssvm_shared_header_t *shared_header;
-  socket_client_main_t *scm = sm->socket_client_main;
-  int rv = ntohl (mp->retval);
-  int my_fd, retval;
-  clib_error_t *error;
-
-  if (rv != 0)
+  clib_socket_t s = { 0 };
+  clib_error_t *err;
+  int fd = -1, retval;
+
+  s.config = (char *) sm->socket_name;
+  s.flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET;
+  err = clib_socket_init (&s);
+  if (err)
     {
-      fformat (stderr, "ERROR mapping stats segment: %d", rv);
+      clib_error_report (err);
       exit (1);
     }
-
-  /*
-   * Check the socket for the magic fd
-   */
-  error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 5);
-  if (error)
+  err = clib_socket_recvmsg (&s, 0, 0, &fd, 1);
+  if (err)
     {
-      clib_error_report (error);
-      exit (1);
+      clib_error_report (err);
+      return -1;
     }
+  clib_socket_close (&s);
 
   memset (ssvmp, 0, sizeof (*ssvmp));
-  ssvmp->fd = my_fd;
+  ssvmp->fd = fd;
 
   /* Note: this closes memfd.fd */
   retval = ssvm_slave_init_memfd (ssvmp);
   if (retval)
     {
       clib_warning ("WARNING: segment map returned %d", retval);
-      exit (1);
+      return -1;
     }
 
   fformat (stdout, "Stat segment mapped OK...\n");
@@ -84,72 +66,21 @@ static void vl_api_map_stats_segment_reply_t_handler
   sm->stat_segment_lockp = (clib_spinlock_t *) (shared_header->opaque[0]);
   sm->segment_ready = 1;
 
-  /* No need to keep the socket API connection open */
-  close (sm->socket_client_main->socket_fd);
-}
-
-#define foreach_api_reply_msg \
-_(MAP_STATS_SEGMENT_REPLY, map_stats_segment_reply)
-
-static void
-vpp_api_hookup (void)
-{
-#define _(N,n)                                                  \
-    vl_msg_api_set_handlers(VL_API_##N, #n,                     \
-                           vl_api_##n##_t_handler,             \
-                           vl_noop_handler,                     \
-                           vl_api_##n##_t_endian,               \
-                           vl_api_##n##_t_print,                \
-                           sizeof(vl_api_##n##_t), 1);
-  foreach_api_reply_msg;
-#undef _
-}
-
-static int
-connect_to_vpp (stat_client_main_t * sm)
-{
-  int rv;
-  vl_api_map_stats_segment_t *mp;
-  api_main_t *am = &api_main;
-
-  sm->socket_client_main = &socket_client_main;
-
-  rv = vl_socket_client_connect ((char *) sm->socket_name,
-                                "stat_client",
-                                0 /* default socket rx, tx buffer */ );
-  if (rv)
-    {
-      fformat (stderr, "Error connecting to vpp...\n");
-      exit (1);
-    }
-
-  /* Hook up reply handler */
-  vpp_api_hookup ();
-
-  /* Map the stats segment */
-  mp = vl_socket_client_msg_alloc (sizeof (*mp));
-  mp->_vl_msg_id = ntohs (VL_API_MAP_STATS_SEGMENT);
-  mp->client_index = am->my_client_index;
-  mp->context = 0xdeaddabe;
-
-  /* Send the message */
-  vl_socket_client_write ();
-
-  /* Wait for a reply, process it.. */
-  vl_socket_client_read (5 /* timeout in seconds */ );
-
   return 0;
 }
 
 #define foreach_cached_pointer                                          \
-_(vector_rate, SCALAR_POINTER, &stat_client_main.vector_rate_ptr)       \
-_(input_rate, SCALAR_POINTER, &stat_client_main.input_rate_ptr)         \
-_(rx, COUNTER_VECTOR, &stat_client_main.intfc_rx_counters)              \
-_(tx, COUNTER_VECTOR, &stat_client_main.intfc_tx_counters)              \
+_(/sys/vector_rate, SCALAR_POINTER, &stat_client_main.vector_rate_ptr) \
+_(/sys/input_rate, SCALAR_POINTER, &stat_client_main.input_rate_ptr)   \
+_(/sys/last_update, SCALAR_POINTER, &stat_client_main.last_runtime_ptr)        \
+_(/sys/last_stats_clear, SCALAR_POINTER,                               \
+  &stat_client_main.last_runtime_stats_clear_ptr)                       \
+_(/if/rx, COUNTER_VECTOR, &stat_client_main.intfc_rx_counters)         \
+_(/if/tx, COUNTER_VECTOR, &stat_client_main.intfc_tx_counters)         \
 _(/err/0/counter_vector, VECTOR_POINTER,                                \
   &stat_client_main.thread_0_error_counts)                              \
-_(/err/IP4 source address matches local interface, ERROR_INDEX,         \
-  &stat_client_main.source_address_match_error_index)
+_(serialized_nodes, SERIALIZED_NODES,                                   \
+  &stat_client_main.serialized_nodes)
 
 typedef struct
 {
@@ -213,9 +144,12 @@ stat_poll_loop (stat_client_main_t * sm)
   ssvm_private_t *ssvmp = &sm->stat_segment;
   ssvm_shared_header_t *shared_header;
   vlib_counter_t *thread0_rx_counters = 0, *thread0_tx_counters = 0;
+  vlib_node_t ***nodes_by_thread;
+  vlib_node_t **nodes;
+  vlib_node_t *n;
   f64 vector_rate, input_rate;
   u32 len;
-  int i;
+  int i, j;
   u32 source_address_match_errors;
 
   /* Wait until the stats segment is mapped */
@@ -290,27 +224,126 @@ stat_poll_loop (stat_client_main_t * sm)
 
       fformat (stdout, "%lld source address match errors\n",
               source_address_match_errors);
+
+      if (sm->serialized_nodes)
+       {
+         nodes_by_thread = vlib_node_unserialize (sm->serialized_nodes);
+
+         /* Across all threads... */
+         for (i = 0; i < vec_len (nodes_by_thread); i++)
+           {
+             u64 n_input, n_output, n_drop, n_punt;
+             u64 n_internal_vectors, n_internal_calls;
+             u64 n_clocks, l, v, c;
+             f64 dt;
+
+             nodes = nodes_by_thread[i];
+
+             fformat (stdout, "Thread %d -------------------------\n", i);
+
+             n_input = n_output = n_drop = n_punt = n_clocks = 0;
+             n_internal_vectors = n_internal_calls = 0;
+
+             /* Across all nodes */
+             for (j = 0; j < vec_len (nodes); j++)
+               {
+                 n = nodes[j];
+
+                 /* Exactly stolen from node_cli.c... */
+                 l = n->stats_total.clocks - n->stats_last_clear.clocks;
+                 n_clocks += l;
+
+                 v = n->stats_total.vectors - n->stats_last_clear.vectors;
+                 c = n->stats_total.calls - n->stats_last_clear.calls;
+
+                 switch (n->type)
+                   {
+                   default:
+                     continue;
+
+                   case VLIB_NODE_TYPE_INTERNAL:
+                     n_output +=
+                       (n->flags & VLIB_NODE_FLAG_IS_OUTPUT) ? v : 0;
+                     n_drop += (n->flags & VLIB_NODE_FLAG_IS_DROP) ? v : 0;
+                     n_punt += (n->flags & VLIB_NODE_FLAG_IS_PUNT) ? v : 0;
+                     if (!(n->flags & VLIB_NODE_FLAG_IS_OUTPUT))
+                       {
+                         n_internal_vectors += v;
+                         n_internal_calls += c;
+                       }
+                     if (n->flags & VLIB_NODE_FLAG_IS_HANDOFF)
+                       n_input += v;
+                     break;
+
+                   case VLIB_NODE_TYPE_INPUT:
+                     n_input += v;
+                     break;
+                   }
+
+                 if (n->stats_total.calls)
+                   {
+                     fformat (stdout,
+                              "%s (%s): clocks %lld calls %lld vectors %lld ",
+                              n->name,
+                              n->state_string,
+                              n->stats_total.clocks,
+                              n->stats_total.calls, n->stats_total.vectors);
+                     if (n->stats_total.vectors)
+                       fformat (stdout, "clocks/pkt %.2f\n",
+                                (f64) n->stats_total.clocks /
+                                (f64) n->stats_total.vectors);
+                     else
+                       fformat (stdout, "\n");
+                   }
+                 vec_free (n->name);
+                 vec_free (n->next_nodes);
+                 vec_free (n);
+               }
+
+             fformat (stdout, "average vectors/node %.2f\n",
+                      (n_internal_calls > 0
+                       ? (f64) n_internal_vectors / (f64) n_internal_calls
+                       : 0));
+
+
+             dt = *sm->last_runtime_ptr - *sm->last_runtime_stats_clear_ptr;
+
+             fformat (stdout,
+                      " vectors rates in %.4e, out %.4e, drop %.4e, "
+                      "punt %.4e\n",
+                      (f64) n_input / dt,
+                      (f64) n_output / dt, (f64) n_drop / dt,
+                      (f64) n_punt / dt);
+
+             vec_free (nodes);
+           }
+         vec_free (nodes_by_thread);
+       }
+      else
+       {
+         fformat (stdout, "serialized nodes NULL?\n");
+       }
+
     }
 }
 
-
 int
 main (int argc, char **argv)
 {
   unformat_input_t _argv, *a = &_argv;
   stat_client_main_t *sm = &stat_client_main;
-  u8 *socket_name;
+  u8 *stat_segment_name;
   int rv;
 
   clib_mem_init (0, 128 << 20);
 
   unformat_init_command_line (a, argv);
 
-  socket_name = (u8 *) API_SOCKET_FILE;
+  stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
 
   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (a, "socket-name %s", &socket_name))
+      if (unformat (a, "socket-name %s", &stat_segment_name))
        ;
       else
        {
@@ -319,14 +352,13 @@ main (int argc, char **argv)
        }
     }
 
-  sm->socket_name = socket_name;
-
-  rv = connect_to_vpp (sm);
+  sm->socket_name = stat_segment_name;
 
+  rv = stat_segment_connect (sm);
   if (rv)
     {
       fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
-              socket_name);
+              stat_segment_name);
       exit (1);
     }