2 *------------------------------------------------------------------
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:
10 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
20 #include <vpp/app/stat_client.h>
22 stat_client_main_t stat_client_main;
25 stat_segment_connect (stat_client_main_t * sm)
27 ssvm_private_t *ssvmp = &sm->stat_segment;
28 ssvm_shared_header_t *shared_header;
29 clib_socket_t s = { 0 };
33 s.config = (char *) sm->socket_name;
34 s.flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET;
35 err = clib_socket_init (&s);
38 clib_error_report (err);
41 err = clib_socket_recvmsg (&s, 0, 0, &fd, 1);
44 clib_error_report (err);
47 clib_socket_close (&s);
49 memset (ssvmp, 0, sizeof (*ssvmp));
52 /* Note: this closes memfd.fd */
53 retval = ssvm_slave_init_memfd (ssvmp);
56 clib_warning ("WARNING: segment map returned %d", retval);
60 fformat (stdout, "Stat segment mapped OK...\n");
62 ASSERT (ssvmp && ssvmp->sh);
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;
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)
88 stat_directory_type_t type;
92 cached_pointer_t cached_pointers[] = {
93 #define _(n,t,p) {#n, STAT_DIR_TYPE_##t, (void *)p},
94 foreach_cached_pointer
99 maybe_update_cached_pointers (stat_client_main_t * sm,
100 ssvm_shared_header_t * shared_header)
102 uword *p, *counter_vector_by_name;
104 stat_segment_directory_entry_t *ep;
105 cached_pointer_t *cp;
108 /* Cached pointers OK? */
109 if (sm->current_epoch ==
110 (u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH])
113 fformat (stdout, "Updating cached pointers...\n");
115 /* Nope, fix them... */
116 counter_vector_by_name = (uword *)
117 shared_header->opaque[STAT_SEGMENT_OPAQUE_DIR];
119 for (i = 0; i < ARRAY_LEN (cached_pointers); i++)
121 cp = &cached_pointers[i];
123 p = hash_get_mem (counter_vector_by_name, cp->name);
127 clib_warning ("WARN: %s not in directory!", cp->name);
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;
136 /* And remember that we did... */
137 sm->current_epoch = (u64) shared_header->opaque[STAT_SEGMENT_OPAQUE_EPOCH];
141 stat_poll_loop (stat_client_main_t * sm)
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;
150 f64 vector_rate, input_rate;
153 u32 source_address_match_errors;
155 /* Wait until the stats segment is mapped */
156 while (!sm->segment_ready)
159 ts.tv_nsec = 100000000;
160 while (nanosleep (&ts, &tsrem) < 0)
164 shared_header = ssvmp->sh;
169 /* Scrape stats every 5 seconds */
172 while (nanosleep (&ts, &tsrem) < 0)
175 vec_reset_length (thread0_rx_counters);
176 vec_reset_length (thread0_tx_counters);
178 /* Grab the stats segment lock */
179 clib_spinlock_lock (sm->stat_segment_lockp);
181 /* see if we need to update cached pointers */
182 maybe_update_cached_pointers (sm, shared_header);
184 ASSERT (sm->vector_rate_ptr);
185 ASSERT (sm->intfc_rx_counters);
186 ASSERT (sm->intfc_tx_counters);
188 /* Read data from the segment */
189 vector_rate = *sm->vector_rate_ptr;
190 input_rate = *sm->input_rate_ptr;
192 len = vec_len (sm->intfc_rx_counters[0]);
196 vec_validate (thread0_rx_counters, len - 1);
197 vec_validate (thread0_tx_counters, len - 1);
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));
204 source_address_match_errors =
205 sm->thread_0_error_counts[sm->source_address_match_error_index];
208 clib_spinlock_unlock (sm->stat_segment_lockp);
210 /* And print results... */
212 fformat (stdout, "vector_rate %.2f input_rate %.2f\n",
213 vector_rate, input_rate);
215 for (i = 0; i < vec_len (thread0_rx_counters); i++)
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);
225 fformat (stdout, "%lld source address match errors\n",
226 source_address_match_errors);
228 if (sm->serialized_nodes)
230 nodes_by_thread = vlib_node_unserialize (sm->serialized_nodes);
232 /* Across all threads... */
233 for (i = 0; i < vec_len (nodes_by_thread); i++)
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;
240 nodes = nodes_by_thread[i];
242 fformat (stdout, "Thread %d -------------------------\n", i);
244 n_input = n_output = n_drop = n_punt = n_clocks = 0;
245 n_internal_vectors = n_internal_calls = 0;
247 /* Across all nodes */
248 for (j = 0; j < vec_len (nodes); j++)
252 /* Exactly stolen from node_cli.c... */
253 l = n->stats_total.clocks - n->stats_last_clear.clocks;
256 v = n->stats_total.vectors - n->stats_last_clear.vectors;
257 c = n->stats_total.calls - n->stats_last_clear.calls;
264 case VLIB_NODE_TYPE_INTERNAL:
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))
271 n_internal_vectors += v;
272 n_internal_calls += c;
274 if (n->flags & VLIB_NODE_FLAG_IS_HANDOFF)
278 case VLIB_NODE_TYPE_INPUT:
283 if (n->stats_total.calls)
286 "%s (%s): clocks %lld calls %lld vectors %lld ",
289 n->stats_total.clocks,
290 n->stats_total.calls, n->stats_total.vectors);
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);
296 fformat (stdout, "\n");
299 vec_free (n->next_nodes);
303 fformat (stdout, "average vectors/node %.2f\n",
304 (n_internal_calls > 0
305 ? (f64) n_internal_vectors / (f64) n_internal_calls
309 dt = *sm->last_runtime_ptr - *sm->last_runtime_stats_clear_ptr;
312 " vectors rates in %.4e, out %.4e, drop %.4e, "
315 (f64) n_output / dt, (f64) n_drop / dt,
320 vec_free (nodes_by_thread);
324 fformat (stdout, "serialized nodes NULL?\n");
331 main (int argc, char **argv)
333 unformat_input_t _argv, *a = &_argv;
334 stat_client_main_t *sm = &stat_client_main;
335 u8 *stat_segment_name;
338 clib_mem_init (0, 128 << 20);
340 unformat_init_command_line (a, argv);
342 stat_segment_name = (u8 *) STAT_SEGMENT_SOCKET_FILE;
344 while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
346 if (unformat (a, "socket-name %s", &stat_segment_name))
350 fformat (stderr, "%s: usage [socket-name <name>]\n", argv[0]);
355 sm->socket_name = stat_segment_name;
357 rv = stat_segment_connect (sm);
360 fformat (stderr, "Couldn't connect to vpp, does %s exist?\n",
370 * fd.io coding-style-patch-verification: ON
373 * eval: (c-set-style "gnu")