diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-record.c | 7 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 6 | ||||
-rw-r--r-- | tools/perf/util/evlist-hybrid.c | 73 | ||||
-rw-r--r-- | tools/perf/util/evlist-hybrid.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 1 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 35 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 4 |
7 files changed, 127 insertions, 0 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 548c1dbde6c5..cc801fecf079 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -2854,6 +2854,13 @@ int cmd_record(int argc, const char **argv) /* Enable ignoring missing threads when -u/-p option is defined. */ rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX || rec->opts.target.pid; + if (evlist__fix_hybrid_cpus(rec->evlist, rec->opts.target.cpu_list)) { + pr_err("failed to use cpu list %s\n", + rec->opts.target.cpu_list); + goto out; + } + + rec->opts.target.hybrid = perf_pmu__has_hybrid(); err = -ENOMEM; if (evlist__create_maps(rec->evlist, &rec->opts.target) < 0) usage_with_options(record_usage, record_options); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 84de61795e67..f4253ba26c3f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2430,6 +2430,12 @@ int cmd_stat(int argc, const char **argv) if ((stat_config.aggr_mode == AGGR_THREAD) && (target.system_wide)) target.per_thread = true; + if (evlist__fix_hybrid_cpus(evsel_list, target.cpu_list)) { + pr_err("failed to use cpu list %s\n", target.cpu_list); + goto out; + } + + target.hybrid = perf_pmu__has_hybrid(); if (evlist__create_maps(evsel_list, &target) < 0) { if (target__has_task(&target)) { pr_err("Problems finding threads of monitor\n"); diff --git a/tools/perf/util/evlist-hybrid.c b/tools/perf/util/evlist-hybrid.c index db3f5fbdebe1..7c554234b43d 100644 --- a/tools/perf/util/evlist-hybrid.c +++ b/tools/perf/util/evlist-hybrid.c @@ -86,3 +86,76 @@ bool evlist__has_hybrid(struct evlist *evlist) return false; } + +int evlist__fix_hybrid_cpus(struct evlist *evlist, const char *cpu_list) +{ + struct perf_cpu_map *cpus; + struct evsel *evsel, *tmp; + struct perf_pmu *pmu; + int ret, unmatched_count = 0, events_nr = 0; + + if (!perf_pmu__has_hybrid() || !cpu_list) + return 0; + + cpus = perf_cpu_map__new(cpu_list); + if (!cpus) + return -1; + + /* + * The evsels are created with hybrid pmu's cpus. But now we + * need to check and adjust the cpus of evsel by cpu_list because + * cpu_list may cause conflicts with cpus of evsel. For example, + * cpus of evsel is cpu0-7, but the cpu_list is cpu6-8, we need + * to adjust the cpus of evsel to cpu6-7. And then propatate maps + * in evlist__create_maps(). + */ + evlist__for_each_entry_safe(evlist, tmp, evsel) { + struct perf_cpu_map *matched_cpus, *unmatched_cpus; + char buf1[128], buf2[128]; + + pmu = perf_pmu__find_hybrid_pmu(evsel->pmu_name); + if (!pmu) + continue; + + ret = perf_pmu__cpus_match(pmu, cpus, &matched_cpus, + &unmatched_cpus); + if (ret) + goto out; + + events_nr++; + + if (matched_cpus->nr > 0 && (unmatched_cpus->nr > 0 || + matched_cpus->nr < cpus->nr || + matched_cpus->nr < pmu->cpus->nr)) { + perf_cpu_map__put(evsel->core.cpus); + perf_cpu_map__put(evsel->core.own_cpus); + evsel->core.cpus = perf_cpu_map__get(matched_cpus); + evsel->core.own_cpus = perf_cpu_map__get(matched_cpus); + + if (unmatched_cpus->nr > 0) { + cpu_map__snprint(matched_cpus, buf1, sizeof(buf1)); + pr_warning("WARNING: use %s in '%s' for '%s', skip other cpus in list.\n", + buf1, pmu->name, evsel->name); + } + } + + if (matched_cpus->nr == 0) { + evlist__remove(evlist, evsel); + evsel__delete(evsel); + + cpu_map__snprint(cpus, buf1, sizeof(buf1)); + cpu_map__snprint(pmu->cpus, buf2, sizeof(buf2)); + pr_warning("WARNING: %s isn't a '%s', please use a CPU list in the '%s' range (%s)\n", + buf1, pmu->name, pmu->name, buf2); + unmatched_count++; + } + + perf_cpu_map__put(matched_cpus); + perf_cpu_map__put(unmatched_cpus); + } + + ret = (unmatched_count == events_nr) ? -1 : 0; +out: + perf_cpu_map__put(cpus); + return ret; +} diff --git a/tools/perf/util/evlist-hybrid.h b/tools/perf/util/evlist-hybrid.h index 19f74b4c340a..aacdb1b0f948 100644 --- a/tools/perf/util/evlist-hybrid.h +++ b/tools/perf/util/evlist-hybrid.h @@ -10,5 +10,6 @@ int evlist__add_default_hybrid(struct evlist *evlist, bool precise); void evlist__warn_hybrid_group(struct evlist *evlist); bool evlist__has_hybrid(struct evlist *evlist); +int evlist__fix_hybrid_cpus(struct evlist *evlist, const char *cpu_list); #endif /* __PERF_EVLIST_HYBRID_H */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 06f8890816c3..5f92319ce258 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -27,6 +27,7 @@ #include "util/perf_api_probe.h" #include "util/evsel_fprintf.h" #include "util/evlist-hybrid.h" +#include "util/pmu.h" #include <signal.h> #include <unistd.h> #include <sched.h> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6cdbee8a12e7..5f486ccb6fe6 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1927,3 +1927,38 @@ int perf_pmu__match(char *pattern, char *name, char *tok) return 0; } + +int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, + struct perf_cpu_map **mcpus_ptr, + struct perf_cpu_map **ucpus_ptr) +{ + struct perf_cpu_map *pmu_cpus = pmu->cpus; + struct perf_cpu_map *matched_cpus, *unmatched_cpus; + int matched_nr = 0, unmatched_nr = 0; + + matched_cpus = perf_cpu_map__default_new(); + if (!matched_cpus) + return -1; + + unmatched_cpus = perf_cpu_map__default_new(); + if (!unmatched_cpus) { + perf_cpu_map__put(matched_cpus); + return -1; + } + + for (int i = 0; i < cpus->nr; i++) { + int cpu; + + cpu = perf_cpu_map__idx(pmu_cpus, cpus->map[i]); + if (cpu == -1) + unmatched_cpus->map[unmatched_nr++] = cpus->map[i]; + else + matched_cpus->map[matched_nr++] = cpus->map[i]; + } + + unmatched_cpus->nr = unmatched_nr; + matched_cpus->nr = matched_nr; + *mcpus_ptr = matched_cpus; + *ucpus_ptr = unmatched_cpus; + return 0; +} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 033e8211c025..5133bc456034 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -11,6 +11,7 @@ #include "pmu-events/pmu-events.h" struct evsel_config_term; +struct perf_cpu_map; enum { PERF_PMU_FORMAT_VALUE_CONFIG, @@ -136,4 +137,7 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, bool perf_pmu__has_hybrid(void); int perf_pmu__match(char *pattern, char *name, char *tok); +int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, + struct perf_cpu_map **mcpus_ptr, + struct perf_cpu_map **ucpus_ptr); #endif /* __PMU_H */ |