From: Ian Rogers Date: Fri, 25 Aug 2023 13:52:36 +0000 (-0700) Subject: perf pmus: Sort pmus by name then suffix X-Git-Tag: v6.6.7~1921^2~21 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8d9f5146f5dae2d80217f204d9abd83ef704aa12;p=platform%2Fkernel%2Flinux-starfive.git perf pmus: Sort pmus by name then suffix Sort PMUs by name. If two PMUs have the same name but differ by suffix, sort the suffixes numerically. For example, "breakpoint" comes before "cpu", "uncore_imc_free_running_0" comes before "uncore_imc_free_running_1". Suffixes need to be treated specially as otherwise they will be ordered like 0, 1, 10, 11, .., 2, 20, 21, .., etc. Only PMUs starting 'uncore_' are considered to have a potential suffix. Sorting of PMUs is done so that later patches can skip duplicate uncore PMUs that differ only by there suffix. Committer notes: Used the more compact, intention revealing strstarts() function we got from the kernel sources: - if (strncmp(str, "uncore_", 7)) + if (!strstarts(str, "uncore_")) Also in pmus_cmp() the lhs_num and rhs_num variables may end up not being set for non "uncore_" prefixed PMUs in pmu_name_len_no_suffix(), or at least gcc 7.5 in some distros (opensuse 15.5, to be EOLed in Dec/2024) thins so, so initialize both to zero. Reviewed-by: Kan Liang Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: John Garry Cc: Kajol Jain Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Link: https://lore.kernel.org/r/20230825135237.921058-2-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 4dd5912..7316da1 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include +#include #include #include #include +#include #include #include #include @@ -33,6 +36,31 @@ static LIST_HEAD(other_pmus); static bool read_sysfs_core_pmus; static bool read_sysfs_all_pmus; +static int pmu_name_len_no_suffix(const char *str, unsigned long *num) +{ + int orig_len, len; + + orig_len = len = strlen(str); + + /* Non-uncore PMUs have their full length, for example, i915. */ + if (!strstarts(str, "uncore_")) + return len; + + /* + * Count trailing digits and '_', if '_{num}' suffix isn't present use + * the full length. + */ + while (len > 0 && isdigit(str[len - 1])) + len--; + + if (len > 0 && len != orig_len && str[len - 1] == '_') { + if (num) + *num = strtoul(&str[len], NULL, 10); + return len - 1; + } + return orig_len; +} + void perf_pmus__destroy(void) { struct perf_pmu *pmu, *tmp; @@ -122,6 +150,25 @@ static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name) return perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name); } +static int pmus_cmp(void *priv __maybe_unused, + const struct list_head *lhs, const struct list_head *rhs) +{ + unsigned long lhs_num = 0, rhs_num = 0; + struct perf_pmu *lhs_pmu = container_of(lhs, struct perf_pmu, list); + struct perf_pmu *rhs_pmu = container_of(rhs, struct perf_pmu, list); + const char *lhs_pmu_name = lhs_pmu->name ?: ""; + const char *rhs_pmu_name = rhs_pmu->name ?: ""; + int lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name, &lhs_num); + int rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name, &rhs_num); + int ret = strncmp(lhs_pmu_name, rhs_pmu_name, + lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len); + + if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0) + return ret; + + return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0); +} + /* Add all pmus in sysfs to pmu list: */ static void pmu_read_sysfs(bool core_only) { @@ -156,6 +203,8 @@ static void pmu_read_sysfs(bool core_only) if (!perf_pmu__create_placeholder_core_pmu(&core_pmus)) pr_err("Failure to set up any core PMUs\n"); } + list_sort(NULL, &core_pmus, pmus_cmp); + list_sort(NULL, &other_pmus, pmus_cmp); if (!list_empty(&core_pmus)) { read_sysfs_core_pmus = true; if (!core_only)