From ede7143386ce1cf086066eec06dbdf7cf6d4cfee Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Thu, 30 Sep 2021 15:15:32 +0100 Subject: perfmon: bundles with multiple types Allow perfmon bundles to support more than one bundle type, either node or thread. Only used for topdown bundle for the moment. Type: improvement Signed-off-by: Ray Kinsella Change-Id: Iba3653a4deb39b0a8ee8ad448a7e8f954283ccd8 --- src/plugins/perfmon/cli.c | 111 +++++++++++++++++---- src/plugins/perfmon/intel/bundle/topdown_metrics.c | 4 +- src/plugins/perfmon/perfmon.c | 6 +- src/plugins/perfmon/perfmon.h | 61 +++++++++-- 4 files changed, 147 insertions(+), 35 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/perfmon/cli.c b/src/plugins/perfmon/cli.c index 2c0ff9e8a14..0d962dca554 100644 --- a/src/plugins/perfmon/cli.c +++ b/src/plugins/perfmon/cli.c @@ -37,6 +37,40 @@ unformat_perfmon_bundle_name (unformat_input_t *input, va_list *args) return p ? 1 : 0; } +uword +unformat_perfmon_active_type (unformat_input_t *input, va_list *args) +{ + perfmon_bundle_t *b = va_arg (*args, perfmon_bundle_t *); + perfmon_bundle_type_t *bundle_type = va_arg (*args, perfmon_bundle_type_t *); + char *str = 0; + + char *_str_types[PERFMON_BUNDLE_TYPE_MAX]; + +#define _(type, pstr) _str_types[type] = (char *) pstr; + + foreach_perfmon_bundle_type +#undef _ + + if (!b) return 0; + + if (unformat (input, "%s", &str) == 0) + return 0; + + for (int i = PERFMON_BUNDLE_TYPE_NODE; i < PERFMON_BUNDLE_TYPE_MAX; i++) + { + /* match the name and confirm it is available on this cpu */ + if (strncmp (str, _str_types[i], strlen (_str_types[i])) == 0 && + (b->type_flags & 1 << i)) + { + *bundle_type = i; + break; + } + } + + vec_free (str); + return bundle_type ? 1 : 0; +} + uword unformat_perfmon_source_name (unformat_input_t *input, va_list *args) { @@ -63,15 +97,17 @@ format_perfmon_bundle (u8 *s, va_list *args) perfmon_bundle_t *b = va_arg (*args, perfmon_bundle_t *); int verbose = va_arg (*args, int); - const char *bundle_type[] = { - [PERFMON_BUNDLE_TYPE_NODE] = "node", - [PERFMON_BUNDLE_TYPE_THREAD] = "thread", - [PERFMON_BUNDLE_TYPE_SYSTEM] = "system", - }; + int vl = 0; - if (b == 0) - return format (s, "%-20s%-10s%-20s%s", "Name", "Type", "Source", - "Description"); + u8 *_bundle_type = 0; + const char *bundle_type[PERFMON_BUNDLE_TYPE_MAX]; +#define _(type, pstr) bundle_type[type] = (const char *) pstr; + + foreach_perfmon_bundle_type +#undef _ + + if (b == 0) return format (s, "%-20s%-20s%-20s%s", "Name", "Type(s)", + "Source", "Description"); if (verbose) { @@ -85,8 +121,23 @@ format_perfmon_bundle (u8 *s, va_list *args) } } else - s = format (s, "%-20s%-10s%-20s%s", b->name, bundle_type[b->type], - b->src->name, b->description); + { + s = format (s, "%-20s", b->name); + for (int i = PERFMON_BUNDLE_TYPE_NODE; i < PERFMON_BUNDLE_TYPE_MAX; i++) + { + /* check the type is available on this uarch*/ + if (b->type_flags & 1 << i) + _bundle_type = format (_bundle_type, "%s,", bundle_type[i]); + } + /* remove any stray commas */ + if ((vl = vec_len (_bundle_type))) + _bundle_type[vl - 1] = 0; + + s = + format (s, "%-20s%-20s%s", _bundle_type, b->src->name, b->description); + } + + vec_free (_bundle_type); return s; } @@ -140,7 +191,7 @@ show_perfmon_bundle_command_fn (vlib_main_t *vm, unformat_input_t *input, for (int i = 0; i < vec_len (vb); i++) /* bundle type will be unknown if no cpu_supports matched */ - if (vb[i]->type != PERFMON_BUNDLE_TYPE_UNKNOWN) + if (vb[i]->type_flags) vlib_cli_output (vm, "%U\n", format_perfmon_bundle, vb[i], verbose); vec_free (vb); @@ -295,7 +346,8 @@ show_perfmon_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vec_validate (readings, n_instances - 1); /*Only perform read() for THREAD or SYSTEM bundles*/ - for (int i = 0; i < n_instances && b->type != PERFMON_BUNDLE_TYPE_NODE; i++) + for (int i = 0; + i < n_instances && b->active_type != PERFMON_BUNDLE_TYPE_NODE; i++) { in = vec_elt_at_index (it->instances, i); r = vec_elt_at_index (readings, i); @@ -324,8 +376,8 @@ show_perfmon_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, { in = vec_elt_at_index (it->instances, i); r = vec_elt_at_index (readings, i); - table_format_cell (t, col, -1, "%s", in->name, b->type); - if (b->type == PERFMON_BUNDLE_TYPE_NODE) + table_format_cell (t, col, -1, "%s", in->name, b->active_type); + if (b->active_type == PERFMON_BUNDLE_TYPE_NODE) { perfmon_thread_runtime_t *tr; tr = vec_elt_at_index (pm->thread_runtimes, i); @@ -334,20 +386,21 @@ show_perfmon_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, { perfmon_node_stats_t ns; table_format_cell (t, ++col, -1, "%U", format_vlib_node_name, - vm, j, b->type); + vm, j, b->active_type); table_set_cell_align (t, col, -1, TTAA_RIGHT); table_set_cell_fg_color (t, col, -1, TTAC_CYAN); clib_memcpy_fast (&ns, tr->node_stats + j, sizeof (ns)); for (int j = 0; j < n_row; j++) table_format_cell (t, col, j, "%U", b->format_fn, &ns, j, - b->type); + b->active_type); } } else { for (int j = 0; j < n_row; j++) - table_format_cell (t, i, j, "%U", b->format_fn, r, j, b->type); + table_format_cell (t, i, j, "%U", b->format_fn, r, j, + b->active_type); } col++; } @@ -393,6 +446,7 @@ perfmon_start_command_fn (vlib_main_t *vm, unformat_input_t *input, perfmon_main_t *pm = &perfmon_main; unformat_input_t _line_input, *line_input = &_line_input; perfmon_bundle_t *b = 0; + perfmon_bundle_type_t bundle_type = PERFMON_BUNDLE_TYPE_UNKNOWN; if (pm->is_running) return clib_error_return (0, "please stop first"); @@ -404,6 +458,9 @@ perfmon_start_command_fn (vlib_main_t *vm, unformat_input_t *input, { if (unformat (line_input, "bundle %U", unformat_perfmon_bundle_name, &b)) ; + else if (unformat (line_input, "type %U", unformat_perfmon_active_type, + b, &bundle_type)) + ; else return clib_error_return (0, "unknown input '%U'", format_unformat_error, line_input); @@ -413,12 +470,30 @@ perfmon_start_command_fn (vlib_main_t *vm, unformat_input_t *input, if (b == 0) return clib_error_return (0, "please specify bundle name"); + /* if there is more than one valid mode */ + if (count_set_bits (b->type_flags) > 1) + { + /* what did the user indicate */ + if (!bundle_type) + return clib_error_return (0, "please specify a valid type"); + } + else /* otherwise just use the default */ + { + if (bundle_type && !(b->type_flags & bundle_type)) + return clib_error_return (0, "please specify a valid type"); + + bundle_type = + (perfmon_bundle_type_t) count_trailing_zeros (b->type_flags); + } + + b->active_type = bundle_type; + return perfmon_start (vm, b); } VLIB_CLI_COMMAND (perfmon_start_command, static) = { .path = "perfmon start", - .short_help = "perfmon start bundle []", + .short_help = "perfmon start bundle [] type []", .function = perfmon_start_command_fn, .is_mp_safe = 1, }; diff --git a/src/plugins/perfmon/intel/bundle/topdown_metrics.c b/src/plugins/perfmon/intel/bundle/topdown_metrics.c index 6913781be90..6b95f553c65 100644 --- a/src/plugins/perfmon/intel/bundle/topdown_metrics.c +++ b/src/plugins/perfmon/intel/bundle/topdown_metrics.c @@ -104,10 +104,8 @@ format_topdown_lvl1 (u8 *s, va_list *args) } static perfmon_cpu_supports_t topdown_lvl1_cpu_supports[] = { - /* Intel SNR supports papi/thread only */ - { clib_cpu_supports_movdiri, PERFMON_BUNDLE_TYPE_THREAD }, /* Intel ICX supports papi/thread or rdpmc/node */ - { clib_cpu_supports_avx512_bitalg, PERFMON_BUNDLE_TYPE_NODE } + { clib_cpu_supports_avx512_bitalg, PERFMON_BUNDLE_TYPE_NODE_OR_THREAD } }; PERFMON_REGISTER_BUNDLE (topdown_lvl1_metric) = { diff --git a/src/plugins/perfmon/perfmon.c b/src/plugins/perfmon/perfmon.c index 46c8cf9ca04..8abce94910f 100644 --- a/src/plugins/perfmon/perfmon.c +++ b/src/plugins/perfmon/perfmon.c @@ -97,7 +97,7 @@ perfmon_set (vlib_main_t *vm, perfmon_bundle_t *b) s = b->src; ASSERT (b->n_events); - if (b->type == PERFMON_BUNDLE_TYPE_NODE) + if (b->active_type == PERFMON_BUNDLE_TYPE_NODE) is_node = 1; if (s->instances_by_type == 0) @@ -236,7 +236,7 @@ perfmon_start (vlib_main_t *vm, perfmon_bundle_t *b) return clib_error_return_unix (0, "ioctl(PERF_EVENT_IOC_ENABLE)"); } } - if (b->type == PERFMON_BUNDLE_TYPE_NODE) + if (b->active_type == PERFMON_BUNDLE_TYPE_NODE) { vlib_node_function_t *funcs[PERFMON_OFFSET_TYPE_MAX]; @@ -267,7 +267,7 @@ perfmon_stop (vlib_main_t *vm) if (pm->is_running != 1) return clib_error_return (0, "not running"); - if (pm->active_bundle->type == PERFMON_BUNDLE_TYPE_NODE) + if (pm->active_bundle->active_type == PERFMON_BUNDLE_TYPE_NODE) { for (int i = 0; i < vlib_get_n_threads (); i++) vlib_node_set_dispatch_wrapper (vlib_get_main_by_index (i), 0); diff --git a/src/plugins/perfmon/perfmon.h b/src/plugins/perfmon/perfmon.h index ffcf2fd5e46..f9b9070d077 100644 --- a/src/plugins/perfmon/perfmon.h +++ b/src/plugins/perfmon/perfmon.h @@ -32,8 +32,23 @@ typedef enum PERFMON_BUNDLE_TYPE_THREAD, PERFMON_BUNDLE_TYPE_SYSTEM, PERFMON_BUNDLE_TYPE_MAX, + PERFMON_BUNDLE_TYPE_NODE_OR_THREAD, } perfmon_bundle_type_t; +#define foreach_perfmon_bundle_type \ + _ (PERFMON_BUNDLE_TYPE_UNKNOWN, "not supported") \ + _ (PERFMON_BUNDLE_TYPE_NODE, "node") \ + _ (PERFMON_BUNDLE_TYPE_THREAD, "thread") \ + _ (PERFMON_BUNDLE_TYPE_SYSTEM, "system") + +typedef enum +{ +#define _(e, str) e##_FLAG = 1 << e, + foreach_perfmon_bundle_type +#undef _ + +} perfmon_bundle_type_flag_t; + typedef enum { PERFMON_OFFSET_TYPE_MMAP, @@ -108,7 +123,14 @@ typedef struct perfmon_bundle char *description; char *source; char *footer; - perfmon_bundle_type_t type; + + union + { + perfmon_bundle_type_flag_t type_flags; + perfmon_bundle_type_t type; + }; + perfmon_bundle_type_t active_type; + perfmon_offset_type_t offset_type; u32 events[PERF_MAX_EVENTS]; u32 n_events; @@ -179,23 +201,40 @@ typedef struct extern perfmon_main_t perfmon_main; +#define PERFMON_BUNDLE_TYPE_TO_FLAGS(type) \ + ({ \ + uword rtype = 0; \ + if (type == PERFMON_BUNDLE_TYPE_NODE_OR_THREAD) \ + rtype = \ + 1 << PERFMON_BUNDLE_TYPE_THREAD | 1 << PERFMON_BUNDLE_TYPE_NODE; \ + else \ + rtype = 1 << type; \ + rtype; \ + }) + always_inline uword -perfmon_cpu_supported_bundle_type (perfmon_bundle_t *b) +perfmon_cpu_update_bundle_type (perfmon_bundle_t *b) { perfmon_cpu_supports_t *supports = b->cpu_supports; uword type = 0; - /* if nothing specific for this bundle, go with the default */ - if (!supports) - return b->type; + /* either supports or b->type should be set, but not both */ + ASSERT (!!supports ^ !!b->type); - /* the last specified type, will always win */ - for (int i = 0; i < b->n_cpu_supports; ++i) - if (supports[i].cpu_supports ()) - type = supports[i].bundle_type; + /* if nothing specific for this bundle, go with the defaults */ + if (!supports) + type = PERFMON_BUNDLE_TYPE_TO_FLAGS (b->type); + else + { + /* more than one type may be supported by a given bundle */ + for (int i = 0; i < b->n_cpu_supports; ++i) + if (supports[i].cpu_supports ()) + type |= PERFMON_BUNDLE_TYPE_TO_FLAGS (supports[i].bundle_type); + } return type; } +#undef PERFMON_BUNDLE_TYPE_TO_FLAGS #define PERFMON_REGISTER_SOURCE(x) \ perfmon_source_t __perfmon_source_##x; \ @@ -213,8 +252,8 @@ perfmon_cpu_supported_bundle_type (perfmon_bundle_t *b) { \ perfmon_main_t *pm = &perfmon_main; \ __perfmon_bundle_##x.next = pm->bundles; \ - __perfmon_bundle_##x.type = \ - perfmon_cpu_supported_bundle_type (&__perfmon_bundle_##x); \ + __perfmon_bundle_##x.type_flags = \ + perfmon_cpu_update_bundle_type (&__perfmon_bundle_##x); \ pm->bundles = &__perfmon_bundle_##x; \ } \ perfmon_bundle_t __perfmon_bundle_##x -- cgit 1.2.3-korg