Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf evsel: Fix missing exclude_{host,guest} setting

The current logic for the perf missing feature has a bug that it can
wrongly clear some modifiers like G or H. Actually some PMUs don't
support any filtering or exclusion while others do. But we check it as
a global feature.

For example, the cycles event can have 'G' modifier to enable it only in
the guest mode on x86. When you don't run any VMs it'll return 0.

# perf stat -a -e cycles:G sleep 1

Performance counter stats for 'system wide':

0 cycles:G

1.000721670 seconds time elapsed

But when it's used with other pmu events that don't support G modifier,
it'll be reset and return non-zero values.

# perf stat -a -e cycles:G,msr/tsc/ sleep 1

Performance counter stats for 'system wide':

538,029,960 cycles:G
16,924,010,738 msr/tsc/

1.001815327 seconds time elapsed

This is because of the missing feature detection logic being global.
Add a hashmap to set pmu-specific exclude_host/guest features.

Committer notes:

Fix 'perf test python' by adding a stub for evsel__find_pmu() in
tools/perf/util/python.c, document that it is used so far only for the
above reasons so that if anybody needs this in the python binding
usecases, we can revisit this.

Reported-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Link: http://lore.kernel.org/lkml/20211105205847.120950-1-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
3500eeeb 88c42f4d

+42 -5
+22 -5
tools/perf/util/evsel.c
··· 1824 1824 evsel->open_flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; 1825 1825 if (perf_missing_features.mmap2) 1826 1826 evsel->core.attr.mmap2 = 0; 1827 - if (perf_missing_features.exclude_guest) 1827 + if (evsel->pmu && evsel->pmu->missing_features.exclude_guest) 1828 1828 evsel->core.attr.exclude_guest = evsel->core.attr.exclude_host = 0; 1829 1829 if (perf_missing_features.lbr_flags) 1830 1830 evsel->core.attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | ··· 1917 1917 perf_missing_features.mmap2 = true; 1918 1918 pr_debug2_peo("switching off mmap2\n"); 1919 1919 return true; 1920 - } else if (!perf_missing_features.exclude_guest && 1921 - (evsel->core.attr.exclude_guest || evsel->core.attr.exclude_host)) { 1922 - perf_missing_features.exclude_guest = true; 1923 - pr_debug2_peo("switching off exclude_guest, exclude_host\n"); 1920 + } else if ((evsel->core.attr.exclude_guest || evsel->core.attr.exclude_host) && 1921 + (evsel->pmu == NULL || evsel->pmu->missing_features.exclude_guest)) { 1922 + if (evsel->pmu == NULL) { 1923 + evsel->pmu = evsel__find_pmu(evsel); 1924 + if (evsel->pmu) 1925 + evsel->pmu->missing_features.exclude_guest = true; 1926 + else { 1927 + /* we cannot find PMU, disable attrs now */ 1928 + evsel->core.attr.exclude_host = false; 1929 + evsel->core.attr.exclude_guest = false; 1930 + } 1931 + } 1932 + 1933 + if (evsel->exclude_GH) { 1934 + pr_debug2_peo("PMU has no exclude_host/guest support, bailing out\n"); 1935 + return false; 1936 + } 1937 + if (!perf_missing_features.exclude_guest) { 1938 + perf_missing_features.exclude_guest = true; 1939 + pr_debug2_peo("switching off exclude_guest, exclude_host\n"); 1940 + } 1924 1941 return true; 1925 1942 } else if (!perf_missing_features.sample_id_all) { 1926 1943 perf_missing_features.sample_id_all = true;
+4
tools/perf/util/evsel.h
··· 22 22 struct hashmap; 23 23 struct bperf_leader_bpf; 24 24 struct bperf_follower_bpf; 25 + struct perf_pmu; 25 26 26 27 typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); 27 28 ··· 154 153 }; 155 154 unsigned long open_flags; 156 155 int precise_ip_original; 156 + 157 + /* for missing_features */ 158 + struct perf_pmu *pmu; 157 159 }; 158 160 159 161 struct perf_missing_features {
+4
tools/perf/util/pmu.h
··· 49 49 struct list_head caps; /* HEAD struct perf_pmu_caps -> list */ 50 50 struct list_head list; /* ELEM */ 51 51 struct list_head hybrid_list; 52 + 53 + struct { 54 + bool exclude_guest; 55 + } missing_features; 52 56 }; 53 57 54 58 extern struct perf_pmu perf_pmu__fake;
+12
tools/perf/util/python.c
··· 70 70 } 71 71 72 72 /* 73 + * This one is needed not to drag the PMU bandwagon, jevents generated 74 + * pmu_sys_event_tables, etc and evsel__find_pmu() is used so far just for 75 + * doing per PMU perf_event_attr.exclude_guest handling, not really needed, so 76 + * far, for the perf python binding known usecases, revisit if this become 77 + * necessary. 78 + */ 79 + struct perf_pmu *evsel__find_pmu(struct evsel *evsel __maybe_unused) 80 + { 81 + return NULL; 82 + } 83 + 84 + /* 73 85 * Add this one here not to drag util/metricgroup.c 74 86 */ 75 87 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,