STATS: Dynamically mapped shared memory segment
[vpp.git] / src / vpp / app / vpp_get_stats.c
1 /*
2  *------------------------------------------------------------------
3  * vpp_get_stats.c
4  *
5  * Copyright (c) 2018 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vpp-api/client/stat_client.h>
21 #include <vlib/vlib.h>
22 #include <vpp/stats/stats.h>
23
24 static int
25 stat_poll_loop (u8 ** patterns)
26 {
27   struct timespec ts, tsrem;
28   stat_segment_data_t *res;
29   int i, j, k, lost_connection = 0;
30   f64 heartbeat, prev_heartbeat = 0;
31   u32 *stats = stat_segment_ls (patterns);
32   if (!stats)
33     {
34       return -1;
35     }
36
37   printf ("\033[2J");           /*  clear the screen  */
38   while (1)
39     {
40       heartbeat = stat_segment_heartbeat ();
41       if (heartbeat > prev_heartbeat)
42         {
43           prev_heartbeat = heartbeat;
44           lost_connection = 0;
45         }
46       else
47         {
48           lost_connection++;
49         }
50       if (lost_connection > 10)
51         {
52           fformat (stderr, "Lost connection to VPP...\n");
53           return -1;
54         }
55
56       printf ("\033[H");        /* Cursor top left corner */
57       res = stat_segment_dump (stats);
58       if (!res)
59         {
60           stats = stat_segment_ls (patterns);
61           continue;
62         }
63       for (i = 0; i < vec_len (res); i++)
64         {
65           switch (res[i].type)
66             {
67             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
68               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
69                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
70                   fformat (stdout, "[%d]: %llu packets %s\n",
71                            j, res[i].simple_counter_vec[k][j], res[i].name);
72               break;
73
74             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
75               for (k = 0; k < vec_len (res[i].simple_counter_vec); k++)
76                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
77                   fformat (stdout, "[%d]: %llu packets, %llu bytes %s\n",
78                            j, res[i].combined_counter_vec[k][j].packets,
79                            res[i].combined_counter_vec[k][j].bytes,
80                            res[i].name);
81               break;
82
83             case STAT_DIR_TYPE_ERROR_INDEX:
84               fformat (stdout, "%llu %s\n", res[i].error_value, res[i].name);
85               break;
86
87             case STAT_DIR_TYPE_SCALAR_INDEX:
88               fformat (stdout, "%.2f %s\n", res[i].scalar_value, res[i].name);
89               break;
90
91             default:
92               printf ("Unknown value\n");
93               ;
94             }
95         }
96       stat_segment_data_free (res);
97       /* Scrape stats every 5 seconds */
98       ts.tv_sec = 1;
99       ts.tv_nsec = 0;
100       while (nanosleep (&ts, &tsrem) < 0)
101         ts = tsrem;
102
103     }
104 }
105
106 enum stat_client_cmd_e
107 {
108   STAT_CLIENT_CMD_UNKNOWN,
109   STAT_CLIENT_CMD_LS,
110   STAT_CLIENT_CMD_POLL,
111   STAT_CLIENT_CMD_DUMP,
112   STAT_CLIENT_CMD_TIGHTPOLL,
113 };
114
115 int
116 main (int argc, char **argv)
117 {
118   unformat_input_t _argv, *a = &_argv;
119   u8 *stat_segment_name, *pattern = 0, **patterns = 0;
120   int rv;
121   enum stat_client_cmd_e cmd = STAT_CLIENT_CMD_UNKNOWN;
122
123   /* Create a heap of 64MB */
124   clib_mem_init (0, 64 << 20);
125
126   unformat_init_command_line (a, argv);
127
128   stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
129
130   while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
131     {
132       if (unformat (a, "socket-name %s", &stat_segment_name))
133         ;
134       else if (unformat (a, "ls"))
135         {
136           cmd = STAT_CLIENT_CMD_LS;
137         }
138       else if (unformat (a, "dump"))
139         {
140           cmd = STAT_CLIENT_CMD_DUMP;
141         }
142       else if (unformat (a, "poll"))
143         {
144           cmd = STAT_CLIENT_CMD_POLL;
145         }
146       else if (unformat (a, "tightpoll"))
147         {
148           cmd = STAT_CLIENT_CMD_TIGHTPOLL;
149         }
150       else if (unformat (a, "%s", &pattern))
151         {
152           vec_add1 (patterns, pattern);
153         }
154       else
155         {
156           fformat (stderr,
157                    "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
158                    argv[0]);
159           exit (1);
160         }
161     }
162 reconnect:
163   rv = stat_segment_connect ((char *) stat_segment_name);
164   if (rv)
165     {
166       fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
167                stat_segment_name);
168       exit (1);
169     }
170
171   u32 *dir;
172   int i, j, k;
173   stat_segment_data_t *res;
174
175   dir = stat_segment_ls (patterns);
176
177   switch (cmd)
178     {
179     case STAT_CLIENT_CMD_LS:
180       /* List all counters */
181       for (i = 0; i < vec_len (dir); i++)
182         {
183           char *n = stat_segment_index_to_name (dir[i]);
184           printf ("%s\n", n);
185           free (n);
186         }
187       break;
188
189     case STAT_CLIENT_CMD_DUMP:
190       res = stat_segment_dump (dir);
191       for (i = 0; i < vec_len (res); i++)
192         {
193           switch (res[i].type)
194             {
195             case STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE:
196               for (k = 0; k < vec_len (res[i].simple_counter_vec) - 1; k++)
197                 for (j = 0; j < vec_len (res[i].simple_counter_vec[k]); j++)
198                   fformat (stdout, "[%d @ %d]: %llu packets %s\n",
199                            j, k, res[i].simple_counter_vec[k][j],
200                            res[i].name);
201               break;
202
203             case STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED:
204               for (k = 0; k < vec_len (res[i].combined_counter_vec); k++)
205                 for (j = 0; j < vec_len (res[i].combined_counter_vec[k]); j++)
206                   fformat (stdout, "[%d @ %d]: %llu packets, %llu bytes %s\n",
207                            j, k, res[i].combined_counter_vec[k][j].packets,
208                            res[i].combined_counter_vec[k][j].bytes,
209                            res[i].name);
210               break;
211
212             case STAT_DIR_TYPE_ERROR_INDEX:
213               fformat (stdout, "%llu %s\n", res[i].error_value, res[i].name);
214               break;
215
216             case STAT_DIR_TYPE_SCALAR_INDEX:
217               fformat (stdout, "%.2f %s\n", res[i].scalar_value, res[i].name);
218               break;
219
220             default:
221               ;
222             }
223         }
224       stat_segment_data_free (res);
225       break;
226
227     case STAT_CLIENT_CMD_POLL:
228       stat_poll_loop (patterns);
229       /* We can only exist the pool loop if we lost connection to VPP */
230       stat_segment_disconnect ();
231       goto reconnect;
232       break;
233
234     case STAT_CLIENT_CMD_TIGHTPOLL:
235       while (1)
236         {
237           res = stat_segment_dump (dir);
238           if (res == 0)
239             {
240               /* Refresh */
241               vec_free (dir);
242               dir = stat_segment_ls (patterns);
243               continue;
244             }
245           stat_segment_data_free (res);
246         }
247       break;
248
249     default:
250       fformat (stderr,
251                "%s: usage [socket-name <name>] [ls|dump|poll] <patterns> ...\n",
252                argv[0]);
253     }
254
255   stat_segment_disconnect ();
256
257   exit (0);
258 }
259
260 /*
261  * fd.io coding-style-patch-verification: ON
262  *
263  * Local Variables:
264  * eval: (c-set-style "gnu")
265  * End:
266  */