X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fperfmon%2Fperfmon.c;h=0643384957e6571c95a4fb448c3cc342cfc3670b;hb=c7d43a5eb19f2acab900274432cfd0e136d6cb44;hp=4cd4f94fda8996eb287e0e9d4a2e254d902e4ce4;hpb=47d165e4c1a5f571995d39b0ce142c06f17dea47;p=vpp.git diff --git a/src/plugins/perfmon/perfmon.c b/src/plugins/perfmon/perfmon.c index 4cd4f94fda8..0643384957e 100644 --- a/src/plugins/perfmon/perfmon.c +++ b/src/plugins/perfmon/perfmon.c @@ -1,7 +1,5 @@ /* - * perfmon.c - skeleton vpp engine plug-in - * - * Copyright (c) + * Copyright (c) 2020 Cisco and/or its affiliates. * 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: @@ -16,623 +14,347 @@ */ #include -#include -#include -#include #include #include +#include #include #include +#include -perfmon_main_t perfmon_main; +#include -void -perfmon_register_intel_pmc (perfmon_intel_pmc_cpu_model_t * m, int n_models, - perfmon_intel_pmc_event_t * e, int n_events) -{ - perfmon_main_t *pm = &perfmon_main; - perfmon_intel_pmc_registration_t r; +perfmon_main_t perfmon_main; - r.events = e; - r.models = m; - r.n_events = n_events; - r.n_models = n_models; +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "Performance Monitor", +}; - vec_add1 (pm->perfmon_tables, r); -} +VLIB_REGISTER_LOG_CLASS (if_default_log, static) = { + .class_name = "perfmon", +}; -static inline u32 -get_cpuid (void) -{ -#if defined(__x86_64__) - u32 cpuid; - asm volatile ("mov $1, %%eax; cpuid; mov %%eax, %0":"=r" (cpuid)::"%eax", - "%edx", "%ecx", "%rbx"); - return cpuid; -#else - return 0; -#endif -} +#define log_debug(fmt, ...) \ + vlib_log_debug (if_default_log.class, fmt, __VA_ARGS__) +#define log_warn(fmt, ...) \ + vlib_log_warn (if_default_log.class, fmt, __VA_ARGS__) +#define log_err(fmt, ...) vlib_log_err (if_default_log.class, fmt, __VA_ARGS__) -static int -perfmon_cpu_model_matches (perfmon_intel_pmc_cpu_model_t * mt, - u32 n_models, u8 model, u8 stepping) +void +perfmon_reset (vlib_main_t *vm) { - u32 i; - for (i = 0; i < n_models; i++) - { - if (mt[i].model != model) - continue; + perfmon_main_t *pm = &perfmon_main; + uword page_size = clib_mem_get_page_size (); - if (mt[i].has_stepping) - { - if (mt[i].stepping != stepping) - continue; - } + if (pm->is_running) + for (int i = 0; i < vlib_get_n_threads (); i++) + vlib_node_set_dispatch_wrapper (vlib_get_main_by_index (i), 0); - return 1; + for (int i = 0; i < vec_len (pm->fds_to_close); i++) + close (pm->fds_to_close[i]); + vec_free (pm->fds_to_close); + vec_free (pm->group_fds); + if (pm->default_instance_type) + { + perfmon_instance_type_t *it = pm->default_instance_type; + for (int i = 0; i < vec_len (it->instances); i++) + vec_free (it->instances[i].name); + vec_free (it->instances); + vec_free (pm->default_instance_type); } - return 0; -} -static perfmon_intel_pmc_event_t * -perfmon_find_table_by_model_stepping (perfmon_main_t * pm, - u8 model, u8 stepping) -{ - perfmon_intel_pmc_registration_t *rt; + for (int i = 0; i < vec_len (pm->thread_runtimes); i++) + { + perfmon_thread_runtime_t *tr = vec_elt_at_index (pm->thread_runtimes, i); + vec_free (tr->node_stats); + for (int j = 0; j < PERF_MAX_EVENTS; j++) + if (tr->mmap_pages[j]) + munmap (tr->mmap_pages[j], page_size); + } + vec_free (pm->thread_runtimes); - vec_foreach (rt, pm->perfmon_tables) - { - if (perfmon_cpu_model_matches (rt->models, rt->n_models, model, stepping)) - return rt->events; - } - return 0; + pm->is_running = 0; + pm->active_instance_type = 0; + pm->active_bundle = 0; } static clib_error_t * -perfmon_init (vlib_main_t * vm) +perfmon_set (vlib_main_t *vm, perfmon_bundle_t *b) { + clib_error_t *err = 0; perfmon_main_t *pm = &perfmon_main; - clib_error_t *error = 0; - u32 cpuid; - u8 model, stepping; - perfmon_intel_pmc_event_t *ev; - - pm->vlib_main = vm; - pm->vnet_main = vnet_get_main (); - - pm->capture_by_thread_and_node_name = - hash_create_string (0, sizeof (uword)); - - pm->log_class = vlib_log_register_class ("perfmon", 0); - - /* Default data collection interval */ - pm->timeout_interval = 2.0; /* seconds */ - vec_validate (pm->pm_fds, 1); - vec_validate (pm->pm_fds[0], vec_len (vlib_mains) - 1); - vec_validate (pm->pm_fds[1], vec_len (vlib_mains) - 1); - vec_validate (pm->perf_event_pages, 1); - vec_validate (pm->perf_event_pages[0], vec_len (vlib_mains) - 1); - vec_validate (pm->perf_event_pages[1], vec_len (vlib_mains) - 1); - vec_validate (pm->rdpmc_indices, 1); - vec_validate (pm->rdpmc_indices[0], vec_len (vlib_mains) - 1); - vec_validate (pm->rdpmc_indices[1], vec_len (vlib_mains) - 1); - pm->page_size = getpagesize (); - - pm->perfmon_table = 0; - pm->pmc_event_by_name = 0; - - cpuid = get_cpuid (); - model = ((cpuid >> 12) & 0xf0) | ((cpuid >> 4) & 0xf); - stepping = cpuid & 0xf; - - pm->perfmon_table = perfmon_find_table_by_model_stepping (pm, - model, stepping); - - if (pm->perfmon_table == 0) + perfmon_source_t *s; + int is_node = 0; + int n_nodes = vec_len (vm->node_main.nodes); + uword page_size = clib_mem_get_page_size (); + u32 instance_type = 0; + perfmon_event_t *e; + perfmon_instance_type_t *it = 0; + + perfmon_reset (vm); + + s = b->src; + ASSERT (b->n_events); + + if (b->active_type == PERFMON_BUNDLE_TYPE_NODE) + is_node = 1; + + if (s->instances_by_type == 0) { - vlib_log_err (pm->log_class, "No table for cpuid %x", cpuid); - vlib_log_err (pm->log_class, " model %x, stepping %x", - model, stepping); + vec_add2 (pm->default_instance_type, it, 1); + it->name = is_node ? "Thread/Node" : "Thread"; + for (int i = 0; i < vlib_get_n_threads (); i++) + { + vlib_worker_thread_t *w = vlib_worker_threads + i; + perfmon_instance_t *in; + vec_add2 (it->instances, in, 1); + in->cpu = w->cpu_id; + in->pid = w->lwp; + in->name = (char *) format (0, "%s (%u)%c", w->name, i, 0); + } + if (is_node) + vec_validate (pm->thread_runtimes, vlib_get_n_threads () - 1); } else { - pm->pmc_event_by_name = hash_create_string (0, sizeof (u32)); - ev = pm->perfmon_table; + e = s->events + b->events[0]; - for (; ev->event_name; ev++) + if (e->type_from_instance) { - hash_set_mem (pm->pmc_event_by_name, ev->event_name, - ev - pm->perfmon_table); + instance_type = e->instance_type; + for (int i = 1; i < b->n_events; i++) + { + e = s->events + b->events[i]; + ASSERT (e->type_from_instance == 1 && + e->instance_type == instance_type); + } } + it = vec_elt_at_index (s->instances_by_type, instance_type); } - return error; -} - -VLIB_INIT_FUNCTION (perfmon_init); - -/* *INDENT-OFF* */ -VLIB_PLUGIN_REGISTER () = -{ - .version = VPP_BUILD_VER, - .description = "Performance monitor plugin", -#if !defined(__x86_64__) - .default_disabled = 1, -#endif -}; -/* *INDENT-ON* */ - -static uword -unformat_processor_event (unformat_input_t * input, va_list * args) -{ - perfmon_main_t *pm = va_arg (*args, perfmon_main_t *); - perfmon_event_config_t *ep = va_arg (*args, perfmon_event_config_t *); - u8 *s = 0; - hash_pair_t *hp; - u32 idx; - u32 pe_config = 0; - - if (pm->perfmon_table == 0 || pm->pmc_event_by_name == 0) - return 0; - - if (!unformat (input, "%s", &s)) - return 0; - - hp = hash_get_pair_mem (pm->pmc_event_by_name, s); + pm->active_instance_type = it; - vec_free (s); - - if (hp == 0) - return 0; - - idx = (u32) (hp->value[0]); - - pe_config |= pm->perfmon_table[idx].event_code[0]; - pe_config |= pm->perfmon_table[idx].umask << 8; + for (int i = 0; i < vec_len (it->instances); i++) + { + perfmon_instance_t *in = vec_elt_at_index (it->instances, i); - ep->name = (char *) hp->key; - ep->pe_type = PERF_TYPE_RAW; - ep->pe_config = pe_config; - return 1; -} + vec_validate (pm->group_fds, i); + pm->group_fds[i] = -1; -static clib_error_t * -set_pmc_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - perfmon_main_t *pm = &perfmon_main; - vlib_thread_main_t *vtm = vlib_get_thread_main (); - int num_threads = 1 + vtm->n_threads; - unformat_input_t _line_input, *line_input = &_line_input; - perfmon_event_config_t ec; - f64 delay; - u32 timeout_seconds; - u32 deadman; - int last_set; - clib_error_t *error; - - vec_reset_length (pm->single_events_to_collect); - vec_reset_length (pm->paired_events_to_collect); - pm->ipc_event_index = ~0; - pm->mispredict_event_index = ~0; - - if (!unformat_user (input, unformat_line_input, line_input)) - return clib_error_return (0, "counter names required..."); - - clib_bitmap_zero (pm->thread_bitmap); - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "timeout %u", &timeout_seconds)) - pm->timeout_interval = (f64) timeout_seconds; - else if (unformat (line_input, "instructions-per-clock")) + for (int j = 0; j < b->n_events; j++) { - ec.name = "instructions"; - ec.pe_type = PERF_TYPE_HARDWARE; - ec.pe_config = PERF_COUNT_HW_INSTRUCTIONS; - pm->ipc_event_index = vec_len (pm->paired_events_to_collect); - vec_add1 (pm->paired_events_to_collect, ec); - ec.name = "cpu-cycles"; - ec.pe_type = PERF_TYPE_HARDWARE; - ec.pe_config = PERF_COUNT_HW_CPU_CYCLES; - vec_add1 (pm->paired_events_to_collect, ec); + int fd; + perfmon_event_t *e = s->events + b->events[j]; + struct perf_event_attr pe = { + .size = sizeof (struct perf_event_attr), + .type = e->type_from_instance ? in->type : e->type, + .config = e->config, + .exclude_kernel = e->exclude_kernel, + .read_format = + (PERF_FORMAT_GROUP | PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING), + .disabled = 1, + }; + + log_debug ("perf_event_open pe.type=%u pe.config=0x%x pid=%d " + "cpu=%d group_fd=%d", + pe.type, pe.config, in->pid, in->cpu, pm->group_fds[i]); + fd = syscall (__NR_perf_event_open, &pe, in->pid, in->cpu, + pm->group_fds[i], 0); + + if (fd == -1) + { + err = clib_error_return_unix (0, "perf_event_open"); + goto error; + } + + vec_add1 (pm->fds_to_close, fd); + + if (pm->group_fds[i] == -1) + pm->group_fds[i] = fd; + + if (is_node) + { + perfmon_thread_runtime_t *tr; + tr = vec_elt_at_index (pm->thread_runtimes, i); + tr->mmap_pages[j] = + mmap (0, page_size, PROT_READ, MAP_SHARED, fd, 0); + + if (tr->mmap_pages[j] == MAP_FAILED) + { + err = clib_error_return_unix (0, "mmap"); + goto error; + } + } } - else if (unformat (line_input, "branch-mispredict-rate")) - { - ec.name = "branch-misses"; - ec.pe_type = PERF_TYPE_HARDWARE; - ec.pe_config = PERF_COUNT_HW_BRANCH_MISSES; - pm->mispredict_event_index = vec_len (pm->paired_events_to_collect); - vec_add1 (pm->paired_events_to_collect, ec); - ec.name = "branches"; - ec.pe_type = PERF_TYPE_HARDWARE; - ec.pe_config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; - vec_add1 (pm->paired_events_to_collect, ec); - } - else if (unformat (line_input, "threads %U", - unformat_bitmap_list, &pm->thread_bitmap)) - ; - else if (unformat (line_input, "thread %U", - unformat_bitmap_list, &pm->thread_bitmap)) - ; - else if (unformat (line_input, "%U", unformat_processor_event, pm, &ec)) - { - vec_add1 (pm->single_events_to_collect, ec); - } -#define _(type,event,str) \ - else if (unformat (line_input, str)) \ - { \ - ec.name = str; \ - ec.pe_type = type; \ - ec.pe_config = event; \ - vec_add1 (pm->single_events_to_collect, ec); \ - } - foreach_perfmon_event -#undef _ - else + + if (is_node) { - error = clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); - unformat_free (line_input); - return error; + perfmon_thread_runtime_t *rt; + rt = vec_elt_at_index (pm->thread_runtimes, i); + rt->bundle = b; + rt->n_events = b->n_events; + rt->n_nodes = n_nodes; + rt->preserve_samples = b->preserve_samples; + vec_validate_aligned (rt->node_stats, n_nodes - 1, + CLIB_CACHE_LINE_BYTES); } } - unformat_free (line_input); - - last_set = clib_bitmap_last_set (pm->thread_bitmap); - if (last_set != ~0 && last_set >= num_threads) - return clib_error_return (0, "thread %d does not exist", last_set); - - /* Stick paired events at the front of the (unified) list */ - if (vec_len (pm->paired_events_to_collect) > 0) - { - perfmon_event_config_t *tmp; - /* first 2n events are pairs... */ - vec_append (pm->paired_events_to_collect, pm->single_events_to_collect); - tmp = pm->single_events_to_collect; - pm->single_events_to_collect = pm->paired_events_to_collect; - pm->paired_events_to_collect = tmp; - } - - if (vec_len (pm->single_events_to_collect) == 0) - return clib_error_return (0, "no events specified..."); - - /* Figure out how long data collection will take */ - delay = - ((f64) vec_len (pm->single_events_to_collect)) * pm->timeout_interval; - delay /= 2.0; /* collect 2 stats at once */ - - vlib_cli_output (vm, "Start collection for %d events, wait %.2f seconds", - vec_len (pm->single_events_to_collect), delay); - - vlib_process_signal_event (pm->vlib_main, perfmon_periodic_node.index, - PERFMON_START, 0); - - /* Coarse-grained wait */ - vlib_process_suspend (vm, delay); + pm->active_bundle = b; - deadman = 0; - /* Reasonable to guess that collection may not be quite done... */ - while (pm->state == PERFMON_STATE_RUNNING) +error: + if (err) { - vlib_process_suspend (vm, 10e-3); - if (deadman++ > 200) - { - vlib_cli_output (vm, "DEADMAN: collection still running..."); - break; - } + log_err ("%U", format_clib_error, err); + perfmon_reset (vm); } - - vlib_cli_output (vm, "Data collection complete..."); - return 0; + return err; } -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (set_pmc_command, static) = +clib_error_t * +perfmon_start (vlib_main_t *vm, perfmon_bundle_t *b) { - .path = "set pmc", - .short_help = "set pmc [threads n,n1-n2] c1... [see \"show pmc events\"]", - .function = set_pmc_command_fn, - .is_mp_safe = 1, -}; -/* *INDENT-ON* */ - -static int -capture_name_sort (void *a1, void *a2) -{ - perfmon_capture_t *c1 = a1; - perfmon_capture_t *c2 = a2; + clib_error_t *err = 0; + perfmon_main_t *pm = &perfmon_main; + int n_groups; - return strcmp ((char *) c1->thread_and_node_name, - (char *) c2->thread_and_node_name); -} + if (pm->is_running == 1) + return clib_error_return (0, "already running"); -static u8 * -format_capture (u8 * s, va_list * args) -{ - perfmon_main_t *pm = va_arg (*args, perfmon_main_t *); - perfmon_capture_t *c = va_arg (*args, perfmon_capture_t *); - int verbose __attribute__ ((unused)) = va_arg (*args, int); - f64 ticks_per_pkt; - int i; + if ((err = perfmon_set (vm, b)) != 0) + return err; - if (c == 0) - { - s = format (s, "%=40s%=20s%=16s%=16s%=16s", - "Name", "Counter", "Count", "Pkts", "Counts/Pkt"); - return s; - } + n_groups = vec_len (pm->group_fds); - for (i = 0; i < vec_len (c->counter_names); i++) + for (int i = 0; i < n_groups; i++) { - u8 *name; - - if (i == 0) - name = c->thread_and_node_name; - else + if (ioctl (pm->group_fds[i], PERF_EVENT_IOC_ENABLE, + PERF_IOC_FLAG_GROUP) == -1) { - vec_add1 (s, '\n'); - name = (u8 *) ""; + perfmon_reset (vm); + return clib_error_return_unix (0, "ioctl(PERF_EVENT_IOC_ENABLE)"); } - - /* Deal with synthetic events right here */ - if (i == pm->ipc_event_index) - { - f64 ipc_rate; - ASSERT ((i + 1) < vec_len (c->counter_names)); - - if (c->counter_values[i + 1] > 0) - ipc_rate = (f64) c->counter_values[i] - / (f64) c->counter_values[i + 1]; - else - ipc_rate = 0.0; - - s = format (s, "%-40s%+20s%+16llu%+16llu%+16.2e\n", - name, "instructions-per-clock", - c->counter_values[i], - c->counter_values[i + 1], ipc_rate); - name = (u8 *) ""; - } - - if (i == pm->mispredict_event_index) + } + if (b->active_type == PERFMON_BUNDLE_TYPE_NODE) + { + vlib_node_function_t *dispatch_wrapper = NULL; + err = b->src->config_dispatch_wrapper (b, &dispatch_wrapper); + if (err || !dispatch_wrapper) { - f64 mispredict_rate; - ASSERT (i + 1 < vec_len (c->counter_names)); - - if (c->counter_values[i + 1] > 0) - mispredict_rate = (f64) c->counter_values[i] - / (f64) c->counter_values[i + 1]; - else - mispredict_rate = 0.0; - - s = format (s, "%-40s%+20s%+16llu%+16llu%+16.2e\n", - name, "branch-mispredict-rate", - c->counter_values[i], - c->counter_values[i + 1], mispredict_rate); - name = (u8 *) ""; + perfmon_reset (vm); + return err; } - if (c->vectors_this_counter[i]) - ticks_per_pkt = - ((f64) c->counter_values[i]) / ((f64) c->vectors_this_counter[i]); - else - ticks_per_pkt = 0.0; - - s = format (s, "%-40s%+20s%+16llu%+16llu%+16.2e", - name, c->counter_names[i], - c->counter_values[i], - c->vectors_this_counter[i], ticks_per_pkt); + for (int i = 0; i < vlib_get_n_threads (); i++) + vlib_node_set_dispatch_wrapper (vlib_get_main_by_index (i), + dispatch_wrapper); } - return s; -} + pm->sample_time = vlib_time_now (vm); + pm->is_running = 1; -static u8 * -format_generic_events (u8 * s, va_list * args) -{ - int verbose = va_arg (*args, int); - -#define _(type,config,name) \ - if (verbose == 0) \ - s = format (s, "\n %s", name); \ - else \ - s = format (s, "\n %s (%d, %d)", name, type, config); - foreach_perfmon_event; -#undef _ - return s; -} - -typedef struct -{ - u8 *name; - u32 index; -} sort_nvp_t; - -static int -sort_nvps_by_name (void *a1, void *a2) -{ - sort_nvp_t *nvp1 = a1; - sort_nvp_t *nvp2 = a2; - - return strcmp ((char *) nvp1->name, (char *) nvp2->name); + return 0; } -static u8 * -format_pmc_event (u8 * s, va_list * args) +clib_error_t * +perfmon_stop (vlib_main_t *vm) { - perfmon_intel_pmc_event_t *ev = va_arg (*args, perfmon_intel_pmc_event_t *); - - s = format (s, "%s\n", ev->event_name); - s = format (s, " umask: 0x%x\n", ev->umask); - s = format (s, " code: 0x%x", ev->event_code[0]); - - if (ev->event_code[1]) - s = format (s, " , 0x%x\n", ev->event_code[1]); - else - s = format (s, "\n"); + perfmon_main_t *pm = &perfmon_main; + int n_groups = vec_len (pm->group_fds); - return s; -} + if (pm->is_running != 1) + return clib_error_return (0, "not running"); -static u8 * -format_processor_events (u8 * s, va_list * args) -{ - perfmon_main_t *pm = va_arg (*args, perfmon_main_t *); - int verbose = va_arg (*args, int); - sort_nvp_t *sort_nvps = 0; - sort_nvp_t *sn; - u8 *key; - u32 value; - - /* *INDENT-OFF* */ - hash_foreach_mem (key, value, pm->pmc_event_by_name, - ({ - vec_add2 (sort_nvps, sn, 1); - sn->name = key; - sn->index = value; - })); - - vec_sort_with_function (sort_nvps, sort_nvps_by_name); - - if (verbose == 0) + if (pm->active_bundle->active_type == PERFMON_BUNDLE_TYPE_NODE) { - vec_foreach (sn, sort_nvps) - s = format (s, "\n %s ", sn->name); + for (int i = 0; i < vlib_get_n_threads (); i++) + vlib_node_set_dispatch_wrapper (vlib_get_main_by_index (i), 0); } - else + + for (int i = 0; i < n_groups; i++) { - vec_foreach (sn, sort_nvps) - s = format(s, "%U", format_pmc_event, &pm->perfmon_table[sn->index]); + if (ioctl (pm->group_fds[i], PERF_EVENT_IOC_DISABLE, + PERF_IOC_FLAG_GROUP) == -1) + { + perfmon_reset (vm); + return clib_error_return_unix (0, "ioctl(PERF_EVENT_IOC_DISABLE)"); + } } - vec_free (sort_nvps); - return s; -} + pm->is_running = 0; + pm->sample_time = vlib_time_now (vm) - pm->sample_time; + return 0; +} static clib_error_t * -show_pmc_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +perfmon_init (vlib_main_t *vm) { perfmon_main_t *pm = &perfmon_main; - int verbose = 0; - int events = 0; - int i; - perfmon_capture_t *c; - perfmon_capture_t *captures = 0; + perfmon_source_t *s = pm->sources; + perfmon_bundle_t *b = pm->bundles; - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + pm->source_by_name = hash_create_string (0, sizeof (uword)); + while (s) { - if (unformat (input, "events")) - events = 1; - else if (unformat (input, "verbose")) - verbose = 1; - else - break; - } - - if (events) - { - vlib_cli_output (vm, "Generic Events %U", - format_generic_events, verbose); - vlib_cli_output (vm, "Synthetic Events"); - vlib_cli_output (vm, " instructions-per-clock"); - vlib_cli_output (vm, " branch-mispredict-rate"); - if (pm->perfmon_table) - vlib_cli_output (vm, "Processor Events %U", - format_processor_events, pm, verbose); - return 0; - } + clib_error_t *err; + if (hash_get_mem (pm->source_by_name, s->name) != 0) + clib_panic ("duplicate source name '%s'", s->name); + if (s->init_fn && ((err = (s->init_fn) (vm, s)))) + { + log_warn ("skipping source '%s' - %U", s->name, format_clib_error, + err); + clib_error_free (err); + s = s->next; + continue; + } - if (pm->state == PERFMON_STATE_RUNNING) - { - vlib_cli_output (vm, "Data collection in progress..."); - return 0; + hash_set_mem (pm->source_by_name, s->name, s); + log_debug ("source '%s' registered", s->name); + s = s->next; } - if (pool_elts (pm->capture_pool) == 0) + pm->bundle_by_name = hash_create_string (0, sizeof (uword)); + while (b) { - vlib_cli_output (vm, "No data..."); - return 0; - } - - /* *INDENT-OFF* */ - pool_foreach (c, pm->capture_pool, - ({ - vec_add1 (captures, *c); - })); - /* *INDENT-ON* */ + clib_error_t *err; + uword *p; - vec_sort_with_function (captures, capture_name_sort); - - vlib_cli_output (vm, "%U", format_capture, pm, 0 /* header */ , - 0 /* verbose */ ); - - for (i = 0; i < vec_len (captures); i++) - { - c = captures + i; - - vlib_cli_output (vm, "%U", format_capture, pm, c, verbose); - } + if ((p = hash_get_mem (pm->source_by_name, b->source)) == 0) + { + log_debug ("missing source '%s', skipping bundle '%s'", b->source, + b->name); + b = b->next; + continue; + } - vec_free (captures); + b->src = (perfmon_source_t *) p[0]; + if (b->src->bundle_support && !b->src->bundle_support (b)) + { + log_debug ("skipping bundle '%s' - not supported", b->name); + b = b->next; + continue; + } - return 0; -} + if (b->init_fn && ((err = (b->init_fn) (vm, b)))) + { + log_warn ("skipping bundle '%s' - %U", b->name, format_clib_error, + err); + clib_error_free (err); + b = b->next; + continue; + } -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_pmc_command, static) = -{ - .path = "show pmc", - .short_help = "show pmc [verbose]", - .function = show_pmc_command_fn, - .is_mp_safe = 1, -}; -/* *INDENT-ON* */ + if (hash_get_mem (pm->bundle_by_name, b->name) != 0) + clib_panic ("duplicate bundle name '%s'", b->name); -static clib_error_t * -clear_pmc_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - perfmon_main_t *pm = &perfmon_main; - u8 *key; - u32 *value; + hash_set_mem (pm->bundle_by_name, b->name, b); + log_debug ("bundle '%s' registered", b->name); - if (pm->state == PERFMON_STATE_RUNNING) - { - vlib_cli_output (vm, "Performance monitor is still running..."); - return 0; + b = b->next; } - pool_free (pm->capture_pool); - - /* *INDENT-OFF* */ - hash_foreach_mem (key, value, pm->capture_by_thread_and_node_name, - ({ - vec_free (key); - })); - /* *INDENT-ON* */ - hash_free (pm->capture_by_thread_and_node_name); - pm->capture_by_thread_and_node_name = - hash_create_string (0, sizeof (uword)); return 0; } -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (clear_pmc_command, static) = -{ - .path = "clear pmc", - .short_help = "clear the performance monitor counters", - .function = clear_pmc_command_fn, -}; -/* *INDENT-ON* */ - - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ +VLIB_INIT_FUNCTION (perfmon_init);