From 0d3f0e6f94ef58d5532e23b6d153b0890cf0014c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 1 Sep 2023 16:39:49 -0700 Subject: perf parse-events: Introduce 'struct parse_events_terms' parse_events_terms() existed in function names but was passed a 'struct list_head'. As many parse_events functions take an evsel_config list as well as a parse_event_term list, and the naming head_terms and head_config is inconsistent, there's a potential to switch the lists and get errors. Introduce a 'struct parse_events_terms', that just wraps a list_head, to avoid this. Add the regular init/exit functions and transition the code to use them. Reviewed-by: James Clark Signed-off-by: Ian Rogers Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rob Herring Link: https://lore.kernel.org/r/20230901233949.2930562-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/intel-pt.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 31807791589e..b923bca939d9 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -64,28 +64,23 @@ static int intel_pt_parse_terms_with_default(struct perf_pmu *pmu, const char *str, u64 *config) { - struct list_head *terms; + struct parse_events_terms terms; struct perf_event_attr attr = { .size = 0, }; int err; - terms = malloc(sizeof(struct list_head)); - if (!terms) - return -ENOMEM; - - INIT_LIST_HEAD(terms); - - err = parse_events_terms(terms, str, /*input=*/ NULL); + parse_events_terms__init(&terms); + err = parse_events_terms(&terms, str, /*input=*/ NULL); if (err) goto out_free; attr.config = *config; - err = perf_pmu__config_terms(pmu, &attr, terms, /*zero=*/true, /*err=*/NULL); + err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*err=*/NULL); if (err) goto out_free; *config = attr.config; out_free: - parse_events_terms__delete(terms); + parse_events_terms__exit(&terms); return err; } -- cgit v1.2.3 From 3d0f5f456a5786573ba6a3358178c8db580e4b85 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 13 Sep 2023 16:33:48 +0100 Subject: perf pmu: Move pmu__find_core_pmu() to pmus.c pmu__find_core_pmu() more logically belongs in pmus.c because it iterates over all PMUs, so move it to pmus.c At the same time rename it to perf_pmus__find_core_pmu() to match the naming convention in this file. list_prepare_entry() can't be used in perf_pmus__scan_core() anymore now that it's called from the same compilation unit. This is with -O2 (specifically -O1 -ftree-vrp -finline-functions -finline-small-functions) which allow the bounds of the array access to be determined at compile time. list_prepare_entry() subtracts the offset of the 'list' member in struct perf_pmu from &core_pmus, which isn't a struct perf_pmu. The compiler sees that pmu results in &core_pmus - 8 and refuses to compile. At runtime this works because list_for_each_entry_continue() always adds the offset back again before dereferencing ->next, but it's technically undefined behavior. With -fsanitize=undefined an additional warning is generated. Using list_first_entry_or_null() to get the first entry here avoids doing &core_pmus - 8 but has the same result and fixes both the compile warning and the undefined behavior warning. There are other uses of list_prepare_entry() in pmus.c, but the compiler doesn't seem to be able to see that they can also be called with &core_pmus, so I won't change any at this time. Signed-off-by: James Clark Reviewed-by: Ian Rogers Reviewed-by: John Garry Cc: Ravi Bangoria Cc: Eduard Zingerman Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Haixin Yu Cc: Kan Liang Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230913153355.138331-2-james.clark@arm.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm64/util/pmu.c | 6 +++--- tools/perf/tests/expr.c | 2 +- tools/perf/util/expr.c | 2 +- tools/perf/util/pmu.c | 17 ----------------- tools/perf/util/pmu.h | 2 +- tools/perf/util/pmus.c | 20 +++++++++++++++++++- 6 files changed, 25 insertions(+), 24 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c index 615084eb88d8..3d9330feebd2 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -10,7 +10,7 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void) { - struct perf_pmu *pmu = pmu__find_core_pmu(); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); if (pmu) return perf_pmu__find_metrics_table(pmu); @@ -20,7 +20,7 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void) const struct pmu_events_table *pmu_events_table__find(void) { - struct perf_pmu *pmu = pmu__find_core_pmu(); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); if (pmu) return perf_pmu__find_events_table(pmu); @@ -32,7 +32,7 @@ double perf_pmu__cpu_slots_per_cycle(void) { char path[PATH_MAX]; unsigned long long slots = 0; - struct perf_pmu *pmu = pmu__find_core_pmu(); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); if (pmu) { perf_pmu__pathname_scnprintf(path, sizeof(path), diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index 78544092ef0c..e3aa9d4fcf3a 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -76,7 +76,7 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u struct expr_parse_ctx *ctx; bool is_intel = false; char strcmp_cpuid_buf[256]; - struct perf_pmu *pmu = pmu__find_core_pmu(); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); char *cpuid = perf_pmu__getcpuid(pmu); char *escaped_cpuid1, *escaped_cpuid2; diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index 4488f306de78..7be23b3ac082 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -509,7 +509,7 @@ double expr__strcmp_cpuid_str(const struct expr_parse_ctx *ctx __maybe_unused, bool compute_ids __maybe_unused, const char *test_id) { double ret; - struct perf_pmu *pmu = pmu__find_core_pmu(); + struct perf_pmu *pmu = perf_pmus__find_core_pmu(); char *cpuid = perf_pmu__getcpuid(pmu); if (!cpuid) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index e2159854ab26..f50a5636633f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -2050,20 +2050,3 @@ void perf_pmu__delete(struct perf_pmu *pmu) zfree(&pmu->id); free(pmu); } - -struct perf_pmu *pmu__find_core_pmu(void) -{ - struct perf_pmu *pmu = NULL; - - while ((pmu = perf_pmus__scan_core(pmu))) { - /* - * The cpumap should cover all CPUs. Otherwise, some CPUs may - * not support some events or have different event IDs. - */ - if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) - return NULL; - - return pmu; - } - return NULL; -} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index bd5d804a6736..d7b46085642d 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -264,6 +264,6 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name); struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus); void perf_pmu__delete(struct perf_pmu *pmu); -struct perf_pmu *pmu__find_core_pmu(void); +struct perf_pmu *perf_pmus__find_core_pmu(void); #endif /* __PMU_H */ diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 6631367c756f..cec869cbe163 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -10,6 +10,7 @@ #include #include #include +#include "cpumap.h" #include "debug.h" #include "evsel.h" #include "pmus.h" @@ -268,7 +269,7 @@ struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu) { if (!pmu) { pmu_read_sysfs(/*core_only=*/true); - pmu = list_prepare_entry(pmu, &core_pmus, list); + return list_first_entry_or_null(&core_pmus, typeof(*pmu), list); } list_for_each_entry_continue(pmu, &core_pmus, list) return pmu; @@ -592,3 +593,20 @@ struct perf_pmu *evsel__find_pmu(const struct evsel *evsel) } return pmu; } + +struct perf_pmu *perf_pmus__find_core_pmu(void) +{ + struct perf_pmu *pmu = NULL; + + while ((pmu = perf_pmus__scan_core(pmu))) { + /* + * The cpumap should cover all CPUs. Otherwise, some CPUs may + * not support some events or have different event IDs. + */ + if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) + return NULL; + + return pmu; + } + return NULL; +} -- cgit v1.2.3 From 105e5b433e5c743bcdb4956b00b772dfddbee455 Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 13 Sep 2023 16:33:49 +0100 Subject: perf pmus: Simplify perf_pmus__find_core_pmu() Currently the while loop always either exits on the first iteration with a core PMU, or exits with NULL on heterogeneous systems or when not all CPUs are online. Both of the latter behaviors are undesirable for platforms other than Arm so simplify it to always return the first core PMU, or NULL if none exist. This behavior was depended on by the Arm version of pmu_metrics_table__find(), so the logic has been moved there instead. Signed-off-by: James Clark Suggested-by: Ian Rogers Reviewed-by: Ian Rogers Reviewed-by: John Garry Cc: Ravi Bangoria Cc: Eduard Zingerman Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Haixin Yu Cc: Kan Liang Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230913153355.138331-3-james.clark@arm.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm64/util/pmu.c | 8 +++++++- tools/perf/util/pmus.c | 14 +------------- 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c index 3d9330feebd2..3099f5f448ba 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -10,8 +10,14 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void) { - struct perf_pmu *pmu = perf_pmus__find_core_pmu(); + struct perf_pmu *pmu; + + /* Metrics aren't currently supported on heterogeneous Arm systems */ + if (perf_pmus__num_core_pmus() > 1) + return NULL; + /* Doesn't matter which one here because they'll all be the same */ + pmu = perf_pmus__find_core_pmu(); if (pmu) return perf_pmu__find_metrics_table(pmu); diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index cec869cbe163..64e798e68a2d 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -596,17 +596,5 @@ struct perf_pmu *evsel__find_pmu(const struct evsel *evsel) struct perf_pmu *perf_pmus__find_core_pmu(void) { - struct perf_pmu *pmu = NULL; - - while ((pmu = perf_pmus__scan_core(pmu))) { - /* - * The cpumap should cover all CPUs. Otherwise, some CPUs may - * not support some events or have different event IDs. - */ - if (RC_CHK_ACCESS(pmu->cpus)->nr != cpu__max_cpu().cpu) - return NULL; - - return pmu; - } - return NULL; + return perf_pmus__scan_core(NULL); } -- cgit v1.2.3 From 70360fad919b06100748764eb82fa399a9f37e1c Mon Sep 17 00:00:00 2001 From: James Clark Date: Wed, 13 Sep 2023 16:33:50 +0100 Subject: perf pmu: Remove unused function pmu_events_table__find() is no longer used so remove it and its Arm specific version. Signed-off-by: James Clark Reviewed-by: Ian Rogers Reviewed-by: John Garry Cc: Ravi Bangoria Cc: Eduard Zingerman Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Haixin Yu Cc: Kan Liang Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20230913153355.138331-4-james.clark@arm.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm64/util/pmu.c | 10 ---------- tools/perf/util/pmu.c | 5 ----- tools/perf/util/pmu.h | 1 - 3 files changed, 16 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c index 3099f5f448ba..2a4eab2d160e 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -24,16 +24,6 @@ const struct pmu_metrics_table *pmu_metrics_table__find(void) return NULL; } -const struct pmu_events_table *pmu_events_table__find(void) -{ - struct perf_pmu *pmu = perf_pmus__find_core_pmu(); - - if (pmu) - return perf_pmu__find_events_table(pmu); - - return NULL; -} - double perf_pmu__cpu_slots_per_cycle(void) { char path[PATH_MAX]; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f50a5636633f..0d81c059c91c 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -776,11 +776,6 @@ char *perf_pmu__getcpuid(struct perf_pmu *pmu) return cpuid; } -__weak const struct pmu_events_table *pmu_events_table__find(void) -{ - return perf_pmu__find_events_table(NULL); -} - __weak const struct pmu_metrics_table *pmu_metrics_table__find(void) { return perf_pmu__find_metrics_table(NULL); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index d7b46085642d..04b317b17d66 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -238,7 +238,6 @@ void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, const struct pmu_events_table *table); char *perf_pmu__getcpuid(struct perf_pmu *pmu); -const struct pmu_events_table *pmu_events_table__find(void); const struct pmu_metrics_table *pmu_metrics_table__find(void); int perf_pmu__convert_scale(const char *scale, char **end, double *sval); -- cgit v1.2.3 From 486021e04b24f8dffe54ec282ce5d4cc3e71133f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 7 Sep 2023 22:22:16 -0700 Subject: perf annotate: Add more x86 mov instruction cases Instructions with sign- and zero- extention like movsbl and movzwq were not handled properly. As it can check different size suffix (-b, -w, -l or -q) we can omit that and add the common parts even though some combinations are not possible. Reviewed-by: Ian Rogers Link: https://lore.kernel.org/r/20230908052216.566148-1-namhyung@kernel.org Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/annotate/instructions.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c index 5f4ac4fc7fcf..5cdf457f5cbe 100644 --- a/tools/perf/arch/x86/annotate/instructions.c +++ b/tools/perf/arch/x86/annotate/instructions.c @@ -74,12 +74,15 @@ static struct ins x86__instructions[] = { { .name = "movdqa", .ops = &mov_ops, }, { .name = "movdqu", .ops = &mov_ops, }, { .name = "movsd", .ops = &mov_ops, }, - { .name = "movslq", .ops = &mov_ops, }, { .name = "movss", .ops = &mov_ops, }, + { .name = "movsb", .ops = &mov_ops, }, + { .name = "movsw", .ops = &mov_ops, }, + { .name = "movsl", .ops = &mov_ops, }, { .name = "movupd", .ops = &mov_ops, }, { .name = "movups", .ops = &mov_ops, }, - { .name = "movzbl", .ops = &mov_ops, }, - { .name = "movzwl", .ops = &mov_ops, }, + { .name = "movzb", .ops = &mov_ops, }, + { .name = "movzw", .ops = &mov_ops, }, + { .name = "movzl", .ops = &mov_ops, }, { .name = "mulsd", .ops = &mov_ops, }, { .name = "mulss", .ops = &mov_ops, }, { .name = "nop", .ops = &nop_ops, }, -- cgit v1.2.3 From b1f05622fef39dded385f9e360e859846c1ddaf1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Sun, 24 Sep 2023 23:23:23 -0700 Subject: perf pmus: Make PMU alias name loading lazy PMU alias names were computed when the first perf_pmu is created, scanning all PMUs in event sources for a file called alias that generally doesn't exist. Switch to trying to load the file when all PMU related files are loaded in lookup. This would cause a PMU name lookup of an alias name to fail if no PMUs were loaded, so in that case all PMUs are loaded and the find repeated. The overhead is similar but in the (very) general case not all PMUs are scanned for the alias file. As the overhead occurs once per invocation it doesn't show in perf bench internals pmu-scan. On a tigerlake machine, the number of openat system calls for an event of cpu/cycles/ with perf stat reduces from 94 to 69 (ie 25 fewer openat calls). Signed-off-by: Ian Rogers Acked-by: Namhyung Kim Cc: Ravi Bangoria Cc: James Clark Cc: Leo Yan Cc: Kan Liang Link: https://lore.kernel.org/r/20230925062323.840799-1-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/util/pmu.c | 139 ----------------------------------------- tools/perf/util/pmu.c | 39 ++++++------ tools/perf/util/pmu.h | 2 - tools/perf/util/pmus.c | 10 +++ 4 files changed, 31 insertions(+), 159 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index f428cffb0378..8b53ca468a50 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -17,15 +17,6 @@ #include "../../../util/pmus.h" #include "env.h" -struct pmu_alias { - char *name; - char *alias; - struct list_head list; -}; - -static LIST_HEAD(pmu_alias_name_list); -static bool cached_list; - struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) { #ifdef HAVE_AUXTRACE_SUPPORT @@ -41,136 +32,6 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __mayb return NULL; } -static void pmu_alias__delete(struct pmu_alias *pmu_alias) -{ - if (!pmu_alias) - return; - - zfree(&pmu_alias->name); - zfree(&pmu_alias->alias); - free(pmu_alias); -} - -static struct pmu_alias *pmu_alias__new(char *name, char *alias) -{ - struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); - - if (pmu_alias) { - pmu_alias->name = strdup(name); - if (!pmu_alias->name) - goto out_delete; - - pmu_alias->alias = strdup(alias); - if (!pmu_alias->alias) - goto out_delete; - } - return pmu_alias; - -out_delete: - pmu_alias__delete(pmu_alias); - return NULL; -} - -static int setup_pmu_alias_list(void) -{ - int fd, dirfd; - DIR *dir; - struct dirent *dent; - struct pmu_alias *pmu_alias; - char buf[MAX_PMU_NAME_LEN]; - FILE *file; - int ret = -ENOMEM; - - dirfd = perf_pmu__event_source_devices_fd(); - if (dirfd < 0) - return -1; - - dir = fdopendir(dirfd); - if (!dir) - return -errno; - - while ((dent = readdir(dir))) { - if (!strcmp(dent->d_name, ".") || - !strcmp(dent->d_name, "..")) - continue; - - fd = perf_pmu__pathname_fd(dirfd, dent->d_name, "alias", O_RDONLY); - if (fd < 0) - continue; - - file = fdopen(fd, "r"); - if (!file) - continue; - - if (!fgets(buf, sizeof(buf), file)) { - fclose(file); - continue; - } - - fclose(file); - - /* Remove the last '\n' */ - buf[strlen(buf) - 1] = 0; - - pmu_alias = pmu_alias__new(dent->d_name, buf); - if (!pmu_alias) - goto close_dir; - - list_add_tail(&pmu_alias->list, &pmu_alias_name_list); - } - - ret = 0; - -close_dir: - closedir(dir); - return ret; -} - -static const char *__pmu_find_real_name(const char *name) -{ - struct pmu_alias *pmu_alias; - - list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { - if (!strcmp(name, pmu_alias->alias)) - return pmu_alias->name; - } - - return name; -} - -const char *pmu_find_real_name(const char *name) -{ - if (cached_list) - return __pmu_find_real_name(name); - - setup_pmu_alias_list(); - cached_list = true; - - return __pmu_find_real_name(name); -} - -static const char *__pmu_find_alias_name(const char *name) -{ - struct pmu_alias *pmu_alias; - - list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { - if (!strcmp(name, pmu_alias->name)) - return pmu_alias->alias; - } - return NULL; -} - -const char *pmu_find_alias_name(const char *name) -{ - if (cached_list) - return __pmu_find_alias_name(name); - - setup_pmu_alias_list(); - cached_list = true; - - return __pmu_find_alias_name(name); -} - int perf_pmus__num_mem_pmus(void) { /* AMD uses IBS OP pmu and not a core PMU for perf mem/c2c */ diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 5b417509b8a9..6b1b7f8f00fa 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -960,16 +960,27 @@ perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) return NULL; } -const char * __weak -pmu_find_real_name(const char *name) +static char *pmu_find_alias_name(struct perf_pmu *pmu, int dirfd) { - return name; -} + FILE *file = perf_pmu__open_file_at(pmu, dirfd, "alias"); + char *line = NULL; + size_t line_len = 0; + ssize_t ret; -const char * __weak -pmu_find_alias_name(const char *name __maybe_unused) -{ - return NULL; + if (!file) + return NULL; + + ret = getline(&line, &line_len, file); + if (ret < 0) { + fclose(file); + return NULL; + } + /* Remove trailing newline. */ + if (ret > 0 && line[ret - 1] == '\n') + line[--ret] = '\0'; + + fclose(file); + return line; } static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) @@ -980,12 +991,10 @@ static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) return max_precise; } -struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name) +struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name) { struct perf_pmu *pmu; __u32 type; - const char *name = pmu_find_real_name(lookup_name); - const char *alias_name; pmu = zalloc(sizeof(*pmu)); if (!pmu) @@ -1018,18 +1027,12 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char pmu->is_core = is_pmu_core(name); pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core); - alias_name = pmu_find_alias_name(name); - if (alias_name) { - pmu->alias_name = strdup(alias_name); - if (!pmu->alias_name) - goto err; - } - pmu->type = type; pmu->is_uncore = pmu_is_uncore(dirfd, name); if (pmu->is_uncore) pmu->id = pmu_id(name); pmu->max_precise = pmu_max_precise(dirfd, pmu); + pmu->alias_name = pmu_find_alias_name(pmu, dirfd); pmu->events_table = perf_pmu__find_events_table(pmu); pmu_add_sys_aliases(pmu); list_add_tail(&pmu->list, pmus); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index a682c6bc0fce..85190d058852 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -252,8 +252,6 @@ void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu); int perf_pmu__match(const char *pattern, const char *name, const char *tok); -const char *pmu_find_real_name(const char *name); -const char *pmu_find_alias_name(const char *name); double perf_pmu__cpu_slots_per_cycle(void); int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size); int perf_pmu__pathname_scnprintf(char *buf, size_t size, diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c index 64e798e68a2d..ce4931461741 100644 --- a/tools/perf/util/pmus.c +++ b/tools/perf/util/pmus.c @@ -37,6 +37,8 @@ static LIST_HEAD(other_pmus); static bool read_sysfs_core_pmus; static bool read_sysfs_all_pmus; +static void pmu_read_sysfs(bool core_only); + int pmu_name_len_no_suffix(const char *str, unsigned long *num) { int orig_len, len; @@ -124,6 +126,14 @@ struct perf_pmu *perf_pmus__find(const char *name) pmu = perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name); close(dirfd); + if (!pmu) { + /* + * Looking up an inidividual PMU failed. This may mean name is + * an alias, so read the PMUs from sysfs and try to find again. + */ + pmu_read_sysfs(core_pmu); + pmu = pmu_find(name); + } return pmu; } -- cgit v1.2.3 From aa61360155ac69003dc5c177f03a7f177a435286 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 12 Oct 2023 10:56:39 -0700 Subject: perf pmu: Rename perf_pmu__get_default_config to perf_pmu__arch_init Assign default_config as part of the init. perf_pmu__get_default_config was doing more than just getting the default config and so this is intended to better align with the code. Signed-off-by: Ian Rogers Cc: Ravi Bangoria Cc: James Clark Cc: Suzuki K Poulose Cc: Yang Jihong Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Kajol Jain Cc: Thomas Richter Cc: Alexander Shishkin Cc: Kan Liang Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231012175645.1849503-2-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/pmu.c | 8 +++----- tools/perf/arch/s390/util/pmu.c | 3 +-- tools/perf/arch/x86/util/pmu.c | 5 ++--- tools/perf/util/pmu.c | 13 ++++++------- tools/perf/util/pmu.h | 2 +- 5 files changed, 13 insertions(+), 18 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c index a9623b128ece..d55d2b15f2e6 100644 --- a/tools/perf/arch/arm/util/pmu.c +++ b/tools/perf/arch/arm/util/pmu.c @@ -14,22 +14,20 @@ #include "../../../util/pmu.h" #include "../../../util/cs-etm.h" -struct perf_event_attr -*perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) +void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) { #ifdef HAVE_AUXTRACE_SUPPORT if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) { /* add ETM default config here */ pmu->selectable = true; - return cs_etm_get_default_config(pmu); + pmu->default_config = cs_etm_get_default_config(pmu); #if defined(__aarch64__) } else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) { - return arm_spe_pmu_default_config(pmu); + pmu->default_config = arm_spe_pmu_default_config(pmu); } else if (strstarts(pmu->name, HISI_PTT_PMU_NAME)) { pmu->selectable = true; #endif } #endif - return NULL; } diff --git a/tools/perf/arch/s390/util/pmu.c b/tools/perf/arch/s390/util/pmu.c index 11f03f32e3fd..886c30e001fa 100644 --- a/tools/perf/arch/s390/util/pmu.c +++ b/tools/perf/arch/s390/util/pmu.c @@ -13,11 +13,10 @@ #define S390_PMUPAI_EXT "pai_ext" #define S390_PMUCPUM_CF "cpum_cf" -struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu) +void perf_pmu__arch_init(struct perf_pmu *pmu) { if (!strcmp(pmu->name, S390_PMUPAI_CRYPTO) || !strcmp(pmu->name, S390_PMUPAI_EXT) || !strcmp(pmu->name, S390_PMUCPUM_CF)) pmu->selectable = true; - return NULL; } diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index 8b53ca468a50..811e2377d2d5 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -17,19 +17,18 @@ #include "../../../util/pmus.h" #include "env.h" -struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) +void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) { #ifdef HAVE_AUXTRACE_SUPPORT if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { pmu->auxtrace = true; - return intel_pt_pmu_default_config(pmu); + pmu->default_config = intel_pt_pmu_default_config(pmu); } if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) { pmu->auxtrace = true; pmu->selectable = true; } #endif - return NULL; } int perf_pmus__num_mem_pmus(void) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6428e2648289..d075da0eecc0 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -954,12 +954,6 @@ void pmu_add_sys_aliases(struct perf_pmu *pmu) pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, pmu); } -struct perf_event_attr * __weak -perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) -{ - return NULL; -} - static char *pmu_find_alias_name(struct perf_pmu *pmu, int dirfd) { FILE *file = perf_pmu__open_file_at(pmu, dirfd, "alias"); @@ -991,6 +985,11 @@ static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) return max_precise; } +void __weak +perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) +{ +} + struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name) { struct perf_pmu *pmu; @@ -1037,7 +1036,7 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char pmu_add_sys_aliases(pmu); list_add_tail(&pmu->list, pmus); - pmu->default_config = perf_pmu__get_default_config(pmu); + perf_pmu__arch_init(pmu); return pmu; err: diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 85190d058852..588c64e38d6b 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -233,7 +233,7 @@ bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name); int perf_pmu__test(void); -struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); +void perf_pmu__arch_init(struct perf_pmu *pmu); void pmu_add_cpu_aliases_table(struct perf_pmu *pmu, const struct pmu_events_table *table); -- cgit v1.2.3 From 461e3e636a26518d3dd9c0ae3aff32894ec00b26 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 12 Oct 2023 10:56:40 -0700 Subject: perf intel-pt: Move PMU initialization from default config code Avoid setting PMU values in intel_pt_pmu_default_config, move to perf_pmu__arch_init. Signed-off-by: Ian Rogers Reviewed-by: Adrian Hunter Cc: Ravi Bangoria Cc: James Clark Cc: Suzuki K Poulose Cc: Yang Jihong Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Kajol Jain Cc: Thomas Richter Cc: Kan Liang Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231012175645.1849503-3-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/arch/x86/util/intel-pt.c | 2 -- tools/perf/arch/x86/util/pmu.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index b923bca939d9..6d6cd8f9133c 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -267,8 +267,6 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu) attr->config = intel_pt_default_config(intel_pt_pmu); - intel_pt_pmu->selectable = true; - return attr; } diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index 811e2377d2d5..949b3e2c67bd 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -22,6 +22,7 @@ void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) #ifdef HAVE_AUXTRACE_SUPPORT if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { pmu->auxtrace = true; + pmu->selectable = true; pmu->default_config = intel_pt_pmu_default_config(pmu); } if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) { -- cgit v1.2.3 From 672bd21390d38dfccbe52b9537555985d65446aa Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 12 Oct 2023 10:56:41 -0700 Subject: perf arm-spe: Move PMU initialization from default config code Avoid setting PMU values in arm_spe_pmu_default_config, move to perf_pmu__arch_init. Signed-off-by: Ian Rogers Reviewed-by: Adrian Hunter Tested-by: Leo Yan Cc: Ravi Bangoria Cc: James Clark Cc: Suzuki K Poulose Cc: Yang Jihong Cc: Will Deacon Cc: Mike Leach Cc: Jing Zhang Cc: Kajol Jain Cc: Thomas Richter Cc: Alexander Shishkin Cc: Kan Liang Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231012175645.1849503-4-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/pmu.c | 2 ++ tools/perf/arch/arm64/util/arm-spe.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c index d55d2b15f2e6..f25f68f84a94 100644 --- a/tools/perf/arch/arm/util/pmu.c +++ b/tools/perf/arch/arm/util/pmu.c @@ -23,6 +23,8 @@ void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) pmu->default_config = cs_etm_get_default_config(pmu); #if defined(__aarch64__) } else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) { + pmu->selectable = true; + pmu->is_uncore = false; pmu->default_config = arm_spe_pmu_default_config(pmu); } else if (strstarts(pmu->name, HISI_PTT_PMU_NAME)) { pmu->selectable = true; diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 9cc3d6dcb849..08a76734ccd2 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -516,8 +516,5 @@ struct perf_event_attr attr->sample_period = 4096; } - arm_spe_pmu->selectable = true; - arm_spe_pmu->is_uncore = false; - return attr; } -- cgit v1.2.3 From 0197da7affab502cd6e25da616ad038b169a7a77 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 12 Oct 2023 10:56:45 -0700 Subject: perf pmu: Lazily compute default config The default config is computed during creation of the PMU and may do things like scanning sysfs, when the PMU may just be used as part of scanning. Change default_config to perf_event_attr_init_default, a callback that is used when a default config needs initializing. This avoids holding onto the memory for a perf_event_attr and copying. On a tigerlake laptop running the pmu-scan benchmark: Before: Running 'internals/pmu-scan' benchmark: Computing performance of sysfs PMU event scan for 100 times Average core PMU scanning took: 28.780 usec (+- 0.503 usec) Average PMU scanning took: 283.480 usec (+- 18.471 usec) Number of openat syscalls: 30,227 After: Running 'internals/pmu-scan' benchmark: Computing performance of sysfs PMU event scan for 100 times Average core PMU scanning took: 27.880 usec (+- 0.169 usec) Average PMU scanning took: 245.260 usec (+- 15.758 usec) Number of openat syscalls: 28,914 Over 3 runs it is a nearly 12% reduction in execution time and a 4.3% of openat calls. Signed-off-by: Ian Rogers Reviewed-by: Adrian Hunter Cc: Ravi Bangoria Cc: James Clark Cc: Suzuki K Poulose Cc: Yang Jihong Cc: Will Deacon Cc: Leo Yan Cc: Mike Leach Cc: Jing Zhang Cc: Kajol Jain Cc: Thomas Richter Cc: Kan Liang Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231012175645.1849503-8-irogers@google.com Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/cs-etm.c | 13 +++-------- tools/perf/arch/arm/util/pmu.c | 4 ++-- tools/perf/arch/arm64/util/arm-spe.c | 45 ++++++++++++++++++------------------ tools/perf/arch/x86/util/intel-pt.c | 25 ++++++++++---------- tools/perf/arch/x86/util/pmu.c | 2 +- tools/perf/util/arm-spe.h | 4 +++- tools/perf/util/cs-etm.h | 2 +- tools/perf/util/intel-pt.h | 3 ++- tools/perf/util/parse-events.c | 12 +++++----- tools/perf/util/pmu.c | 3 +-- tools/perf/util/pmu.h | 7 +++--- 11 files changed, 58 insertions(+), 62 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index b8d6a953fd74..16bba74f048b 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -917,16 +917,9 @@ out: * (CFG_CHG and evsel__set_config_if_unset()). If no default is set then user * changes aren't tracked. */ -struct perf_event_attr * -cs_etm_get_default_config(struct perf_pmu *pmu __maybe_unused) +void +cs_etm_get_default_config(const struct perf_pmu *pmu __maybe_unused, + struct perf_event_attr *attr) { - struct perf_event_attr *attr; - - attr = zalloc(sizeof(struct perf_event_attr)); - if (!attr) - return NULL; - attr->sample_period = 1; - - return attr; } diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c index f25f68f84a94..7f3af3b97f3b 100644 --- a/tools/perf/arch/arm/util/pmu.c +++ b/tools/perf/arch/arm/util/pmu.c @@ -20,12 +20,12 @@ void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) { /* add ETM default config here */ pmu->selectable = true; - pmu->default_config = cs_etm_get_default_config(pmu); + pmu->perf_event_attr_init_default = cs_etm_get_default_config; #if defined(__aarch64__) } else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) { pmu->selectable = true; pmu->is_uncore = false; - pmu->default_config = arm_spe_pmu_default_config(pmu); + pmu->perf_event_attr_init_default = arm_spe_pmu_default_config; } else if (strstarts(pmu->name, HISI_PTT_PMU_NAME)) { pmu->selectable = true; #endif diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 08a76734ccd2..e3acc739bd00 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -113,6 +113,25 @@ arm_spe_snapshot_resolve_auxtrace_defaults(struct record_opts *opts, } } +static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu) +{ + static __u64 sample_period; + + if (sample_period) + return sample_period; + + /* + * If kernel driver doesn't advertise a minimum, + * use max allowable by PMSIDR_EL1.INTERVAL + */ + if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu", + &sample_period) != 1) { + pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n"); + sample_period = 4096; + } + return sample_period; +} + static int arm_spe_recording_options(struct auxtrace_record *itr, struct evlist *evlist, struct record_opts *opts) @@ -136,7 +155,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, return -EINVAL; } evsel->core.attr.freq = 0; - evsel->core.attr.sample_period = arm_spe_pmu->default_config->sample_period; + evsel->core.attr.sample_period = arm_spe_pmu__sample_period(arm_spe_pmu); evsel->needs_auxtrace_mmap = true; arm_spe_evsel = evsel; opts->full_auxtrace = true; @@ -495,26 +514,8 @@ struct auxtrace_record *arm_spe_recording_init(int *err, return &sper->itr; } -struct perf_event_attr -*arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu) +void +arm_spe_pmu_default_config(const struct perf_pmu *arm_spe_pmu, struct perf_event_attr *attr) { - struct perf_event_attr *attr; - - attr = zalloc(sizeof(struct perf_event_attr)); - if (!attr) { - pr_err("arm_spe default config cannot allocate a perf_event_attr\n"); - return NULL; - } - - /* - * If kernel driver doesn't advertise a minimum, - * use max allowable by PMSIDR_EL1.INTERVAL - */ - if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu", - &attr->sample_period) != 1) { - pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n"); - attr->sample_period = 4096; - } - - return attr; + attr->sample_period = arm_spe_pmu__sample_period(arm_spe_pmu); } diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 6d6cd8f9133c..fa0c718b9e72 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -60,7 +60,7 @@ struct intel_pt_recording { size_t priv_size; }; -static int intel_pt_parse_terms_with_default(struct perf_pmu *pmu, +static int intel_pt_parse_terms_with_default(const struct perf_pmu *pmu, const char *str, u64 *config) { @@ -84,7 +84,7 @@ out_free: return err; } -static int intel_pt_parse_terms(struct perf_pmu *pmu, const char *str, u64 *config) +static int intel_pt_parse_terms(const struct perf_pmu *pmu, const char *str, u64 *config) { *config = 0; return intel_pt_parse_terms_with_default(pmu, str, config); @@ -177,7 +177,7 @@ static int intel_pt_pick_bit(int bits, int target) return pick; } -static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu) +static u64 intel_pt_default_config(const struct perf_pmu *intel_pt_pmu) { char buf[256]; int mtc, mtc_periods = 0, mtc_period; @@ -256,18 +256,17 @@ static int intel_pt_parse_snapshot_options(struct auxtrace_record *itr, return 0; } -struct perf_event_attr * -intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu) +void intel_pt_pmu_default_config(const struct perf_pmu *intel_pt_pmu, + struct perf_event_attr *attr) { - struct perf_event_attr *attr; + static u64 config; + static bool initialized; - attr = zalloc(sizeof(struct perf_event_attr)); - if (!attr) - return NULL; - - attr->config = intel_pt_default_config(intel_pt_pmu); - - return attr; + if (!initialized) { + config = intel_pt_default_config(intel_pt_pmu); + initialized = true; + } + attr->config = config; } static const char *intel_pt_find_filter(struct evlist *evlist, diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index 949b3e2c67bd..469555ae9b3c 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -23,7 +23,7 @@ void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { pmu->auxtrace = true; pmu->selectable = true; - pmu->default_config = intel_pt_pmu_default_config(pmu); + pmu->perf_event_attr_init_default = intel_pt_pmu_default_config; } if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) { pmu->auxtrace = true; diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h index 98d3235781c3..4f4900c18f3e 100644 --- a/tools/perf/util/arm-spe.h +++ b/tools/perf/util/arm-spe.h @@ -27,5 +27,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err, int arm_spe_process_auxtrace_info(union perf_event *event, struct perf_session *session); -struct perf_event_attr *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu); +void arm_spe_pmu_default_config(const struct perf_pmu *arm_spe_pmu, + struct perf_event_attr *attr); + #endif diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index 7cca37887917..4696267a32f0 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -242,7 +242,7 @@ struct cs_etm_packet_queue { int cs_etm__process_auxtrace_info(union perf_event *event, struct perf_session *session); -struct perf_event_attr *cs_etm_get_default_config(struct perf_pmu *pmu); +void cs_etm_get_default_config(const struct perf_pmu *pmu, struct perf_event_attr *attr); enum cs_etm_pid_fmt { CS_ETM_PIDFMT_NONE, diff --git a/tools/perf/util/intel-pt.h b/tools/perf/util/intel-pt.h index c7d6068e3a6b..18fd0be52e6c 100644 --- a/tools/perf/util/intel-pt.h +++ b/tools/perf/util/intel-pt.h @@ -42,6 +42,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err); int intel_pt_process_auxtrace_info(union perf_event *event, struct perf_session *session); -struct perf_event_attr *intel_pt_pmu_default_config(struct perf_pmu *pmu); +void intel_pt_pmu_default_config(const struct perf_pmu *intel_pt_pmu, + struct perf_event_attr *attr); #endif diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 23c027cf20ae..aa2f5c6fc7fc 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1418,11 +1418,10 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, } fix_raw(&parsed_terms, pmu); - if (pmu->default_config) { - memcpy(&attr, pmu->default_config, sizeof(struct perf_event_attr)); - } else { - memset(&attr, 0, sizeof(attr)); - } + memset(&attr, 0, sizeof(attr)); + if (pmu->perf_event_attr_init_default) + pmu->perf_event_attr_init_default(pmu, &attr); + attr.type = pmu->type; if (list_empty(&parsed_terms.terms)) { @@ -1466,7 +1465,8 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, * When using default config, record which bits of attr->config were * changed by the user. */ - if (pmu->default_config && get_config_chgs(pmu, &parsed_terms, &config_terms)) { + if (pmu->perf_event_attr_init_default && + get_config_chgs(pmu, &parsed_terms, &config_terms)) { parse_events_terms__exit(&parsed_terms); return -ENOMEM; } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 8ef675ea7bdd..a967d25e899b 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1402,7 +1402,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, struct parse_events_terms *head_terms, struct parse_events_error *err) { - bool zero = !!pmu->default_config; + bool zero = !!pmu->perf_event_attr_init_default; return perf_pmu__config_terms(pmu, attr, head_terms, zero, err); } @@ -2064,7 +2064,6 @@ void perf_pmu__delete(struct perf_pmu *pmu) perf_cpu_map__put(pmu->cpus); - zfree(&pmu->default_config); zfree(&pmu->name); zfree(&pmu->alias_name); zfree(&pmu->id); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 5a05131aa4ce..d2895d415f08 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -92,10 +92,11 @@ struct perf_pmu { */ int max_precise; /** - * @default_config: Optional default perf_event_attr determined in - * architecture specific code. + * @perf_event_attr_init_default: Optional function to default + * initialize PMU specific parts of the perf_event_attr. */ - struct perf_event_attr *default_config; + void (*perf_event_attr_init_default)(const struct perf_pmu *pmu, + struct perf_event_attr *attr); /** * @cpus: Empty or the contents of either of: * /bus/event_source/devices//cpumask. -- cgit v1.2.3 From f8ccc2d5cc6516b019bcf8e361ae2a380cb36019 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Sat, 14 Oct 2023 15:41:58 +0800 Subject: perf cs-etm: Validate timestamp tracing in per-thread mode So far, it's impossible to validate timestamp trace in Arm CoreSight when the perf is in the per-thread mode. E.g. for the command: perf record -e cs_etm/timestamp/ --per-thread -- ls The command enables config 'timestamp' for 'cs_etm' event in the per-thread mode. In this case, the function cs_etm_validate_config() directly bails out and skips validation. Given profiled process can be scheduled on any CPUs in the per-thread mode, this patch validates timestamp tracing for all CPUs when detect the CPU map is empty. Signed-off-by: Leo Yan Reviewed-by: James Clark Acked-by: Suzuki K Poulose Cc: Will Deacon Cc: Mike Leach Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231014074159.1667880-2-leo.yan@linaro.org Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/cs-etm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 16bba74f048b..39ec6cae91ed 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -205,8 +205,17 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, for (i = 0; i < cpu__max_cpu().cpu; i++) { struct perf_cpu cpu = { .cpu = i, }; - if (!perf_cpu_map__has(event_cpus, cpu) || - !perf_cpu_map__has(online_cpus, cpu)) + /* + * In per-cpu case, do the validation for CPUs to work with. + * In per-thread case, the CPU map is empty. Since the traced + * program can run on any CPUs in this case, thus don't skip + * validation. + */ + if (!perf_cpu_map__empty(event_cpus) && + !perf_cpu_map__has(event_cpus, cpu)) + continue; + + if (!perf_cpu_map__has(online_cpus, cpu)) continue; err = cs_etm_validate_context_id(itr, evsel, i); -- cgit v1.2.3 From 78efa7b411450a534e9d326cdf5578f681c73988 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Sat, 14 Oct 2023 15:41:59 +0800 Subject: perf cs-etm: Respect timestamp option When users pass the option '--timestamp' or '-T' in the record command, all events will set the PERF_SAMPLE_TIME bit in the attribution. In this case, the AUX event will record the kernel timestamp, but it doesn't mean Arm CoreSight enables timestamp packets in its hardware tracing. If the option '--timestamp' or '-T' is set, this patch always enables Arm CoreSight timestamp, as a result, the bit 28 in event's config is to be set. Before: # perf record -e cs_etm// --per-thread --timestamp -- ls # perf script --header-only ... # event : name = cs_etm//, , id = { 69 }, type = 12, size = 136, config = 0, { sample_period, sample_freq } = 1, sample_type = IP|TID|TIME|CPU|IDENTIFIER, read_format = ID|LOST, disabled = 1, enable_on_exec = 1, sample_id_all = 1, exclude_guest = 1 ... After: # perf record -e cs_etm// --per-thread --timestamp -- ls # perf script --header-only ... # event : name = cs_etm//, , id = { 49 }, type = 12, size = 136, config = 0x10000000, { sample_period, sample_freq } = 1, sample_type = IP|TID|TIME|CPU|IDENTIFIER, read_format = ID|LOST, disabled = 1, enable_on_exec = 1, sample_id_all = 1, exclude_guest = 1 ... Signed-off-by: Leo Yan Reviewed-by: James Clark Acked-by: Suzuki K Poulose Cc: Will Deacon Cc: Mike Leach Cc: Alexander Shishkin Cc: John Garry Cc: linux-arm-kernel@lists.infradead.org Cc: coresight@lists.linaro.org Link: https://lore.kernel.org/r/20231014074159.1667880-3-leo.yan@linaro.org Signed-off-by: Namhyung Kim --- tools/perf/arch/arm/util/cs-etm.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 39ec6cae91ed..2cf873d71dff 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -442,6 +442,15 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, "contextid", 1); } + /* + * When the option '--timestamp' or '-T' is enabled, the PERF_SAMPLE_TIME + * bit is set for all events. In this case, always enable Arm CoreSight + * timestamp tracing. + */ + if (opts->sample_time_set) + evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel, + "timestamp", 1); + /* Add dummy event to keep tracking */ err = parse_event(evlist, "dummy:u"); if (err) -- cgit v1.2.3 From f6a66ff98ac1cfbfb83ec2445f5652ae065a1bf0 Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Mon, 9 Oct 2023 10:30:52 +0530 Subject: tools/perf/arch/powerpc: Fix the CPU ID const char* value by adding 0x prefix Simple expression parser test fails in powerpc as below: 4: Simple expression parser test child forked, pid 170385 Using CPUID 004e2102 division by zero syntax error syntax error FAILED tests/expr.c:65 parse test failed test child finished with -1 Simple expression parser: FAILED! This is observed after commit: 'commit 9d5da30e4ae9 ("perf jevents: Add a new expression builtin strcmp_cpuid_str()")' With this commit, a new expression builtin strcmp_cpuid_str got added. This function takes an 'ID' type value, which is a string. So expression parse for strcmp_cpuid_str expects const char * as cpuid value type. In case of powerpc, CPU IDs are numbers. Hence it doesn't get interpreted correctly by bison parser. Example in case of power9, cpuid string returns as: 004e2102 cpuid of string type is expected in two cases: 1. char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused); Testcase "tests/expr.c" uses "perf_pmu__getcpuid" which calls get_cpuid_str to get the cpuid string. 2. cpuid field in :struct pmu_events_map struct pmu_events_map { const char *arch; const char *cpuid; Here cpuid field is used in "perf_pmu__find_events_table" function as "strcmp_cpuid_str(map->cpuid, cpuid)". The value for cpuid field is picked from mapfile.csv. Fix the mapfile.csv and get_cpuid_str function to prefix cpuid with 0x so that it gets correctly interpreted by the bison parser Signed-off-by: Athira Rajeev Tested-by: Disha Goel Cc: kjain@linux.ibm.com Cc: maddy@linux.ibm.com Cc: disgoel@linux.vnet.ibm.com Cc: linuxppc-dev@lists.ozlabs.org Link: https://lore.kernel.org/r/20231009050052.64935-1-atrajeev@linux.vnet.ibm.com Signed-off-by: Namhyung Kim --- tools/perf/arch/powerpc/util/header.c | 2 +- tools/perf/pmu-events/arch/powerpc/mapfile.csv | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index c8d0dc775e5d..6b00efd53638 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -34,7 +34,7 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused) { char *bufp; - if (asprintf(&bufp, "%.8lx", mfspr(SPRN_PVR)) < 0) + if (asprintf(&bufp, "0x%.8lx", mfspr(SPRN_PVR)) < 0) bufp = NULL; return bufp; diff --git a/tools/perf/pmu-events/arch/powerpc/mapfile.csv b/tools/perf/pmu-events/arch/powerpc/mapfile.csv index a534ff6db14b..f4908af7ad66 100644 --- a/tools/perf/pmu-events/arch/powerpc/mapfile.csv +++ b/tools/perf/pmu-events/arch/powerpc/mapfile.csv @@ -13,6 +13,6 @@ # # Power8 entries -004[bcd][[:xdigit:]]{4},1,power8,core -004e[[:xdigit:]]{4},1,power9,core -0080[[:xdigit:]]{4},1,power10,core +0x004[bcd][[:xdigit:]]{4},1,power8,core +0x004e[[:xdigit:]]{4},1,power9,core +0x0080[[:xdigit:]]{4},1,power10,core -- cgit v1.2.3