perf jevents: Add support for metricgroup descriptions

Metrics have a field where the groups they belong to are listed like
the following from
tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json:

        "MetricGroup": "PGO;TmaL1;TopdownL1;tma_L1_group",
        "MetricName": "tma_frontend_bound",

The metric groups are shown in 'perf list' like the following where
TopdownL1 is a metric group:

TopdownL1:
  tma_backend_bound
       [This category represents fraction of slots where no uops are being
        delivered due to a lack of required resources for accepting new uops
        in the Backend]
  tma_bad_speculation
       [This category represents fraction of slots wasted due to incorrect
        speculations]
  tma_frontend_bound
       [This category represents fraction of slots where the processor's
        Frontend undersupplies its Backend]
  tma_retiring
       [This category represents fraction of slots utilized by useful work
        i.e. issued uops that eventually get retired]

This patch adds support for a new json file in each model directory
called metricgroups.json that comprises a dictionary containing
entries that map from a metric group to a description:

{
...
    "TopdownL1": "Metrics for top-down breakdown at level 1",
...
}

perf list is then updated to support this changing the above output
to:

  TopdownL1: [Metrics for top-down breakdown at level 1]

Committer notes:

Added a (int) cast to the ARRAY_SIZE() introduced in this patch to
address:

  /tmp/build/perf-tools-next/pmu-events/pmu-events.c: In function ‘describe_metricgroup’:
  /var/home/acme/git/perf-tools-next/tools/include/linux/kernel.h:102:25: error: overflow in conversion from ‘long unsigned int’ to ‘int’ changes value from ‘18446744073709551615’ to ‘-1’ [-Werror=overflow]
    102 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
        |                         ^
  /tmp/build/perf-tools-next/pmu-events/pmu-events.c:61603:29: note: in expansion of macro ‘ARRAY_SIZE’
  61603 |         int low = 0, high = ARRAY_SIZE(metricgroups) - 1;
        |                             ^~~~~~~~~~
  cc1: all warnings being treated as errors

Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20230517173805.602113-15-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2023-05-17 10:38:03 -07:00 committed by Arnaldo Carvalho de Melo
parent bfce728db3
commit 66c6e0c100
4 changed files with 62 additions and 5 deletions

View File

@ -192,9 +192,14 @@ static void default_print_metric(void *ps,
if (group && print_state->metricgroups) { if (group && print_state->metricgroups) {
if (print_state->name_only) if (print_state->name_only)
printf("%s ", group); printf("%s ", group);
else if (print_state->metrics) else if (print_state->metrics) {
printf("\n%s:\n", group); const char *gdesc = describe_metricgroup(group);
else
if (gdesc)
printf("\n%s: [%s]\n", group, gdesc);
else
printf("\n%s:\n", group);
} else
printf("%s\n", group); printf("%s\n", group);
} }
zfree(&print_state->last_metricgroups); zfree(&print_state->last_metricgroups);

View File

@ -420,3 +420,8 @@ int pmu_for_each_sys_metric(pmu_metric_iter_fn fn __maybe_unused, void *data __m
{ {
return 0; return 0;
} }
const char *describe_metricgroup(const char *group __maybe_unused)
{
return NULL;
}

View File

@ -37,6 +37,8 @@ _pending_metrics = []
_pending_metrics_tblname = None _pending_metrics_tblname = None
# Global BigCString shared by all structures. # Global BigCString shared by all structures.
_bcs = None _bcs = None
# Map from the name of a metric group to a description of the group.
_metricgroups = {}
# Order specific JsonEvent attributes will be visited. # Order specific JsonEvent attributes will be visited.
_json_event_attributes = [ _json_event_attributes = [
# cmp_sevent related attributes. # cmp_sevent related attributes.
@ -512,6 +514,17 @@ def preprocess_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
if not item.is_file() or not item.name.endswith('.json'): if not item.is_file() or not item.name.endswith('.json'):
return return
if item.name == 'metricgroups.json':
metricgroup_descriptions = json.load(open(item.path))
for mgroup in metricgroup_descriptions:
assert len(mgroup) > 1, parents
description = f"{metricgroup_descriptions[mgroup]}\\000"
mgroup = f"{mgroup}\\000"
_bcs.add(mgroup)
_bcs.add(description)
_metricgroups[mgroup] = description
return
topic = get_topic(item.name) topic = get_topic(item.name)
for event in read_json_events(item.path, topic): for event in read_json_events(item.path, topic):
if event.name: if event.name:
@ -548,7 +561,7 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:
# Ignore other directories. If the file name does not have a .json # Ignore other directories. If the file name does not have a .json
# extension, ignore it. It could be a readme.txt for instance. # extension, ignore it. It could be a readme.txt for instance.
if not item.is_file() or not item.name.endswith('.json'): if not item.is_file() or not item.name.endswith('.json') or item.name == 'metricgroups.json':
return return
add_events_table_entries(item, get_topic(item.name)) add_events_table_entries(item, get_topic(item.name))
@ -911,6 +924,38 @@ int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
} }
""") """)
def print_metricgroups() -> None:
_args.output_file.write("""
static const int metricgroups[][2] = {
""")
for mgroup in sorted(_metricgroups):
description = _metricgroups[mgroup]
_args.output_file.write(
f'\t{{ {_bcs.offsets[mgroup]}, {_bcs.offsets[description]} }}, /* {mgroup} => {description} */\n'
)
_args.output_file.write("""
};
const char *describe_metricgroup(const char *group)
{
int low = 0, high = (int)ARRAY_SIZE(metricgroups) - 1;
while (low <= high) {
int mid = (low + high) / 2;
const char *mgroup = &big_c_string[metricgroups[mid][0]];
int cmp = strcmp(mgroup, group);
if (cmp == 0) {
return &big_c_string[metricgroups[mid][1]];
} else if (cmp < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return NULL;
}
""")
def main() -> None: def main() -> None:
global _args global _args
@ -993,7 +1038,7 @@ struct compact_pmu_event {
print_mapping_table(archs) print_mapping_table(archs)
print_system_mapping_table() print_system_mapping_table()
print_metricgroups()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -93,4 +93,6 @@ const struct pmu_metrics_table *find_sys_metrics_table(const char *name);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data); int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data); int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);
const char *describe_metricgroup(const char *group);
#endif #endif