+/*
+ * Node performance counters:
+ * total_calls [threads][node-index]
+ * total_vectors
+ * total_calls
+ * total suspends
+ */
+
+static inline void
+update_node_counters (stats_main_t * sm)
+{
+ vlib_main_t *vm = vlib_mains[0];
+ vlib_main_t **stat_vms = 0;
+ vlib_node_t ***node_dups = 0;
+ int i, j;
+ stat_segment_shared_header_t *shared_header = sm->shared_header;
+ static u32 no_max_nodes = 0;
+
+ vlib_node_get_nodes (0 /* vm, for barrier sync */ ,
+ (u32) ~ 0 /* all threads */ ,
+ 1 /* include stats */ ,
+ 0 /* barrier sync */ ,
+ &node_dups, &stat_vms);
+
+ u32 l = vec_len (node_dups[0]);
+
+ /*
+ * Extend performance nodes if necessary
+ */
+ if (l > no_max_nodes)
+ {
+ void *oldheap = clib_mem_set_heap (sm->heap);
+ vlib_stat_segment_lock ();
+
+ stat_validate_counter_vector (&sm->directory_vector
+ [STAT_COUNTER_NODE_CLOCKS], l);
+ stat_validate_counter_vector (&sm->directory_vector
+ [STAT_COUNTER_NODE_VECTORS], l);
+ stat_validate_counter_vector (&sm->directory_vector
+ [STAT_COUNTER_NODE_CALLS], l);
+ stat_validate_counter_vector (&sm->directory_vector
+ [STAT_COUNTER_NODE_SUSPENDS], l);
+
+ vlib_stat_segment_unlock ();
+ clib_mem_set_heap (oldheap);
+ no_max_nodes = l;
+ }
+
+ for (j = 0; j < vec_len (node_dups); j++)
+ {
+ vlib_node_t **nodes = node_dups[j];
+ u32 l = vec_len (nodes);
+
+ for (i = 0; i < vec_len (nodes); i++)
+ {
+ counter_t **counters;
+ counter_t *c;
+ vlib_node_t *n = nodes[i];
+
+ counters =
+ stat_segment_pointer (shared_header,
+ sm->directory_vector
+ [STAT_COUNTER_NODE_CLOCKS].offset);
+ c = counters[j];
+ c[n->index] = n->stats_total.clocks - n->stats_last_clear.clocks;
+
+ counters =
+ stat_segment_pointer (shared_header,
+ sm->directory_vector
+ [STAT_COUNTER_NODE_VECTORS].offset);
+ c = counters[j];
+ c[n->index] = n->stats_total.vectors - n->stats_last_clear.vectors;
+
+ counters =
+ stat_segment_pointer (shared_header,
+ sm->directory_vector
+ [STAT_COUNTER_NODE_CALLS].offset);
+ c = counters[j];
+ c[n->index] = n->stats_total.calls - n->stats_last_clear.calls;
+
+ counters =
+ stat_segment_pointer (shared_header,
+ sm->directory_vector
+ [STAT_COUNTER_NODE_SUSPENDS].offset);
+ c = counters[j];
+ c[n->index] =
+ n->stats_total.suspends - n->stats_last_clear.suspends;
+ }
+ }
+}
+
+/*
+ * Called by stats_thread_fn, in stats.c, which runs in a
+ * separate pthread, which won't halt the parade
+ * in single-forwarding-core cases.
+ */
+
+void
+do_stat_segment_updates (stats_main_t * sm)