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

perf tools: Add fallback for exclude_guest

Commit 7b100989b4f6bce70 ("perf evlist: Remove __evlist__add_default")
changed to parse "cycles:P" event instead of creating a new cycles
event for perf record. But it also changed the way how modifiers are
handled so it doesn't set the exclude_guest bit by default.

It seems Apple M1 PMU requires exclude_guest set and returns EOPNOTSUPP
if not. Let's add a fallback so that it can work with default events.

Also update perf stat hybrid tests to handle possible u or H modifiers.

Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Ravi Bangoria <ravi.bangoria@amd.com>
Acked-by: Kan Liang <kan.liang@linux.intel.com>
Cc: James Clark <james.clark@arm.com>
Cc: Atish Patra <atishp@atishpatra.org>
Cc: Mingwei Zhang <mizhang@google.com>
Cc: Kajol Jain <kjain@linux.ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Palmer Dabbelt <palmer@rivosinc.com>
Link: https://lore.kernel.org/r/20241016062359.264929-2-namhyung@kernel.org
Fixes: 7b100989b4f6bce70 ("perf evlist: Remove __evlist__add_default")
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

+37 -4
+15 -3
tools/perf/builtin-stat.c
··· 640 640 * (behavior changed with commit b0a873e). 641 641 */ 642 642 if (errno == EINVAL || errno == ENOSYS || 643 - errno == ENOENT || errno == EOPNOTSUPP || 644 - errno == ENXIO) { 643 + errno == ENOENT || errno == ENXIO) { 645 644 if (verbose > 0) 646 645 ui__warning("%s event is not supported by the kernel.\n", 647 646 evsel__name(counter)); ··· 658 659 if (verbose > 0) 659 660 ui__warning("%s\n", msg); 660 661 return COUNTER_RETRY; 661 - } else if (target__has_per_thread(&target) && 662 + } else if (target__has_per_thread(&target) && errno != EOPNOTSUPP && 662 663 evsel_list->core.threads && 663 664 evsel_list->core.threads->err_thread != -1) { 664 665 /* ··· 677 678 counter->supported = false; 678 679 counter->errored = true; 679 680 return COUNTER_SKIP; 681 + } 682 + 683 + if (errno == EOPNOTSUPP) { 684 + if (verbose > 0) { 685 + ui__warning("%s event is not supported by the kernel.\n", 686 + evsel__name(counter)); 687 + } 688 + counter->supported = false; 689 + counter->errored = true; 690 + 691 + if ((evsel__leader(counter) != counter) || 692 + !(counter->core.leader->nr_members > 1)) 693 + return COUNTER_SKIP; 680 694 } 681 695 682 696 evsel__open_strerror(counter, &target, errno, msg, sizeof(msg));
+1 -1
tools/perf/tests/shell/stat.sh
··· 185 185 fi 186 186 187 187 # Run default Perf stat 188 - cycles_events=$(perf stat -- true 2>&1 | grep -E "/cycles/| cycles " | wc -l) 188 + cycles_events=$(perf stat -- true 2>&1 | grep -E "/cycles/[uH]*| cycles[:uH]* " -c) 189 189 190 190 if [ "$pmus" -ne "$cycles_events" ] 191 191 then
+21
tools/perf/util/evsel.c
··· 3157 3157 evsel->core.attr.exclude_hv = 1; 3158 3158 3159 3159 return true; 3160 + } else if (err == EOPNOTSUPP && !evsel->core.attr.exclude_guest && 3161 + !evsel->exclude_GH) { 3162 + const char *name = evsel__name(evsel); 3163 + char *new_name; 3164 + const char *sep = ":"; 3165 + 3166 + /* Is there already the separator in the name. */ 3167 + if (strchr(name, '/') || 3168 + (strchr(name, ':') && !evsel->is_libpfm_event)) 3169 + sep = ""; 3170 + 3171 + if (asprintf(&new_name, "%s%sH", name, sep) < 0) 3172 + return false; 3173 + 3174 + free(evsel->name); 3175 + evsel->name = new_name; 3176 + /* Apple M1 requires exclude_guest */ 3177 + scnprintf(msg, msgsize, "trying to fall back to excluding guest samples"); 3178 + evsel->core.attr.exclude_guest = 1; 3179 + 3180 + return true; 3160 3181 } 3161 3182 3162 3183 return false;