FD.io VPP  v19.01.3-6-g70449b9b9
Vector Packet Processing
perfmon_periodic.c
Go to the documentation of this file.
1 /*
2  * perfmon_periodic.c - skeleton plug-in periodic function
3  *
4  * Copyright (c) <current-year> <your-organization>
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vppinfra/error.h>
20 #include <perfmon/perfmon.h>
21 #include <asm/unistd.h>
22 #include <sys/ioctl.h>
23 
24 static long
25 perf_event_open (struct perf_event_attr *hw_event, pid_t pid, int cpu,
26  int group_fd, unsigned long flags)
27 {
28  int ret;
29 
30  ret = syscall (__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
31  return ret;
32 }
33 
34 static u64
36 {
37  if (vm->perf_counter_id)
38  return clib_rdpmc (vm->perf_counter_id);
39  else
40  {
41  u64 sw_value;
42  if (read (vm->perf_counter_fd, &sw_value, sizeof (sw_value)) !=
43  sizeof (sw_value))
44  {
45  clib_unix_warning ("counter read failed, disable collection...");
47  return 0ULL;
48  }
49  return sw_value;
50  }
51 }
52 
53 static void
55 {
56  int i, j;
57  vlib_main_t *vm = pm->vlib_main;
58  vlib_main_t *stat_vm;
59  vlib_node_main_t *nm;
60  vlib_node_t *n;
61 
63 
64  for (j = 0; j < vec_len (vlib_mains); j++)
65  {
66  stat_vm = vlib_mains[j];
67  if (stat_vm == 0)
68  continue;
69 
70  nm = &stat_vm->node_main;
71 
72  /* Clear the node runtime perfmon counters */
73  for (i = 0; i < vec_len (nm->nodes); i++)
74  {
75  n = nm->nodes[i];
76  vlib_node_sync_stats (stat_vm, n);
77  }
78 
79  /* And clear the node perfmon counters */
80  for (i = 0; i < vec_len (nm->nodes); i++)
81  {
82  n = nm->nodes[i];
87  }
88  }
90 }
91 
92 static void
94 {
95  struct perf_event_attr pe;
96  int fd;
97  struct perf_event_mmap_page *p = 0;
100  u32 my_thread_index = vm->thread_index;
101 
103 
104  memset (&pe, 0, sizeof (struct perf_event_attr));
105  pe.type = c->pe_type;
106  pe.size = sizeof (struct perf_event_attr);
107  pe.config = c->pe_config;
108  pe.disabled = 1;
109  pe.pinned = 1;
110  /*
111  * Note: excluding the kernel makes the
112  * (software) context-switch counter read 0...
113  */
114  if (pe.type != PERF_TYPE_SOFTWARE)
115  {
116  /* Exclude kernel and hypervisor */
117  pe.exclude_kernel = 1;
118  pe.exclude_hv = 1;
119  }
120 
121  fd = perf_event_open (&pe, 0, -1, -1, 0);
122  if (fd == -1)
123  {
124  clib_unix_warning ("event open: type %d config %d", c->pe_type,
125  c->pe_config);
126  return;
127  }
128 
129  if (pe.type != PERF_TYPE_SOFTWARE)
130  {
131  p = mmap (0, pm->page_size, PROT_READ, MAP_SHARED, fd, 0);
132  if (p == MAP_FAILED)
133  {
134  clib_unix_warning ("mmap");
135  close (fd);
136  return;
137  }
138  }
139 
140  if (ioctl (fd, PERF_EVENT_IOC_RESET, 0) < 0)
141  clib_unix_warning ("reset ioctl");
142 
143  if (ioctl (fd, PERF_EVENT_IOC_ENABLE, 0) < 0)
144  clib_unix_warning ("enable ioctl");
145 
146  /*
147  * Software event counters - and others not capable of being
148  * read via the "rdpmc" instruction - will be read
149  * by system calls.
150  */
151  if (pe.type == PERF_TYPE_SOFTWARE || p->cap_user_rdpmc == 0)
152  pm->rdpmc_indices[my_thread_index] = 0;
153  else /* use rdpmc instrs */
154  pm->rdpmc_indices[my_thread_index] = p->index - 1;
155  pm->perf_event_pages[my_thread_index] = (void *) p;
156 
157  pm->pm_fds[my_thread_index] = fd;
158 
159  /* Enable the main loop counter snapshot mechanism */
160  vm->perf_counter_id = pm->rdpmc_indices[my_thread_index];
161  vm->perf_counter_fd = fd;
163 }
164 
165 static void
167 {
169  u32 my_thread_index = vm->thread_index;
170 
171  if (pm->pm_fds[my_thread_index] == 0)
172  return;
173 
174  /* Stop main loop collection */
176 
177  if (ioctl (pm->pm_fds[my_thread_index], PERF_EVENT_IOC_DISABLE, 0) < 0)
178  clib_unix_warning ("disable ioctl");
179 
180  if (pm->perf_event_pages[my_thread_index])
181  if (munmap (pm->perf_event_pages[my_thread_index], pm->page_size) < 0)
182  clib_unix_warning ("munmap");
183 
184  (void) close (pm->pm_fds[my_thread_index]);
185  pm->pm_fds[my_thread_index] = 0;
186 }
187 
188 static void
190 {
192 
195 }
196 
197 static void
199 {
201  disable_event (pm);
203 }
204 
205 static void
206 start_event (perfmon_main_t * pm, f64 now, uword event_data)
207 {
208  int i;
209  pm->current_event = 0;
210  if (vec_len (pm->events_to_collect) == 0)
211  {
212  pm->state = PERFMON_STATE_OFF;
213  return;
214  }
216  clear_counters (pm);
217 
218  /* Start collection on this thread */
220 
221  /* And also on worker threads */
222  for (i = 1; i < vec_len (vlib_mains); i++)
223  {
224  if (vlib_mains[i] == 0)
225  continue;
228  }
229 }
230 
231 void
233 {
234  int i, j;
235  vlib_main_t *vm = pm->vlib_main;
236  vlib_main_t *stat_vm;
237  vlib_node_main_t *nm;
238  vlib_node_t ***node_dups = 0;
239  vlib_node_t **nodes;
240  vlib_node_t *n;
242  perfmon_event_config_t *current_event;
243  uword *p;
244  u8 *counter_name;
245  u64 counter_value;
246  u64 vectors_this_counter;
247 
248  /* snapshoot the nodes, including pm counters */
250 
251  for (j = 0; j < vec_len (vlib_mains); j++)
252  {
253  stat_vm = vlib_mains[j];
254  if (stat_vm == 0)
255  continue;
256 
257  nm = &stat_vm->node_main;
258 
259  for (i = 0; i < vec_len (nm->nodes); i++)
260  {
261  n = nm->nodes[i];
262  vlib_node_sync_stats (stat_vm, n);
263  }
264 
265  nodes = 0;
266  vec_validate (nodes, vec_len (nm->nodes) - 1);
267  vec_add1 (node_dups, nodes);
268 
269  /* Snapshoot and clear the per-node perfmon counters */
270  for (i = 0; i < vec_len (nm->nodes); i++)
271  {
272  n = nm->nodes[i];
273  nodes[i] = clib_mem_alloc (sizeof (*n));
274  clib_memcpy_fast (nodes[i], n, sizeof (*n));
279  }
280  }
281 
283 
284  current_event = pm->events_to_collect + pm->current_event;
285 
286  for (j = 0; j < vec_len (vlib_mains); j++)
287  {
288  stat_vm = vlib_mains[j];
289  if (stat_vm == 0)
290  continue;
291 
292  nodes = node_dups[j];
293 
294  for (i = 0; i < vec_len (nodes); i++)
295  {
296  u8 *capture_name;
297 
298  n = nodes[i];
299  if (n->stats_total.perf_counter_ticks == 0)
300  {
301  clib_mem_free (n);
302  continue;
303  }
304 
305  capture_name = format (0, "t%d-%v%c", j, n->name, 0);
306 
308  capture_name);
309 
310  if (p == 0)
311  {
312  pool_get (pm->capture_pool, c);
313  memset (c, 0, sizeof (*c));
314  c->thread_and_node_name = capture_name;
316  capture_name, c - pm->capture_pool);
317  }
318  else
319  c = pool_elt_at_index (pm->capture_pool, p[0]);
320 
321  /* Snapshoot counters, etc. into the capture */
322  counter_name = (u8 *) current_event->name;
323  counter_value = n->stats_total.perf_counter_ticks -
325  vectors_this_counter = n->stats_total.perf_counter_vectors -
327 
328  vec_add1 (c->counter_names, counter_name);
329  vec_add1 (c->counter_values, counter_value);
330  vec_add1 (c->vectors_this_counter, vectors_this_counter);
331  clib_mem_free (n);
332  }
333  vec_free (nodes);
334  }
335  vec_free (node_dups);
336 }
337 
338 static void
340 {
341  int i;
342  disable_event (pm);
343 
344  /* And also on worker threads */
345  for (i = 1; i < vec_len (vlib_mains); i++)
346  {
347  if (vlib_mains[i] == 0)
348  continue;
351  }
352 
353  /* Short delay to make sure workers have stopped collection */
354  if (i > 1)
355  vlib_process_suspend (pm->vlib_main, 1e-3);
357  pm->current_event++;
358  if (pm->current_event >= vec_len (pm->events_to_collect))
359  {
360  pm->current_event = 0;
361  pm->state = PERFMON_STATE_OFF;
362  return;
363  }
365 
366  /* And also on worker threads */
367  for (i = 1; i < vec_len (vlib_mains); i++)
368  {
369  if (vlib_mains[i] == 0)
370  continue;
373  }
374 }
375 
376 static uword
379 {
381  f64 now;
382  uword *event_data = 0;
383  uword event_type;
384  int i;
385 
386  while (1)
387  {
388  if (pm->state == PERFMON_STATE_RUNNING)
390  else
392 
393  now = vlib_time_now (vm);
394 
395  event_type = vlib_process_get_events (vm, (uword **) & event_data);
396 
397  switch (event_type)
398  {
399  case PERFMON_START:
400  for (i = 0; i < vec_len (event_data); i++)
401  start_event (pm, now, event_data[i]);
402  break;
403 
404  /* Handle timeout */
405  case ~0:
406  handle_timeout (pm, now);
407  break;
408 
409  default:
410  clib_warning ("Unexpected event %d", event_type);
411  break;
412  }
413  vec_reset_length (event_data);
414  }
415  return 0; /* or not */
416 }
417 
418 /* *INDENT-OFF* */
420 {
421  .function = perfmon_periodic_process,
422  .type = VLIB_NODE_TYPE_PROCESS,
423  .name = "perfmon-periodic-process",
424 };
425 /* *INDENT-ON* */
426 
427 /*
428  * fd.io coding-style-patch-verification: ON
429  *
430  * Local Variables:
431  * eval: (c-set-style "gnu")
432  * End:
433  */
perfmon_capture_t * capture_pool
Definition: perfmon.h:93
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
volatile u8 state
Definition: perfmon.h:90
u32 current_event
Definition: perfmon.h:111
f64 timeout_interval
Definition: perfmon.h:108
static void worker_thread_start_event(vlib_main_t *vm)
u32 flags
Definition: vhost_user.h:115
u64 * vectors_this_counter
Definition: perfmon.h:69
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:673
static void disable_event(perfmon_main_t *pm)
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:593
perfmon_event_config_t * events_to_collect
Definition: perfmon.h:101
static void clear_counters(perfmon_main_t *pm)
unsigned long u64
Definition: types.h:89
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags)
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:232
u32 thread_index
Definition: main.h:179
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:525
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:275
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
vlib_main_t * vlib_main
Definition: perfmon.h:124
u32 * rdpmc_indices
Definition: perfmon.h:112
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
vlib_main_t ** vlib_mains
Definition: buffer.c:310
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
#define vlib_worker_thread_barrier_sync(X)
Definition: threads.h:204
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:422
vlib_node_stats_t stats_last_clear
Definition: node.h:298
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:516
vlib_node_t ** nodes
Definition: node.h:721
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u64 perf_counter_vectors
Definition: node.h:262
u64 perf_counter_ticks
Definition: node.h:261
u8 * thread_and_node_name
Definition: perfmon.h:66
unsigned int u32
Definition: types.h:88
void scrape_and_clear_counters(perfmon_main_t *pm)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
vlib_node_stats_t stats_total
Definition: node.h:294
u8 ** counter_names
Definition: perfmon.h:67
static void handle_timeout(perfmon_main_t *pm, f64 now)
int perf_counter_id
Definition: main.h:91
u8 * name
Definition: node.h:288
u64(* vlib_node_runtime_perf_counter_cb)(struct vlib_main_t *)
Definition: main.h:90
static void worker_thread_stop_event(vlib_main_t *vm)
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
svmdb_client_t * c
vlib_main_t * vm
Definition: buffer.c:301
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
#define clib_warning(format, args...)
Definition: error.h:59
int * pm_fds
Definition: perfmon.h:118
u8 ** perf_event_pages
Definition: perfmon.h:114
int perf_counter_fd
Definition: main.h:92
static u64 read_current_perf_counter(vlib_main_t *vm)
static void enable_current_event(perfmon_main_t *pm)
static void clib_mem_free(void *p)
Definition: mem.h:205
static u64 clib_rdpmc(int counter_id)
Definition: pmc.h:22
perfmon_main_t perfmon_main
Definition: perfmon.c:27
static void * clib_mem_alloc(uword size)
Definition: mem.h:132
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
uword * capture_by_thread_and_node_name
Definition: perfmon.h:94
static void start_event(perfmon_main_t *pm, f64 now, uword event_data)
void vlib_node_sync_stats(vlib_main_t *vm, vlib_node_t *n)
Definition: main.c:577
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 * counter_values
Definition: perfmon.h:68
vlib_node_main_t node_main
Definition: main.h:129
u64 uword
Definition: types.h:112
#define clib_unix_warning(format, args...)
Definition: error.h:68
#define hash_get_mem(h, key)
Definition: hash.h:269
void vlib_worker_thread_barrier_release(vlib_main_t *vm)
Definition: threads.c:1470
static uword perfmon_periodic_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
volatile void(* worker_thread_main_loop_callback)(struct vlib_main_t *)
Definition: main.h:196
vlib_node_registration_t perfmon_periodic_node
(constructor) VLIB_REGISTER_NODE (perfmon_periodic_node)
#define PERFMON_START
Definition: perfmon.h:135