Re: [PATCH v1 12/15] perf tool_pmu: Switch to standard pmu functions and json descriptions
From: Namhyung Kim
Date: Tue Sep 10 2024 - 01:47:28 EST
On Fri, Sep 06, 2024 at 10:08:27PM -0700, Ian Rogers wrote:
> Use the regular PMU approaches with tool json events to reduce the
> amount of special tool_pmu code - tool_pmu__config_terms and
> tool_pmu__for_each_event_cb are removed. Some functions remain, like
> tool_pmu__str_to_event, as conveniences to metricgroups. Add
> tool_pmu__skip_event/tool_pmu__num_skip_events to handle the case that
> tool json events shouldn't appear on certain architectures. This isn't
> done in jevents.py due to complexity in the empty-pmu-events.c and
> when all vendor json is built into the tool.
>
> Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
> ---
> tools/perf/util/pmu.c | 26 ++++-----
> tools/perf/util/pmus.c | 4 +-
> tools/perf/util/tool_pmu.c | 111 ++++++++++++-------------------------
> tools/perf/util/tool_pmu.h | 12 +---
> 4 files changed, 48 insertions(+), 105 deletions(-)
>
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index a412c9c62f9c..5ff6556292fd 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -1549,9 +1549,6 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
> {
> bool zero = !!pmu->perf_event_attr_init_default;
>
> - if (perf_pmu__is_tool(pmu))
> - return tool_pmu__config_terms(attr, head_terms, err);
> -
> /* Fake PMU doesn't have proper terms so nothing to configure in attr. */
> if (perf_pmu__is_fake(pmu))
> return 0;
> @@ -1664,8 +1661,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
> info->scale = 0.0;
> info->snapshot = false;
>
> - /* Tool/fake PMU doesn't rewrite terms. */
> - if (perf_pmu__is_tool(pmu) || perf_pmu__is_fake(pmu))
> + /* Fake PMU doesn't rewrite terms. */
> + if (perf_pmu__is_fake(pmu))
> goto out;
>
> list_for_each_entry_safe(term, h, &head_terms->terms, list) {
> @@ -1831,8 +1828,8 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
> {
> if (!name)
> return false;
> - if (perf_pmu__is_tool(pmu))
> - return tool_pmu__str_to_event(name) != TOOL_PMU__EVENT_NONE;
> + if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(name))
> + return false;
> if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
> return true;
> if (pmu->cpu_aliases_added || !pmu->events_table)
> @@ -1844,9 +1841,6 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
> {
> size_t nr;
>
> - if (perf_pmu__is_tool(pmu))
> - return tool_pmu__num_events();
> -
> pmu_aliases_parse(pmu);
> nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
>
> @@ -1857,6 +1851,9 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
> else
> assert(pmu->cpu_json_aliases == 0);
>
> + if (perf_pmu__is_tool(pmu))
> + nr -= tool_pmu__num_skip_events();
> +
> return pmu->selectable ? nr + 1 : nr;
> }
>
> @@ -1907,15 +1904,15 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
> int ret = 0;
> struct strbuf sb;
>
> - if (perf_pmu__is_tool(pmu))
> - return tool_pmu__for_each_event_cb(pmu, state, cb);
> -
> strbuf_init(&sb, /*hint=*/ 0);
> pmu_aliases_parse(pmu);
> pmu_add_cpu_aliases(pmu);
> list_for_each_entry(event, &pmu->aliases, list) {
> size_t buf_used, pmu_name_len;
>
> + if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
> + continue;
> +
> info.pmu_name = event->pmu_name ?: pmu->name;
> pmu_name_len = pmu_deduped_name_len(pmu, info.pmu_name,
> skip_duplicate_pmus);
> @@ -2321,9 +2318,6 @@ const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
> if (!pmu)
> return NULL;
>
> - if (perf_pmu__is_tool(pmu))
> - return tool_pmu__event_to_str(config);
> -
> pmu_aliases_parse(pmu);
> pmu_add_cpu_aliases(pmu);
> list_for_each_entry(event, &pmu->aliases, list) {
> diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c
> index 36329bc77316..19673b9991c6 100644
> --- a/tools/perf/util/pmus.c
> +++ b/tools/perf/util/pmus.c
> @@ -440,6 +440,7 @@ static int perf_pmus__print_pmu_events__callback(void *vstate,
> pr_err("Unexpected event %s/%s/\n", info->pmu->name, info->name);
> return 1;
> }
> + assert(info->pmu != NULL || info->name != NULL);
> s = &state->aliases[state->index];
> s->pmu = info->pmu;
> #define COPY_STR(str) s->str = info->str ? strdup(info->str) : NULL
> @@ -590,9 +591,6 @@ void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, voi
> int len = pmu_name_len_no_suffix(pmu->name);
> const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
>
> - if (perf_pmu__is_tool(pmu))
> - continue;
> -
> if (!pmu->is_core)
> desc = NULL;
>
> diff --git a/tools/perf/util/tool_pmu.c b/tools/perf/util/tool_pmu.c
> index 3dc7cc7b8d32..f2d26e9e51f5 100644
> --- a/tools/perf/util/tool_pmu.c
> +++ b/tools/perf/util/tool_pmu.c
> @@ -33,101 +33,54 @@ static const char *const tool_pmu__event_names[TOOL_PMU__EVENT_MAX] = {
> "system_tsc_freq",
> };
>
> -
> -const char *tool_pmu__event_to_str(enum tool_pmu_event ev)
> -{
> - if (ev > TOOL_PMU__EVENT_NONE && ev < TOOL_PMU__EVENT_MAX)
> - return tool_pmu__event_names[ev];
> -
> - return NULL;
> -}
> -
> -enum tool_pmu_event tool_pmu__str_to_event(const char *str)
> +bool tool_pmu__skip_event(const char *name)
I think you need __maybe_unused.
> {
> - int i;
> -
> - tool_pmu__for_each_event(i) {
> - if (!strcasecmp(str, tool_pmu__event_names[i])) {
> #if !defined(__aarch64__)
> - /* The slots event should only appear on arm64. */
> - if (i == TOOL_PMU__EVENT_SLOTS)
> - return TOOL_PMU__EVENT_NONE;
> + /* The slots event should only appear on arm64. */
> + if (strcasecmp(name, "slots") == 0)
> + return true;
> #endif
> - return i;
> - }
> - }
> - return TOOL_PMU__EVENT_NONE;
> +#if !defined(__i386__) && !defined(__x86_64__)
> + /* The system_tsc_freq event should only appear on x86. */
> + if (strcasecmp(name, "system_tsc_freq") == 0)
> + return true;
> +#endif
> + return false;
> }
>
> -static int tool_pmu__config_term(struct perf_event_attr *attr,
> - struct parse_events_term *term,
> - struct parse_events_error *err)
> +int tool_pmu__num_skip_events(void)
> {
> - if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) {
> - enum tool_pmu_event ev = tool_pmu__str_to_event(term->config);
> + int num = 0;
>
> - if (ev == TOOL_PMU__EVENT_NONE)
> - goto err_out;
> -
> - attr->config = ev;
> - return 0;
> - }
> -err_out:
> - if (err) {
> - char *err_str;
> -
> - parse_events_error__handle(err, term->err_val,
> - asprintf(&err_str,
> - "unexpected tool event term (%s) %s",
> - parse_events__term_type_str(term->type_term),
> - term->config) < 0
> - ? strdup("unexpected tool event term")
> - : err_str,
> - NULL);
> - }
> - return -EINVAL;
> +#if !defined(__aarch64__)
> + num++;
> +#endif
> +#if !defined(__i386__) && !defined(__x86_64__)
> + num++;
> +#endif
> + return num;
> }
>
> -int tool_pmu__config_terms(struct perf_event_attr *attr,
> - struct parse_events_terms *terms,
> - struct parse_events_error *err)
> +const char *tool_pmu__event_to_str(enum tool_pmu_event ev)
> {
> - struct parse_events_term *term;
> -
> - list_for_each_entry(term, &terms->terms, list) {
> - if (tool_pmu__config_term(attr, term, err))
> - return -EINVAL;
> - }
> -
> - return 0;
> + if (ev > TOOL_PMU__EVENT_NONE && ev < TOOL_PMU__EVENT_MAX)
> + return tool_pmu__event_names[ev];
>
> + return NULL;
> }
>
> -int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
> +enum tool_pmu_event tool_pmu__str_to_event(const char *str)
> {
> - struct pmu_event_info info = {
> - .pmu = pmu,
> - .event_type_desc = "Tool event",
> - };
> int i;
>
> + if (tool_pmu__skip_event(str))
> + return TOOL_PMU__EVENT_NONE;
> +
> tool_pmu__for_each_event(i) {
> - int ret;
> -
> - info.name = tool_pmu__event_to_str(i);
> - info.alias = NULL;
> - info.scale_unit = NULL;
> - info.desc = NULL;
> - info.long_desc = NULL;
> - info.encoding_desc = NULL;
> - info.topic = NULL;
> - info.pmu_name = pmu->name;
> - info.deprecated = false;
> - ret = cb(state, &info);
> - if (ret)
> - return ret;
> + if (!strcasecmp(str, tool_pmu__event_names[i]))
> + return i;
> }
> - return 0;
> + return TOOL_PMU__EVENT_NONE;
> }
>
> bool perf_pmu__is_tool(const struct perf_pmu *pmu)
> @@ -544,8 +497,12 @@ struct perf_pmu *perf_pmus__tool_pmu(void)
> static struct perf_pmu tool = {
> .name = "tool",
> .type = PERF_PMU_TYPE_TOOL,
> + .aliases = LIST_HEAD_INIT(tool.aliases),
> + .caps = LIST_HEAD_INIT(tool.caps),
This can be moved to the previous patch.
Thanks,
Namhyung
> .format = LIST_HEAD_INIT(tool.format),
> };
> + if (!tool.events_table)
> + tool.events_table = find_core_events_table("common", "common");
>
> return &tool;
> }
> diff --git a/tools/perf/util/tool_pmu.h b/tools/perf/util/tool_pmu.h
> index ecdf316525bb..a60184859080 100644
> --- a/tools/perf/util/tool_pmu.h
> +++ b/tools/perf/util/tool_pmu.h
> @@ -29,17 +29,11 @@ enum tool_pmu_event {
> #define tool_pmu__for_each_event(ev) \
> for ((ev) = TOOL_PMU__EVENT_DURATION_TIME; (ev) < TOOL_PMU__EVENT_MAX; ev++)
>
> -static inline size_t tool_pmu__num_events(void)
> -{
> - return TOOL_PMU__EVENT_MAX - 1;
> -}
> -
> const char *tool_pmu__event_to_str(enum tool_pmu_event ev);
> enum tool_pmu_event tool_pmu__str_to_event(const char *str);
> -int tool_pmu__config_terms(struct perf_event_attr *attr,
> - struct parse_events_terms *terms,
> - struct parse_events_error *err);
> -int tool_pmu__for_each_event_cb(struct perf_pmu *pmu, void *state, pmu_event_callback cb);
> +bool tool_pmu__skip_event(const char *name);
> +int tool_pmu__num_skip_events(void);
> +
> bool tool_pmu__read_event(enum tool_pmu_event ev, u64 *result);
>
> u64 tool_pmu__cpu_slots_per_cycle(void);
> --
> 2.46.0.469.g59c65b2a67-goog
>