]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf pmu: Add and use legacy_terms in alias information
authorIan Rogers <irogers@google.com>
Sun, 5 Oct 2025 18:24:15 +0000 (11:24 -0700)
committerNamhyung Kim <namhyung@kernel.org>
Wed, 15 Oct 2025 14:59:11 +0000 (23:59 +0900)
Add support to finding/adding events from the default_core event
table. If an event already exists from sysfs/json then the
default_core configuration is saved in the legacy_terms string. Lazily
use the legacy_terms string to set a legacy hardware or cache event as
deprecated if the core PMU doesn't support it. Use the legacy terms
string to set the alternate_hw_config, avoiding the value needing to
be passed from the parse_events parser.

Tested-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/pmu.c

index e25a4201f9ade40ac65415358e67bee881f25872..667be41abcd76816744a21e057bd94b58c76380a 100644 (file)
@@ -69,6 +69,11 @@ struct perf_pmu_alias {
        char *topic;
        /** @terms: Owned copy of the event terms. */
        char *terms;
+       /**
+        * @legacy_terms: If the event aliases a legacy event, holds a copy
+        * ofthe legacy event string.
+        */
+       char *legacy_terms;
        /**
         * @pmu_name: The name copied from the json struct pmu_event. This can
         * differ from the PMU name as it won't have suffixes.
@@ -101,6 +106,12 @@ struct perf_pmu_alias {
         * default.
         */
        bool deprecated;
+       /**
+        * @legacy_deprecated_checked: Legacy events may not be supported by the
+        * PMU need to be checked. If they aren't supported they are marked
+        * deprecated.
+        */
+       bool legacy_deprecated_checked;
        /** @from_sysfs: Was the alias from sysfs or a json event? */
        bool from_sysfs;
        /** @info_loaded: Have the scale, unit and other values been read from disk? */
@@ -430,6 +441,7 @@ static void perf_pmu_free_alias(struct perf_pmu_alias *alias)
        zfree(&alias->topic);
        zfree(&alias->pmu_name);
        zfree(&alias->terms);
+       zfree(&alias->legacy_terms);
        free(alias);
 }
 
