summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRay Kinsella <mdr@ashroe.eu>2021-09-30 15:15:32 +0100
committerDamjan Marion <dmarion@me.com>2021-10-05 10:44:39 +0000
commitede7143386ce1cf086066eec06dbdf7cf6d4cfee (patch)
tree9e6aad9d33551c9abf8813b52f449d0919f849d0
parent4189108e1dbac0a7961d31d59a21b7fe8354ce61 (diff)
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 <mdr@ashroe.eu> Change-Id: Iba3653a4deb39b0a8ee8ad448a7e8f954283ccd8
-rw-r--r--src/plugins/perfmon/cli.c111
-rw-r--r--src/plugins/perfmon/intel/bundle/topdown_metrics.c4
-rw-r--r--src/plugins/perfmon/perfmon.c6
-rw-r--r--src/plugins/perfmon/perfmon.h61
4 files changed, 147 insertions, 35 deletions
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
@@ -38,6 +38,40 @@ unformat_perfmon_bundle_name (unformat_input_t *input, va_list *args)
}
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)
{
perfmon_main_t *pm = &perfmon_main;
@@ -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 [<bundle-name>]",
+ .short_help = "perfmon start bundle [<bundle-name>] type [<node|thread>]",
.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