Skip to content

Commit f7e36d0

Browse files
james-c-linaronamhyung
authored andcommitted
libperf: evlist: Fix --cpu argument on hybrid platform
Since the linked fixes: commit, specifying a CPU on hybrid platforms results in an error because Perf tries to open an extended type event on "any" CPU which isn't valid. Extended type events can only be opened on CPUs that match the type. Before (working): $ perf record --cpu 1 -- true [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 2.385 MB perf.data (7 samples) ] After (not working): $ perf record -C 1 -- true WARNING: A requested CPU in '1' is not supported by PMU 'cpu_atom' (CPUs 16-27) for event 'cycles:P' Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (cpu_atom/cycles:P/). /bin/dmesg | grep -i perf may provide additional information. (Ignore the warning message, that's expected and not particularly relevant to this issue). This is because perf_cpu_map__intersect() of the user specified CPU (1) and one of the PMU's CPUs (16-27) correctly results in an empty (NULL) CPU map. However for the purposes of opening an event, libperf converts empty CPU maps into an any CPU (-1) which the kernel rejects. Fix it by deleting evsels with empty CPU maps in the specific case where user requested CPU maps are evaluated. Fixes: 251aa04 ("perf parse-events: Wildcard most "numeric" events") Reviewed-by: Ian Rogers <[email protected]> Tested-by: Thomas Falcon <[email protected]> Signed-off-by: James Clark <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent a93a620 commit f7e36d0

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

tools/lib/perf/evlist.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
4747
*/
4848
perf_cpu_map__put(evsel->cpus);
4949
evsel->cpus = perf_cpu_map__intersect(evlist->user_requested_cpus, evsel->own_cpus);
50+
51+
/*
52+
* Empty cpu lists would eventually get opened as "any" so remove
53+
* genuinely empty ones before they're opened in the wrong place.
54+
*/
55+
if (perf_cpu_map__is_empty(evsel->cpus)) {
56+
struct perf_evsel *next = perf_evlist__next(evlist, evsel);
57+
58+
perf_evlist__remove(evlist, evsel);
59+
/* Keep idx contiguous */
60+
if (next)
61+
list_for_each_entry_from(next, &evlist->entries, node)
62+
next->idx--;
63+
}
5064
} else if (!evsel->own_cpus || evlist->has_user_cpus ||
5165
(!evsel->requires_cpu && perf_cpu_map__has_any_cpu(evlist->user_requested_cpus))) {
5266
/*
@@ -80,11 +94,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
8094

8195
static void perf_evlist__propagate_maps(struct perf_evlist *evlist)
8296
{
83-
struct perf_evsel *evsel;
97+
struct perf_evsel *evsel, *n;
8498

8599
evlist->needs_map_propagation = true;
86100

87-
perf_evlist__for_each_evsel(evlist, evsel)
101+
list_for_each_entry_safe(evsel, n, &evlist->entries, node)
88102
__perf_evlist__propagate_maps(evlist, evsel);
89103
}
90104

0 commit comments

Comments
 (0)