@@ -522,6 +534,7 @@ static void read_alias_info(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
 struct update_alias_data {
        struct perf_pmu *pmu;
        struct perf_pmu_alias *alias;
+       bool legacy;
 };
 
 static int update_alias(const struct pmu_event *pe,
@@ -537,8 +550,13 @@ static int update_alias(const struct pmu_event *pe,
        assign_str(pe->name, "topic", &data->alias->topic, pe->topic);
        data->alias->per_pkg = pe->perpkg;
        if (pe->event) {
-               zfree(&data->alias->terms);
-               data->alias->terms = strdup(pe->event);
+               if (data->legacy) {
+                       zfree(&data->alias->legacy_terms);
+                       data->alias->legacy_terms = strdup(pe->event);
+               } else {
+                       zfree(&data->alias->terms);
+                       data->alias->terms = strdup(pe->event);
+               }
        }
        if (!ret && pe->unit) {
                char *unit;
@@ -628,7 +646,6 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
                        return ret;
                }
        }
-
        alias->name = strdup(name);
        alias->desc = desc ? strdup(desc) : NULL;
        alias->long_desc = long_desc ? strdup(long_desc) : NULL;
@@ -645,15 +662,29 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
        default:
        case EVENT_SRC_SYSFS:
                alias->from_sysfs = true;
-               if (pmu->events_table) {
+               if (pmu->events_table || pmu->is_core) {
                        /* Update an event from sysfs with json data. */
                        struct update_alias_data data = {
                                .pmu = pmu,
                                .alias = alias,
+                               .legacy = false,
                        };
-                       if (pmu_events_table__find_event(pmu->events_table, pmu, name,
-                                                        update_alias, &data) == 0)
+                       if ((pmu_events_table__find_event(pmu->events_table, pmu, name,
+                                                         update_alias, &data) == 0)) {
+                               /*
+                                * Override sysfs encodings with json encodings
+                                * specific to the cpuid.
+                                */
                                pmu->cpu_common_json_aliases++;
+                       }
+                       if (pmu->is_core) {
+                               /* Add in legacy encodings. */
+                               data.legacy = true;
+                               if (pmu_events_table__find_event(
+                                               perf_pmu__default_core_events_table(),
+                                               pmu, name, update_alias, &data) == 0)
+                                       pmu->cpu_common_json_aliases++;
+                       }
                }
                pmu->sysfs_aliases++;
                break;
@@ -1054,13 +1085,16 @@ void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, const struct pmu_events_tab
 
 static void pmu_add_cpu_aliases(struct perf_pmu *pmu)
 {
-       if (!pmu->events_table)
+       if (!pmu->events_table && !pmu->is_core)
                return;
 
        if (pmu->cpu_aliases_added)
                return;
 
        pmu_add_cpu_aliases_table(pmu, pmu->events_table);
+       if (pmu->is_core)
+               pmu_add_cpu_aliases_table(pmu, perf_pmu__default_core_events_table());
+
        pmu->cpu_aliases_added = true;
 }
 
@@ -1738,10 +1772,14 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
                return alias;
 
        /* Alias doesn't exist, try to get it from the json events. */
-       if (pmu->events_table &&
-           pmu_events_table__find_event(pmu->events_table, pmu, name,
-                                        pmu_add_cpu_aliases_map_callback,
-                                        pmu) == 0) {
+       if ((pmu_events_table__find_event(pmu->events_table, pmu, name,
+                                         pmu_add_cpu_aliases_map_callback,
+                                         pmu) == 0) ||
+           (pmu->is_core &&
+            pmu_events_table__find_event(perf_pmu__default_core_events_table(),
+                                         pmu, name,
+                                         pmu_add_cpu_aliases_map_callback,
+                                         pmu) == 0)) {
                alias = perf_pmu__find_alias(pmu, name, /*load=*/ false);
        }
        return alias;
@@ -1865,6 +1903,20 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_
                if (ret)
                        return ret;
 
+               if (alias->legacy_terms) {
+                       struct perf_event_attr attr = {.config = 0,};
+
+                       ret = perf_pmu__parse_terms_to_attr(pmu, alias->legacy_terms, &attr);
+                       if (ret) {
+                               parse_events_error__handle(err, term->err_term,
+                                                       strdup("Error evaluating legacy terms"),
+                                                       NULL);
+                               return ret;
+                       }
+                       if (attr.type == PERF_TYPE_HARDWARE)
+                               *alternate_hw_config = attr.config & PERF_HW_EVENT_MASK;
+               }
+
                if (alias->per_pkg)
                        info->per_pkg = true;
 
@@ -2034,9 +2086,13 @@ bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
                return drm_pmu__have_event(pmu, name);
        if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
                return true;
-       if (pmu->cpu_aliases_added || !pmu->events_table)
+       if (pmu->cpu_aliases_added || (!pmu->events_table && !pmu->is_core))
                return false;
-       return pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0;
+       if (pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0)
+               return true;
+       return pmu->is_core &&
+               pmu_events_table__find_event(perf_pmu__default_core_events_table(),
+                                            pmu, name, NULL, NULL) == 0;
 }
 
 size_t perf_pmu__num_events(struct perf_pmu *pmu)
@@ -2053,13 +2109,18 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
        pmu_aliases_parse(pmu);
        nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
 
-       if (pmu->cpu_aliases_added)
-                nr += pmu->cpu_json_aliases;
-       else if (pmu->events_table)
-               nr += pmu_events_table__num_events(pmu->events_table, pmu) -
-                       pmu->cpu_common_json_aliases;
-       else
+       if (pmu->cpu_aliases_added) {
+               nr += pmu->cpu_json_aliases;
+       } else if (pmu->events_table || pmu->is_core) {
+               nr += pmu_events_table__num_events(pmu->events_table, pmu);
+               if (pmu->is_core) {
+                       nr += pmu_events_table__num_events(
+                               perf_pmu__default_core_events_table(), pmu);
+               }
+               nr -= pmu->cpu_common_json_aliases;
+       } else {
                assert(pmu->cpu_json_aliases == 0 && pmu->cpu_common_json_aliases == 0);
+       }
 
        if (perf_pmu__is_tool(pmu))
                nr -= tool_pmu__num_skip_events();
@@ -2121,6 +2182,42 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
        return buf;
 }
 
+static bool perf_pmu_alias__check_deprecated(struct perf_pmu *pmu, struct perf_pmu_alias *alias)
+{
+       struct perf_event_attr attr = {.config = 0,};
+       const char *check_terms;
+       bool has_legacy_config;
+
+       if (alias->legacy_deprecated_checked)
+               return alias->deprecated;
+
+       alias->legacy_deprecated_checked = true;
+       if (alias->deprecated)
+               return true;
+
+       check_terms = alias->terms;
+       has_legacy_config =
+               strstr(check_terms, "legacy-hardware-config=") != NULL ||
+               strstr(check_terms, "legacy-cache-config=") != NULL;
+       if (!has_legacy_config && alias->legacy_terms) {
+               check_terms = alias->legacy_terms;
+               has_legacy_config =
+                       strstr(check_terms, "legacy-hardware-config=") != NULL ||
+                       strstr(check_terms, "legacy-cache-config=") != NULL;
+       }
+       if (!has_legacy_config)
+               return false;
+
+       if (perf_pmu__parse_terms_to_attr(pmu, check_terms, &attr) != 0) {
+               /* Parsing failed, set as deprecated. */
+               alias->deprecated = true;
+       } else if (attr.type < PERF_TYPE_MAX) {
+               /* Flag unsupported legacy events as deprecated. */
+               alias->deprecated = !is_event_supported(attr.type, attr.config);
+       }
+       return alias->deprecated;
+}
+
 int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
                             void *state, pmu_event_callback cb)
 {
@@ -2178,7 +2275,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
                                "%.*s/%s/", (int)pmu_name_len, info.pmu_name, event->terms) + 1;
                info.str = event->terms;
                info.topic = event->topic;
-               info.deprecated = event->deprecated;
+               info.deprecated = perf_pmu_alias__check_deprecated(pmu, event);
                ret = cb(state, &info);
                if (ret)
                        goto out;