From nobody Thu Nov 28 15:57:40 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5614D26AFB; Tue, 1 Oct 2024 00:20:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727742033; cv=none; b=BE1H0fIUeMaoyn7n5IryUw4Tt/CxgiR4h0pOZ54il3Jc6sYQAdBfRgJqK/JBmtst9hBGdZLD2M4aPHG8DY4ichvz0aDZyMZDlcqSSFo/yGOszQl5REo2MeJeSftxXKjVOG/PWLUTemTpjw6jWthNzERvfPETJUZb86VFVNEK5io= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1727742033; c=relaxed/simple; bh=2ptCQpVMnHWaOaDmDBPPCdoy5ML1jYi83Mp2dZ9qdJ8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cxVBVU+VY1FUCvOCELZtX/sP2l52t5AwwihkstxVDKH3RiZ8d5bAV7+TT1KZkvSey/q2snY6S8BQQMM4SamB4bXBIEzkQqrW6r2t/n97wQumpbX4/QaIRj7sJGKNmipKcRSJSbxAmPgAnJbMZj0OXUyV9TW3aBnOqUh1DHwOod8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uzy7jiRM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uzy7jiRM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4EBFAC4CECD; Tue, 1 Oct 2024 00:20:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1727742032; bh=2ptCQpVMnHWaOaDmDBPPCdoy5ML1jYi83Mp2dZ9qdJ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uzy7jiRMx0AlBdm3+NYAIQKTb9ypbgxGe+tz4q9m6f4tnIY2M2F+BnOwPBQ3ViifG WlC0f70tkXj8Ifnx0Tr44mgiUSF5CjHiM4qSn6jW+KInM89vUgMMDb/jKGpiiPRTNj cGw1J2ajYHe4iwdTWeIp4BgfNTZ0u3zUAKy12figJJynnf7BHSweo1H1DH1lkVMmga yAk0vRK9+76rPXJP27isX36ht7hDvc7X2ddviurq5dSEqOtHvXK+dwBQbDp4HGTYJv Owx5emK8Pf5ylITWARiDcPyJUcNMOyc2xMFBK89pJl/gUPVSd146ZG2NViYHFNaO3p vPCy1JeRByRVQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Ravi Bangoria , Mark Rutland , James Clark , Kajol Jain , Thomas Richter , Atish Patra , Palmer Dabbelt , Mingwei Zhang Subject: [PATCH 5/8] perf tools: Detect missing kernel features properly Date: Mon, 30 Sep 2024 17:20:24 -0700 Message-ID: <20241001002027.1272889-6-namhyung@kernel.org> X-Mailer: git-send-email 2.46.1.824.gd892dcdcdd-goog In-Reply-To: <20241001002027.1272889-1-namhyung@kernel.org> References: <20241001002027.1272889-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The evsel__detect_missing_features() is to check if the attributes of the evsel is supported or not. But it checks the attribute based on the given evsel, it might miss something if the attr doesn't have the bit or give incorrect results if the event is special. Also it maintains the order of the feature that was added to the kernel which means it can assume older features should be supported once it detects the current feature is working. To minimized the confusion and to accurately check the kernel features, I think it's better to use a software event and go through all the features at once. Also make the function static since it's only used in evsel.c. Signed-off-by: Namhyung Kim --- tools/perf/util/evsel.c | 345 +++++++++++++++++++++++++++++----------- tools/perf/util/evsel.h | 1 - 2 files changed, 249 insertions(+), 97 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f202d28147d62a44..32e30c293d0c6198 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2150,120 +2151,272 @@ int evsel__prepare_open(struct evsel *evsel, stru= ct perf_cpu_map *cpus, return err; } =20 -bool evsel__detect_missing_features(struct evsel *evsel) +static bool has_attr_feature(struct perf_event_attr *attr, unsigned long f= lags) { + int fd =3D syscall(SYS_perf_event_open, attr, /*pid=3D*/0, /*cpu=3D*/-1, + /*group_fd=3D*/-1, flags); + close(fd); + + if (fd < 0) { + attr->exclude_kernel =3D 1; + + fd =3D syscall(SYS_perf_event_open, attr, /*pid=3D*/0, /*cpu=3D*/-1, + /*group_fd=3D*/-1, flags); + close(fd); + } + + if (fd < 0) { + attr->exclude_hv =3D 1; + + fd =3D syscall(SYS_perf_event_open, attr, /*pid=3D*/0, /*cpu=3D*/-1, + /*group_fd=3D*/-1, flags); + close(fd); + } + + if (fd < 0) { + attr->exclude_guest =3D 1; + + fd =3D syscall(SYS_perf_event_open, attr, /*pid=3D*/0, /*cpu=3D*/-1, + /*group_fd=3D*/-1, flags); + close(fd); + } + + attr->exclude_kernel =3D 0; + attr->exclude_guest =3D 0; + attr->exclude_hv =3D 0; + + return fd >=3D 0; +} + +static void evsel__detect_missing_brstack_features(struct evsel *evsel) +{ + static bool detection_done =3D false; + struct perf_event_attr attr =3D { + .type =3D evsel->core.attr.type, + .config =3D evsel->core.attr.config, + .disabled =3D 1, + .sample_type =3D PERF_SAMPLE_BRANCH_STACK, + .sample_period =3D 1000, + }; + int old_errno; + + if (detection_done) + return; + + old_errno =3D errno; + /* * Must probe features in the order they were added to the - * perf_event_attr interface. + * perf_event_attr interface. These are PMU specific limitation + * so we can detect with the given hardware event and stop on the + * first one succeeded. */ - if (!perf_missing_features.branch_counters && - (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) { - perf_missing_features.branch_counters =3D true; - pr_debug2("switching off branch counters support\n"); - return true; - } else if (!perf_missing_features.read_lost && - (evsel->core.attr.read_format & PERF_FORMAT_LOST)) { - perf_missing_features.read_lost =3D true; - pr_debug2("switching off PERF_FORMAT_LOST support\n"); + + /* Please add new feature detection here. */ + + attr.branch_sample_type =3D PERF_SAMPLE_BRANCH_COUNTERS; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.branch_counters =3D true; + pr_debug2("switching off branch counters support\n"); + + attr.branch_sample_type =3D PERF_SAMPLE_BRANCH_HW_INDEX; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.branch_hw_idx =3D true; + pr_debug2("switching off branch HW index support\n"); + + attr.branch_sample_type =3D PERF_SAMPLE_BRANCH_NO_CYCLES | PERF_SAMPLE_BR= ANCH_NO_FLAGS; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.lbr_flags =3D true; + pr_debug2_peo("switching off branch sample type no (cycles/flags)\n"); + +found: + detection_done =3D true; + errno =3D old_errno; +} + +static bool evsel__detect_missing_features(struct evsel *evsel) +{ + static bool detection_done =3D false; + struct perf_event_attr attr =3D { + .type =3D PERF_TYPE_SOFTWARE, + .config =3D PERF_COUNT_SW_TASK_CLOCK, + .disabled =3D 1, + }; + int old_errno; + + if (evsel__has_br_stack(evsel)) + evsel__detect_missing_brstack_features(evsel); + + if (detection_done) + goto check; + + old_errno =3D errno; + + /* + * Must probe features in the order they were added to the + * perf_event_attr interface. These are kernel core limitation + * not PMU-specific so we can detect with a software event and + * stop on the first one succeeded. + */ + + /* Please add new feature detection here. */ + + attr.read_format =3D PERF_FORMAT_LOST; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.read_lost =3D true; + pr_debug2("switching off PERF_FORMAT_LOST support\n"); + attr.read_format =3D 0; + + attr.sample_type =3D PERF_SAMPLE_WEIGHT_STRUCT; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.weight_struct =3D true; + pr_debug2("switching off weight struct support\n"); + attr.sample_type =3D 0; + + attr.sample_type =3D PERF_SAMPLE_CODE_PAGE_SIZE; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.code_page_size =3D true; + pr_debug2_peo("Kernel has no PERF_SAMPLE_CODE_PAGE_SIZE support\n"); + attr.sample_type =3D 0; + + attr.sample_type =3D PERF_SAMPLE_DATA_PAGE_SIZE; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.data_page_size =3D true; + pr_debug2_peo("Kernel has no PERF_SAMPLE_DATA_PAGE_SIZE support\n"); + attr.sample_type =3D 0; + + attr.cgroup =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.cgroup =3D true; + pr_debug2_peo("Kernel has no cgroup sampling support\n"); + attr.cgroup =3D 0; + + attr.aux_output =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.aux_output =3D true; + pr_debug2_peo("Kernel has no attr.aux_output support\n"); + attr.aux_output =3D 0; + + attr.bpf_event =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.bpf =3D true; + pr_debug2_peo("switching off bpf_event\n"); + attr.bpf_event =3D 0; + + attr.ksymbol =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.ksymbol =3D true; + pr_debug2_peo("switching off ksymbol\n"); + attr.ksymbol =3D 0; + + attr.write_backward =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.write_backward =3D true; + pr_debug2_peo("switching off write_backward\n"); + attr.write_backward =3D 0; + + attr.use_clockid =3D 1; + attr.clockid =3D CLOCK_MONOTONIC; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.clockid =3D true; + pr_debug2_peo("switching off clockid\n"); + attr.use_clockid =3D 0; + attr.clockid =3D 0; + + if (has_attr_feature(&attr, /*flags=3D*/PERF_FLAG_FD_CLOEXEC)) + goto found; + perf_missing_features.cloexec =3D true; + pr_debug2_peo("switching off cloexec flag\n"); + + attr.mmap2 =3D 1; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.mmap2 =3D true; + pr_debug2_peo("switching off mmap2\n"); + attr.mmap2 =3D 0; + + /* set this unconditionally? */ + perf_missing_features.sample_id_all =3D true; + pr_debug2_peo("switching off sample_id_all\n"); + + attr.inherit =3D 1; + attr.read_format =3D PERF_FORMAT_GROUP; + if (has_attr_feature(&attr, /*flags=3D*/0)) + goto found; + perf_missing_features.group_read =3D true; + pr_debug2_peo("switching off group read\n"); + attr.inherit =3D 0; + attr.read_format =3D 0; + +found: + detection_done =3D true; + errno =3D old_errno; + +check: + if ((evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) && + perf_missing_features.branch_counters) return true; - } else if (!perf_missing_features.weight_struct && - (evsel->core.attr.sample_type & PERF_SAMPLE_WEIGHT_STRUCT)) { - perf_missing_features.weight_struct =3D true; - pr_debug2("switching off weight struct support\n"); + + if ((evsel->core.attr.read_format & PERF_FORMAT_LOST) && + perf_missing_features.read_lost) return true; - } else if (!perf_missing_features.code_page_size && - (evsel->core.attr.sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)) { - perf_missing_features.code_page_size =3D true; - pr_debug2_peo("Kernel has no PERF_SAMPLE_CODE_PAGE_SIZE support, bailing= out\n"); - return false; - } else if (!perf_missing_features.data_page_size && - (evsel->core.attr.sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)) { - perf_missing_features.data_page_size =3D true; - pr_debug2_peo("Kernel has no PERF_SAMPLE_DATA_PAGE_SIZE support, bailing= out\n"); - return false; - } else if (!perf_missing_features.cgroup && evsel->core.attr.cgroup) { - perf_missing_features.cgroup =3D true; - pr_debug2_peo("Kernel has no cgroup sampling support, bailing out\n"); - return false; - } else if (!perf_missing_features.branch_hw_idx && - (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)) { - perf_missing_features.branch_hw_idx =3D true; - pr_debug2("switching off branch HW index support\n"); + + if ((evsel->core.attr.sample_type & PERF_SAMPLE_WEIGHT_STRUCT) && + perf_missing_features.weight_struct) return true; - } else if (!perf_missing_features.aux_output && evsel->core.attr.aux_outp= ut) { - perf_missing_features.aux_output =3D true; - pr_debug2_peo("Kernel has no attr.aux_output support, bailing out\n"); - return false; - } else if (!perf_missing_features.bpf && evsel->core.attr.bpf_event) { - perf_missing_features.bpf =3D true; - pr_debug2_peo("switching off bpf_event\n"); + + if (evsel->core.attr.use_clockid && evsel->core.attr.clockid !=3D CLOCK_M= ONOTONIC && + !perf_missing_features.clockid) { + perf_missing_features.clockid_wrong =3D true; return true; - } else if (!perf_missing_features.ksymbol && evsel->core.attr.ksymbol) { - perf_missing_features.ksymbol =3D true; - pr_debug2_peo("switching off ksymbol\n"); + } + + if (evsel->core.attr.use_clockid && perf_missing_features.clockid) return true; - } else if (!perf_missing_features.write_backward && evsel->core.attr.writ= e_backward) { - perf_missing_features.write_backward =3D true; - pr_debug2_peo("switching off write_backward\n"); - return false; - } else if (!perf_missing_features.clockid_wrong && evsel->core.attr.use_c= lockid) { - perf_missing_features.clockid_wrong =3D true; - pr_debug2_peo("switching off clockid\n"); + + if ((evsel->open_flags & PERF_FLAG_FD_CLOEXEC) && + perf_missing_features.cloexec) return true; - } else if (!perf_missing_features.clockid && evsel->core.attr.use_clockid= ) { - perf_missing_features.clockid =3D true; - pr_debug2_peo("switching off use_clockid\n"); + + if (evsel->core.attr.mmap2 && perf_missing_features.mmap2) return true; - } else if (!perf_missing_features.cloexec && (evsel->open_flags & PERF_FL= AG_FD_CLOEXEC)) { - perf_missing_features.cloexec =3D true; - pr_debug2_peo("switching off cloexec flag\n"); + + if ((evsel->core.attr.branch_sample_type & (PERF_SAMPLE_BRANCH_NO_FLAGS | + PERF_SAMPLE_BRANCH_NO_CYCLES)) && + perf_missing_features.lbr_flags) return true; - } else if (!perf_missing_features.mmap2 && evsel->core.attr.mmap2) { - perf_missing_features.mmap2 =3D true; - pr_debug2_peo("switching off mmap2\n"); + + if (evsel->core.attr.inherit && (evsel->core.attr.read_format & PERF_FORM= AT_GROUP) && + perf_missing_features.group_read) return true; - } else if (evsel->core.attr.exclude_guest || evsel->core.attr.exclude_hos= t) { - if (evsel->pmu =3D=3D NULL) - evsel->pmu =3D evsel__find_pmu(evsel); - - if (evsel->pmu) - evsel->pmu->missing_features.exclude_guest =3D true; - else { - /* we cannot find PMU, disable attrs now */ - evsel->core.attr.exclude_host =3D false; - evsel->core.attr.exclude_guest =3D false; - } =20 - if (evsel->exclude_GH) { - pr_debug2_peo("PMU has no exclude_host/guest support, bailing out\n"); - return false; - } - if (!perf_missing_features.exclude_guest) { - perf_missing_features.exclude_guest =3D true; - pr_debug2_peo("switching off exclude_guest, exclude_host\n"); - } + if (evsel->core.attr.ksymbol && perf_missing_features.ksymbol) return true; - } else if (!perf_missing_features.sample_id_all) { - perf_missing_features.sample_id_all =3D true; - pr_debug2_peo("switching off sample_id_all\n"); + + if (evsel->core.attr.bpf_event && perf_missing_features.bpf) return true; - } else if (!perf_missing_features.lbr_flags && - (evsel->core.attr.branch_sample_type & - (PERF_SAMPLE_BRANCH_NO_CYCLES | - PERF_SAMPLE_BRANCH_NO_FLAGS))) { - perf_missing_features.lbr_flags =3D true; - pr_debug2_peo("switching off branch sample type no (cycles/flags)\n"); + + if ((evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX) && + perf_missing_features.branch_hw_idx) return true; - } else if (!perf_missing_features.group_read && - evsel->core.attr.inherit && - (evsel->core.attr.read_format & PERF_FORMAT_GROUP) && - evsel__is_group_leader(evsel)) { - perf_missing_features.group_read =3D true; - pr_debug2_peo("switching off group read\n"); + + if (evsel->core.attr.sample_id_all && perf_missing_features.sample_id_all) return true; - } else { - return false; - } + + return false; } =20 static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3e751ea769ac4d3a..ea3140cd91c589fd 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -368,7 +368,6 @@ int evsel__open(struct evsel *evsel, struct perf_cpu_ma= p *cpus, void evsel__close(struct evsel *evsel); int evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, struct perf_thread_map *threads); -bool evsel__detect_missing_features(struct evsel *evsel); =20 bool evsel__precise_ip_fallback(struct evsel *evsel); =20 --=20 2.46.1.824.gd892dcdcdd-goog