FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
stat_client.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * stat_client.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/app/stat_client.h>
21 
23 
24 static int
26 {
27  ssvm_private_t *ssvmp = &sm->stat_segment;
28  ssvm_shared_header_t *shared_header;
29  clib_socket_t s = { 0 };
30  clib_error_t *err;
31  int fd = -1, retval;
32 
33  s.config = (char *) sm->socket_name;
35  err = clib_socket_init (&s);
36  if (err)
37  {
38  clib_error_report (err);
39  exit (1);
40  }
41  err = clib_socket_recvmsg (&s, 0, 0, &fd, 1);
42  if (err)
43  {
44  clib_error_report (err);
45  return -1;
46  }
47  clib_socket_close (&s);
48 
49  memset (ssvmp, 0, sizeof (*ssvmp));
50  ssvmp->fd = fd;
51 
52  /* Note: this closes memfd.fd */
53  retval = ssvm_slave_init_memfd (ssvmp);
54  if (retval)
55  {
56  clib_warning ("WARNING: segment map returned %d", retval);
57  return -1;
58  }
59 
60  fformat (stdout, "Stat segment mapped OK...\n");
61 
62  ASSERT (ssvmp && ssvmp->sh);
63 
64  /* Pick up the segment lock from the shared memory header */
65  shared_header = ssvmp->sh;
66  sm->stat_segment_lockp = (clib_spinlock_t *) (shared_header->opaque[0]);
67  sm->segment_ready = 1;
68 
69  return 0;
70 }
71 
72 #define foreach_cached_pointer \
73 _(/sys/vector_rate, SCALAR_POINTER, &stat_client_main.vector_rate_ptr) \
74 _(/sys/input_rate, SCALAR_POINTER, &stat_client_main.input_rate_ptr) \
75 _(/sys/last_update, SCALAR_POINTER, &stat_client_main.last_runtime_ptr) \
76 _(/sys/last_stats_clear, SCALAR_POINTER, \
77  &stat_client_main.last_runtime_stats_clear_ptr) \
78 _(/if/rx, COUNTER_VECTOR, &stat_client_main.intfc_rx_counters) \
79 _(/if/tx, COUNTER_VECTOR, &stat_client_main.intfc_tx_counters) \
80 _(/err/0/counter_vector, VECTOR_POINTER, \
81  &stat_client_main.thread_0_error_counts) \
82 _(serialized_nodes, SERIALIZED_NODES, \
83  &stat_client_main.serialized_nodes)
84 
85 typedef struct
86 {
87  char *name;
89  void *valuep;
91 
92 cached_pointer_t cached_pointers[] = {
93 #define _(n,t,p) {#n, STAT_DIR_TYPE_##t, (void *)p},
95 #undef _
96 };
97 
98 static void
100  ssvm_shared_header_t * shared_header)
101 {
102  uword *p, *counter_vector_by_name;
103  int i;
105  cached_pointer_t *cp;
106  u64 *valuep;
107 
108  /* Cached pointers OK? */
109  if (sm->current_epoch ==
110  (u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH])
111  return;
112 
113  fformat (stdout, "Updating cached pointers...\n");
114 
115  /* Nope, fix them... */
116  counter_vector_by_name = (uword *)
117  shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR];
118 
119  for (i = 0; i < ARRAY_LEN (cached_pointers); i++)
120  {
121  cp = &cached_pointers[i];
122 
123  p = hash_get_mem (counter_vector_by_name, cp->name);
124 
125  if (p == 0)
126  {
127  clib_warning ("WARN: %s not in directory!", cp->name);
128  continue;
129  }
130  ep = (stat_segment_directory_entry_t *) (p[0]);
131  ASSERT (ep->type == cp->type);
132  valuep = (u64 *) cp->valuep;
133  *valuep = (u64) ep->value;
134  }
135 
136  /* And remember that we did... */
137  sm->current_epoch = (u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH];
138 }
139 
140 static void
142 {
143  struct timespec ts, tsrem;
144  ssvm_private_t *ssvmp = &sm->stat_segment;
145  ssvm_shared_header_t *shared_header;
146  vlib_counter_t *thread0_rx_counters = 0, *thread0_tx_counters = 0;
147  vlib_node_t ***nodes_by_thread;
148  vlib_node_t **nodes;
149  vlib_node_t *n;
150  f64 vector_rate, input_rate;
151  u32 len;
152  int i, j;
153  u32 source_address_match_errors;
154 
155  /* Wait until the stats segment is mapped */
156  while (!sm->segment_ready)
157  {
158  ts.tv_sec = 0;
159  ts.tv_nsec = 100000000;
160  while (nanosleep (&ts, &tsrem) < 0)
161  ts = tsrem;
162  }
163 
164  shared_header = ssvmp->sh;
165  ASSERT (ssvmp->sh);
166 
167  while (1)
168  {
169  /* Scrape stats every 5 seconds */
170  ts.tv_sec = 5;
171  ts.tv_nsec = 0;
172  while (nanosleep (&ts, &tsrem) < 0)
173  ts = tsrem;
174 
175  vec_reset_length (thread0_rx_counters);
176  vec_reset_length (thread0_tx_counters);
177 
178  /* Grab the stats segment lock */
180 
181  /* see if we need to update cached pointers */
182  maybe_update_cached_pointers (sm, shared_header);
183 
184  ASSERT (sm->vector_rate_ptr);
187 
188  /* Read data from the segment */
189  vector_rate = *sm->vector_rate_ptr;
190  input_rate = *sm->input_rate_ptr;
191 
192  len = vec_len (sm->intfc_rx_counters[0]);
193 
194  ASSERT (len);
195 
196  vec_validate (thread0_rx_counters, len - 1);
197  vec_validate (thread0_tx_counters, len - 1);
198 
199  clib_memcpy (thread0_rx_counters, sm->intfc_rx_counters[0],
200  len * sizeof (vlib_counter_t));
201  clib_memcpy (thread0_tx_counters, sm->intfc_tx_counters[0],
202  len * sizeof (vlib_counter_t));
203 
204  source_address_match_errors =
206 
207  /* Drop the lock */
209 
210  /* And print results... */
211 
212  fformat (stdout, "vector_rate %.2f input_rate %.2f\n",
213  vector_rate, input_rate);
214 
215  for (i = 0; i < vec_len (thread0_rx_counters); i++)
216  {
217  fformat (stdout, "[%d]: %lld rx packets, %lld rx bytes\n",
218  i, thread0_rx_counters[i].packets,
219  thread0_rx_counters[i].bytes);
220  fformat (stdout, "[%d]: %lld tx packets, %lld tx bytes\n",
221  i, thread0_tx_counters[i].packets,
222  thread0_tx_counters[i].bytes);
223  }
224 
225  fformat (stdout, "%lld source address match errors\n",
226  source_address_match_errors);
227 
228  if (sm->serialized_nodes)
229  {
230  nodes_by_thread = vlib_node_unserialize (sm->serialized_nodes);
231 
232  /* Across all threads... */
233  for (i = 0; i < vec_len (nodes_by_thread); i++)
234  {
235  u64 n_input, n_output, n_drop, n_punt;
236  u64 n_internal_vectors, n_internal_calls;
237  u64 n_clocks, l, v, c;
238  f64 dt;
239 
240  nodes = nodes_by_thread[i];
241 
242  fformat (stdout, "Thread %d -------------------------\n", i);
243 
244  n_input = n_output = n_drop = n_punt = n_clocks = 0;
245  n_internal_vectors = n_internal_calls = 0;
246 
247  /* Across all nodes */
248  for (j = 0; j < vec_len (nodes); j++)
249  {
250  n = nodes[j];
251 
252  /* Exactly stolen from node_cli.c... */
254  n_clocks += l;
255 
258 
259  switch (n->type)
260  {
261  default:
262  continue;
263 
265  n_output +=
266  (n->flags & VLIB_NODE_FLAG_IS_OUTPUT) ? v : 0;
267  n_drop += (n->flags & VLIB_NODE_FLAG_IS_DROP) ? v : 0;
268  n_punt += (n->flags & VLIB_NODE_FLAG_IS_PUNT) ? v : 0;
269  if (!(n->flags & VLIB_NODE_FLAG_IS_OUTPUT))
270  {
271  n_internal_vectors += v;
272  n_internal_calls += c;
273  }
275  n_input += v;
276  break;
277 
279  n_input += v;
280  break;
281  }
282 
283  if (n->stats_total.calls)
284  {
285  fformat (stdout,
286  "%s (%s): clocks %lld calls %lld vectors %lld ",
287  n->name,
288  n->state_string,
289  n->stats_total.clocks,
291  if (n->stats_total.vectors)
292  fformat (stdout, "clocks/pkt %.2f\n",
293  (f64) n->stats_total.clocks /
294  (f64) n->stats_total.vectors);
295  else
296  fformat (stdout, "\n");
297  }
298  vec_free (n->name);
299  vec_free (n->next_nodes);
300  vec_free (n);
301  }
302 
303  fformat (stdout, "average vectors/node %.2f\n",
304  (n_internal_calls > 0
305  ? (f64) n_internal_vectors / (f64) n_internal_calls
306  : 0));
307 
308 
310 
311  fformat (stdout,
312  " vectors rates in %.4e, out %.4e, drop %.4e, "
313  "punt %.4e\n",
314  (f64) n_input / dt,
315  (f64) n_output / dt, (f64) n_drop / dt,
316  (f64) n_punt / dt);
317 
318  vec_free (nodes);
319  }
320  vec_free (nodes_by_thread);
321  }
322  else
323  {
324  fformat (stdout, "serialized nodes NULL?\n");
325  }
326 
327  }
328 }
329 
330 int
331 main (int argc, char **argv)
332 {
333  unformat_input_t _argv, *a = &_argv;
335  u8 *stat_segment_name;
336  int rv;
337 
338  clib_mem_init (0, 128 << 20);
339 
340  unformat_init_command_line (a, argv);
341 
342  stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
343 
345  {
346  if (unformat (a, "socket-name %s", &stat_segment_name))
347  ;
348  else
349  {
350  fformat (stderr, "%s: usage [socket-name <name>]\n", argv[0]);
351  exit (1);
352  }
353  }
354 
355  sm->socket_name = stat_segment_name;
356 
357  rv = stat_segment_connect (sm);
358  if (rv)
359  {
360  fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
361  stat_segment_name);
362  exit (1);
363  }
364 
365  stat_poll_loop (sm);
366  exit (0);
367 }
368 
369 /*
370  * fd.io coding-style-patch-verification: ON
371  *
372  * Local Variables:
373  * eval: (c-set-style "gnu")
374  * End:
375  */
u32 * next_nodes
Definition: node.h:324
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
u8 * state_string
Definition: node.h:358
Definition: stats.h:212
#define STAT_SEGMENT_OPAQUE_DIR
Definition: stats.h:199
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:89
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:74
a
Definition: bitmap.h:537
u64 source_address_match_error_index
Definition: stat_client.h:44
unsigned long u64
Definition: types.h:89
#define foreach_cached_pointer
Definition: stat_client.c:72
stat_client_main_t stat_client_main
Definition: stat_client.c:22
u16 flags
Definition: node.h:282
void * opaque[SSVM_N_OPAQUE]
Definition: ssvm.h:73
stat_directory_type_t type
Definition: stat_client.c:88
Combined counter to hold both packets and byte differences.
Definition: counter.h:140
#define VLIB_NODE_FLAG_IS_PUNT
Definition: node.h:291
for(i=1;i<=collision_buckets;i++)
int i
clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:376
ssvm_shared_header_t * sh
Definition: ssvm.h:83
unsigned char u8
Definition: types.h:56
static void stat_poll_loop(stat_client_main_t *sm)
Definition: stat_client.c:141
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
int main(int argc, char **argv)
Definition: stat_client.c:331
vlib_node_stats_t stats_last_clear
Definition: node.h:267
stat_directory_type_t
Definition: stats.h:202
clib_spinlock_t * stat_segment_lockp
Definition: stat_client.h:50
volatile int segment_ready
Definition: stat_client.h:33
static clib_error_t * clib_socket_recvmsg(clib_socket_t *s, void *msg, int msglen, int fds[], int num_fds)
Definition: socket.h:158
unsigned int u32
Definition: types.h:88
vlib_node_stats_t stats_total
Definition: node.h:263
static clib_error_t * clib_socket_close(clib_socket_t *sock)
Definition: socket.h:175
#define v
Definition: acl.c:491
struct _unformat_input_t unformat_input_t
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:1007
ssvm_private_t stat_segment
Definition: stat_client.h:47
vlib_counter_t ** intfc_rx_counters
Definition: stat_client.h:39
word fformat(FILE *f, char *fmt,...)
Definition: format.c:453
#define STAT_SEGMENT_OPAQUE_EPOCH
Definition: stats.h:200
u8 * name
Definition: node.h:257
u64 * thread_0_error_counts
Definition: stat_client.h:43
static int stat_segment_connect(stat_client_main_t *sm)
Definition: stat_client.c:25
void * clib_mem_init(void *heap, uword size)
Definition: mem_mheap.c:60
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
svmdb_client_t * c
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:75
#define ARRAY_LEN(x)
Definition: clib.h:59
vlib_node_t *** vlib_node_unserialize(u8 *vector)
int fd
memfd segments
Definition: ssvm.h:92
#define ASSERT(truth)
#define CLIB_SOCKET_F_IS_CLIENT
Definition: socket.h:59
#define clib_error_report(e)
Definition: error.h:113
struct _socket_t clib_socket_t
#define CLIB_SOCKET_F_SEQPACKET
Definition: socket.h:63
void * value
Definition: stats.h:215
#define VLIB_NODE_FLAG_IS_HANDOFF
Definition: node.h:292
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define STAT_SEGMENT_SOCKET_FILE
Definition: stats.h:33
u64 uword
Definition: types.h:112
vlib_counter_t ** intfc_tx_counters
Definition: stat_client.h:40
#define VLIB_NODE_FLAG_IS_DROP
Definition: node.h:290
#define hash_get_mem(h, key)
Definition: hash.h:269
vlib_node_type_t type
Definition: node.h:270
#define VLIB_NODE_FLAG_IS_OUTPUT
Definition: node.h:289
static void maybe_update_cached_pointers(stat_client_main_t *sm, ssvm_shared_header_t *shared_header)
Definition: stat_client.c:99
int ssvm_slave_init_memfd(ssvm_private_t *memfd)
Initialize memfd segment slave.
Definition: ssvm.c:262
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
f64 * last_runtime_stats_clear_ptr
Definition: stat_client.h:31
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
stat_directory_type_t type
Definition: stats.h:214