summaryrefslogtreecommitdiffstats
path: root/src/plugins/perfmon/perfmon_periodic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/perfmon/perfmon_periodic.c')
-rw-r--r--src/plugins/perfmon/perfmon_periodic.c547
1 files changed, 0 insertions, 547 deletions
diff --git a/src/plugins/perfmon/perfmon_periodic.c b/src/plugins/perfmon/perfmon_periodic.c
deleted file mode 100644
index de31221f6f4..00000000000
--- a/src/plugins/perfmon/perfmon_periodic.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * perfmon_periodic.c - skeleton plug-in periodic function
- *
- * Copyright (c) <current-year> <your-organization>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vlib/vlib.h>
-#include <vppinfra/error.h>
-#include <perfmon/perfmon.h>
-#include <asm/unistd.h>
-#include <sys/ioctl.h>
-
-/* "not in glibc" */
-static long
-perf_event_open (struct perf_event_attr *hw_event, pid_t pid, int cpu,
- int group_fd, unsigned long flags)
-{
- int ret;
-
- ret = syscall (__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
- return ret;
-}
-
-static void
-read_current_perf_counters (vlib_node_runtime_perf_callback_data_t * data,
- vlib_node_runtime_perf_callback_args_t * args)
-{
- int i;
- perfmon_main_t *pm = &perfmon_main;
- perfmon_thread_t *pt = data->u[0].v;
- u64 c[2] = { 0, 0 };
- u64 *cc;
-
- if (PREDICT_FALSE (args->call_type == VLIB_NODE_RUNTIME_PERF_RESET))
- return;
-
- if (args->call_type == VLIB_NODE_RUNTIME_PERF_BEFORE)
- cc = pt->c;
- else
- cc = c;
-
- for (i = 0; i < pm->n_active; i++)
- {
- if (pt->rdpmc_indices[i] != ~0)
- cc[i] = clib_rdpmc ((int) pt->rdpmc_indices[i]);
- else
- {
- u64 sw_value;
- int read_result;
- if ((read_result = read (pt->pm_fds[i], &sw_value,
- sizeof (sw_value))) != sizeof (sw_value))
- {
- clib_unix_warning
- ("counter read returned %d, expected %d",
- read_result, sizeof (sw_value));
- clib_callback_data_enable_disable
- (&args->vm->vlib_node_runtime_perf_callbacks,
- read_current_perf_counters, 0 /* enable */ );
- return;
- }
- cc[i] = sw_value;
- }
- }
-
- if (args->call_type == VLIB_NODE_RUNTIME_PERF_AFTER)
- {
- u32 node_index = args->node->node_index;
- vec_validate (pt->counters, node_index);
- pt->counters[node_index].ticks[0] += c[0] - pt->c[0];
- pt->counters[node_index].ticks[1] += c[1] - pt->c[1];
- pt->counters[node_index].vectors += args->packets;
- }
-}
-
-static void
-clear_counters (perfmon_main_t * pm)
-{
- int j;
- vlib_main_t *vm = pm->vlib_main;
- vlib_main_t *stat_vm;
- perfmon_thread_t *pt;
- u32 len;
-
-
- vlib_worker_thread_barrier_sync (vm);
-
- for (j = 0; j < vec_len (vlib_mains); j++)
- {
- stat_vm = vlib_mains[j];
- if (stat_vm == 0)
- continue;
-
- pt = pm->threads[j];
- len = vec_len (pt->counters);
- if (!len)
- continue;
-
- clib_memset (pt->counters, 0, len * sizeof (pt->counters[0]));
- }
- vlib_worker_thread_barrier_release (vm);
-}
-
-static void
-enable_current_events (perfmon_main_t * pm)
-{
- struct perf_event_attr pe;
- int fd;
- struct perf_event_mmap_page *p = 0;
- perfmon_event_config_t *c;
- vlib_main_t *vm = vlib_get_main ();
- u32 my_thread_index = vm->thread_index;
- perfmon_thread_t *pt = pm->threads[my_thread_index];
- u32 index;
- int i, limit = 1;
- int cpu;
- vlib_node_runtime_perf_callback_data_t cbdata = { 0 };
- cbdata.fp = read_current_perf_counters;
- cbdata.u[0].v = pt;
- cbdata.u[1].v = vm;
-
- if ((pm->current_event + 1) < vec_len (pm->single_events_to_collect))
- limit = 2;
-
- for (i = 0; i < limit; i++)
- {
- c = vec_elt_at_index (pm->single_events_to_collect,
- pm->current_event + i);
-
- memset (&pe, 0, sizeof (struct perf_event_attr));
- pe.type = c->pe_type;
- pe.size = sizeof (struct perf_event_attr);
- pe.config = c->pe_config;
- pe.disabled = 1;
- pe.pinned = 1;
- /*
- * Note: excluding the kernel makes the
- * (software) context-switch counter read 0...
- */
- if (pe.type != PERF_TYPE_SOFTWARE)
- {
- /* Exclude kernel and hypervisor */
- pe.exclude_kernel = 1;
- pe.exclude_hv = 1;
- }
-
- cpu = vm->cpu_id;
-
- fd = perf_event_open (&pe, 0, cpu, -1, 0);
- if (fd == -1)
- {
- clib_unix_warning ("event open: type %d config %d", c->pe_type,
- c->pe_config);
- return;
- }
-
- if (pe.type != PERF_TYPE_SOFTWARE)
- {
- p = mmap (0, pm->page_size, PROT_READ, MAP_SHARED, fd, 0);
- if (p == MAP_FAILED)
- {
- clib_unix_warning ("mmap");
- close (fd);
- return;
- }
- CLIB_MEM_UNPOISON (p, pm->page_size);
- }
- else
- p = 0;
-
- if (ioctl (fd, PERF_EVENT_IOC_RESET, 0) < 0)
- clib_unix_warning ("reset ioctl");
-
- if (ioctl (fd, PERF_EVENT_IOC_ENABLE, 0) < 0)
- clib_unix_warning ("enable ioctl");
-
- pt->perf_event_pages[i] = (void *) p;
- pt->pm_fds[i] = fd;
- }
-
- /*
- * Hardware events must be all opened and enabled before aquiring
- * pmc indices, otherwise the pmc indices might be out-dated.
- */
- for (i = 0; i < limit; i++)
- {
- p = (struct perf_event_mmap_page *) pt->perf_event_pages[i];
-
- /*
- * Software event counters - and others not capable of being
- * read via the "rdpmc" instruction - will be read
- * by system calls.
- */
- if (p == 0 || p->cap_user_rdpmc == 0)
- index = ~0;
- else
- index = p->index - 1;
-
- pt->rdpmc_indices[i] = index;
- }
-
- pm->n_active = i;
- /* Enable the main loop counter snapshot mechanism */
- clib_callback_data_add (&vm->vlib_node_runtime_perf_callbacks, cbdata);
-}
-
-static void
-disable_events (perfmon_main_t * pm)
-{
- vlib_main_t *vm = vlib_get_main ();
- u32 my_thread_index = vm->thread_index;
- perfmon_thread_t *pt = pm->threads[my_thread_index];
- int i;
-
- /* Stop main loop collection */
- clib_callback_data_remove (&vm->vlib_node_runtime_perf_callbacks,
- read_current_perf_counters);
-
- for (i = 0; i < pm->n_active; i++)
- {
- if (pt->pm_fds[i] == 0)
- continue;
-
- if (ioctl (pt->pm_fds[i], PERF_EVENT_IOC_DISABLE, 0) < 0)
- clib_unix_warning ("disable ioctl");
-
- if (pt->perf_event_pages[i])
- {
- if (munmap (pt->perf_event_pages[i], pm->page_size) < 0)
- clib_unix_warning ("munmap");
- pt->perf_event_pages[i] = 0;
- }
-
- (void) close (pt->pm_fds[i]);
- pt->pm_fds[i] = 0;
- }
-}
-
-static void
-worker_thread_start_event (vlib_main_t * vm)
-{
- perfmon_main_t *pm = &perfmon_main;
-
- clib_callback_enable_disable (vm->worker_thread_main_loop_callbacks,
- vm->worker_thread_main_loop_callback_tmp,
- vm->worker_thread_main_loop_callback_lock,
- worker_thread_start_event, 0 /* disable */ );
- enable_current_events (pm);
-}
-
-static void
-worker_thread_stop_event (vlib_main_t * vm)
-{
- perfmon_main_t *pm = &perfmon_main;
- clib_callback_enable_disable (vm->worker_thread_main_loop_callbacks,
- vm->worker_thread_main_loop_callback_tmp,
- vm->worker_thread_main_loop_callback_lock,
- worker_thread_stop_event, 0 /* disable */ );
- disable_events (pm);
-}
-
-static void
-start_event (perfmon_main_t * pm, f64 now, uword event_data)
-{
- int i;
- int last_set;
- int all = 0;
- pm->current_event = 0;
-
- if (vec_len (pm->single_events_to_collect) == 0)
- {
- pm->state = PERFMON_STATE_OFF;
- return;
- }
-
- last_set = clib_bitmap_last_set (pm->thread_bitmap);
- all = (last_set == ~0);
-
- pm->state = PERFMON_STATE_RUNNING;
- clear_counters (pm);
-
- /* Start collection on thread 0? */
- if (all || clib_bitmap_get (pm->thread_bitmap, 0))
- {
- /* Start collection on this thread */
- enable_current_events (pm);
- }
-
- /* And also on worker threads */
- for (i = 1; i < vec_len (vlib_mains); i++)
- {
- if (vlib_mains[i] == 0)
- continue;
-
- if (all || clib_bitmap_get (pm->thread_bitmap, i))
- clib_callback_enable_disable
- (vlib_mains[i]->worker_thread_main_loop_callbacks,
- vlib_mains[i]->worker_thread_main_loop_callback_tmp,
- vlib_mains[i]->worker_thread_main_loop_callback_lock,
- (void *) worker_thread_start_event, 1 /* enable */ );
- }
-}
-
-void
-scrape_and_clear_counters (perfmon_main_t * pm)
-{
- int i, j, k;
- vlib_main_t *vm = pm->vlib_main;
- vlib_main_t *stat_vm;
- vlib_node_main_t *nm;
- perfmon_counters_t *ctr;
- perfmon_counters_t *ctrs;
- perfmon_counters_t **ctr_dups = 0;
- perfmon_thread_t *pt;
- perfmon_capture_t *c;
- perfmon_event_config_t *current_event;
- uword *p;
- u8 *counter_name;
- u32 len;
-
- /* snapshoot the nodes, including pm counters */
- vlib_worker_thread_barrier_sync (vm);
-
- for (j = 0; j < vec_len (vlib_mains); j++)
- {
- stat_vm = vlib_mains[j];
- if (stat_vm == 0)
- continue;
-
- pt = pm->threads[j];
- len = vec_len (pt->counters);
- ctrs = 0;
- if (len)
- {
- vec_validate (ctrs, len - 1);
- clib_memcpy (ctrs, pt->counters, len * sizeof (pt->counters[0]));
- clib_memset (pt->counters, 0, len * sizeof (pt->counters[0]));
- }
- vec_add1 (ctr_dups, ctrs);
- }
-
- vlib_worker_thread_barrier_release (vm);
-
- for (j = 0; j < vec_len (vlib_mains); j++)
- {
- stat_vm = vlib_mains[j];
- if (stat_vm == 0)
- continue;
-
- pt = pm->threads[j];
- ctrs = ctr_dups[j];
-
- for (i = 0; i < vec_len (ctrs); i++)
- {
- u8 *capture_name;
-
- ctr = &ctrs[i];
- nm = &stat_vm->node_main;
-
- if (ctr->ticks[0] == 0 && ctr->ticks[1] == 0)
- continue;
-
- for (k = 0; k < 2; k++)
- {
- /*
- * We collect 2 counters at once, except for the
- * last counter when the user asks for an odd number of
- * counters
- */
- if ((pm->current_event + k)
- >= vec_len (pm->single_events_to_collect))
- break;
-
- capture_name = format (0, "t%d-%v%c", j, nm->nodes[i]->name, 0);
-
- p = hash_get_mem (pm->capture_by_thread_and_node_name,
- capture_name);
-
- if (p == 0)
- {
- pool_get (pm->capture_pool, c);
- memset (c, 0, sizeof (*c));
- c->thread_and_node_name = capture_name;
- hash_set_mem (pm->capture_by_thread_and_node_name,
- capture_name, c - pm->capture_pool);
- }
- else
- {
- c = pool_elt_at_index (pm->capture_pool, p[0]);
- vec_free (capture_name);
- }
-
- /* Snapshoot counters, etc. into the capture */
- current_event = pm->single_events_to_collect
- + pm->current_event + k;
- counter_name = (u8 *) current_event->name;
-
- vec_add1 (c->counter_names, counter_name);
- vec_add1 (c->counter_values, ctr->ticks[k]);
- vec_add1 (c->vectors_this_counter, ctr->vectors);
- }
- }
- vec_free (ctrs);
- }
- vec_free (ctr_dups);
-}
-
-static void
-handle_timeout (vlib_main_t * vm, perfmon_main_t * pm, f64 now)
-{
- int i;
- int last_set, all;
-
- last_set = clib_bitmap_last_set (pm->thread_bitmap);
- all = (last_set == ~0);
-
- if (all || clib_bitmap_get (pm->thread_bitmap, 0))
- disable_events (pm);
-
- /* And also on worker threads */
- for (i = 1; i < vec_len (vlib_mains); i++)
- {
- if (vlib_mains[i] == 0)
- continue;
- if (all || clib_bitmap_get (pm->thread_bitmap, i))
- clib_callback_enable_disable
- (vlib_mains[i]->worker_thread_main_loop_callbacks,
- vlib_mains[i]->worker_thread_main_loop_callback_tmp,
- vlib_mains[i]->worker_thread_main_loop_callback_lock,
- (void *) worker_thread_stop_event, 1 /* enable */ );
- }
-
- /* Make sure workers have stopped collection */
- if (i > 1)
- {
- f64 deadman = vlib_time_now (vm) + 1.0;
-
- for (i = 1; i < vec_len (vlib_mains); i++)
- {
- /* Has the worker actually stopped collecting data? */
- while (clib_callback_data_is_set
- (&vm->vlib_node_runtime_perf_callbacks,
- read_current_perf_counters))
- {
- if (vlib_time_now (vm) > deadman)
- {
- clib_warning ("Thread %d deadman timeout!", i);
- break;
- }
- vlib_process_suspend (pm->vlib_main, 1e-3);
- }
- }
- }
- scrape_and_clear_counters (pm);
- pm->current_event += pm->n_active;
- if (pm->current_event >= vec_len (pm->single_events_to_collect))
- {
- pm->current_event = 0;
- pm->state = PERFMON_STATE_OFF;
- return;
- }
-
- if (all || clib_bitmap_get (pm->thread_bitmap, 0))
- enable_current_events (pm);
-
- /* And also on worker threads */
- for (i = 1; i < vec_len (vlib_mains); i++)
- {
- if (vlib_mains[i] == 0)
- continue;
- if (all || clib_bitmap_get (pm->thread_bitmap, i))
- clib_callback_enable_disable
- (vlib_mains[i]->worker_thread_main_loop_callbacks,
- vlib_mains[i]->worker_thread_main_loop_callback_tmp,
- vlib_mains[i]->worker_thread_main_loop_callback_lock,
- worker_thread_start_event, 0 /* disable */ );
- }
-}
-
-static uword
-perfmon_periodic_process (vlib_main_t * vm,
- vlib_node_runtime_t * rt, vlib_frame_t * f)
-{
- perfmon_main_t *pm = &perfmon_main;
- f64 now;
- uword *event_data = 0;
- uword event_type;
- int i;
-
- while (1)
- {
- if (pm->state == PERFMON_STATE_RUNNING)
- vlib_process_wait_for_event_or_clock (vm, pm->timeout_interval);
- else
- vlib_process_wait_for_event (vm);
-
- now = vlib_time_now (vm);
-
- event_type = vlib_process_get_events (vm, (uword **) & event_data);
-
- switch (event_type)
- {
- case PERFMON_START:
- for (i = 0; i < vec_len (event_data); i++)
- start_event (pm, now, event_data[i]);
- break;
-
- /* Handle timeout */
- case ~0:
- handle_timeout (vm, pm, now);
- break;
-
- default:
- clib_warning ("Unexpected event %d", event_type);
- break;
- }
- vec_reset_length (event_data);
- }
- return 0; /* or not */
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (perfmon_periodic_node) =
-{
- .function = perfmon_periodic_process,
- .type = VLIB_NODE_TYPE_PROCESS,
- .name = "perfmon-periodic-process",
-};
-/* *INDENT-ON* */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */