From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 84576C38141 for ; Fri, 20 Jan 2023 14:40:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229902AbjATOj7 (ORCPT ); Fri, 20 Jan 2023 09:39:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42750 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229550AbjATOj5 (ORCPT ); Fri, 20 Jan 2023 09:39:57 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6B44CCE894; Fri, 20 Jan 2023 06:39:19 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 856AC1515; Fri, 20 Jan 2023 06:38:38 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 0BCF03F67D; Fri, 20 Jan 2023 06:37:53 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 1/8] perf: Remove duplication around EVENT_SOURCE_DEVICE_PATH Date: Fri, 20 Jan 2023 14:36:54 +0000 Message-Id: <20230120143702.4035046-2-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The pattern for accessing EVENT_SOURCE_DEVICE_PATH is duplicated in a few places, so add two utility functions to cover it. Also just use perf_pmu__scan_file() instead of pmu_type() which already does the same thing. No functional changes. Reviewed-by: Leo Yan Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/arch/arm/util/auxtrace.c | 5 +- tools/perf/arch/arm64/util/pmu.c | 4 +- tools/perf/arch/x86/util/pmu.c | 12 +-- tools/perf/util/pmu.c | 110 +++++++++++----------------- tools/perf/util/pmu.h | 5 +- 5 files changed, 51 insertions(+), 85 deletions(-) diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util= /auxtrace.c index deeb163999ce..adec6c9ee11d 100644 --- a/tools/perf/arch/arm/util/auxtrace.c +++ b/tools/perf/arch/arm/util/auxtrace.c @@ -55,17 +55,16 @@ static struct perf_pmu **find_all_arm_spe_pmus(int *nr_= spes, int *err) =20 static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err) { - const char *sysfs =3D sysfs__mountpoint(); struct perf_pmu **hisi_ptt_pmus =3D NULL; struct dirent *dent; char path[PATH_MAX]; DIR *dir =3D NULL; int idx =3D 0; =20 - snprintf(path, PATH_MAX, "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); + perf_pmu__event_source_devices_scnprintf(path, sizeof(path)); dir =3D opendir(path); if (!dir) { - pr_err("can't read directory '%s'\n", EVENT_SOURCE_DEVICE_PATH); + pr_err("can't read directory '%s'\n", path); *err =3D -EINVAL; return NULL; } diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/= pmu.c index 9e674cac5a73..801bf52e2ea6 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -44,8 +44,8 @@ double perf_pmu__cpu_slots_per_cycle(void) struct perf_pmu *pmu =3D pmu__find_core_pmu(); =20 if (pmu) { - scnprintf(path, PATH_MAX, - EVENT_SOURCE_DEVICE_PATH "%s/caps/slots", pmu->name); + perf_pmu__pathname_scnprintf(path, sizeof(path), + pmu->name, "caps/slots"); /* * The value of slots is not greater than 32 bits, but sysfs__read_int * can't read value with 0x prefix, so use sysfs__read_ull instead. diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index 74d69db1ea99..358340b34243 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -15,8 +15,6 @@ #include "../../../util/pmu.h" #include "../../../util/fncache.h" =20 -#define TEMPLATE_ALIAS "%s/bus/event_source/devices/%s/alias" - struct pmu_alias { char *name; char *alias; @@ -72,18 +70,14 @@ static int setup_pmu_alias_list(void) char path[PATH_MAX]; DIR *dir; struct dirent *dent; - const char *sysfs =3D sysfs__mountpoint(); struct pmu_alias *pmu_alias; char buf[MAX_PMU_NAME_LEN]; FILE *file; int ret =3D -ENOMEM; =20 - if (!sysfs) + if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) return -1; =20 - snprintf(path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); - dir =3D opendir(path); if (!dir) return -errno; @@ -93,9 +87,7 @@ static int setup_pmu_alias_list(void) !strcmp(dent->d_name, "..")) continue; =20 - snprintf(path, PATH_MAX, - TEMPLATE_ALIAS, sysfs, dent->d_name); - + perf_pmu__pathname_scnprintf(path, sizeof(path), dent->d_name, "alias"); if (!file_available(path)) continue; =20 diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index cbb4fbf124bd..1edbb714ff32 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -108,14 +108,10 @@ int perf_pmu__format_parse(char *dir, struct list_hea= d *head) static int pmu_format(const char *name, struct list_head *format) { char path[PATH_MAX]; - const char *sysfs =3D sysfs__mountpoint(); =20 - if (!sysfs) + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "format")) return -1; =20 - snprintf(path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); - if (!file_available(path)) return 0; =20 @@ -514,14 +510,10 @@ static int pmu_aliases_parse(char *dir, struct list_h= ead *head) static int pmu_aliases(const char *name, struct list_head *head) { char path[PATH_MAX]; - const char *sysfs =3D sysfs__mountpoint(); =20 - if (!sysfs) + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "events")) return -1; =20 - snprintf(path, PATH_MAX, - "%s/bus/event_source/devices/%s/events", sysfs, name); - if (!file_available(path)) return 0; =20 @@ -555,52 +547,16 @@ static int pmu_alias_terms(struct perf_pmu_alias *ali= as, return 0; } =20 -/* - * Reading/parsing the default pmu type value, which should be - * located at: - * /sys/bus/event_source/devices//type as sysfs attribute. - */ -static int pmu_type(const char *name, __u32 *type) -{ - char path[PATH_MAX]; - FILE *file; - int ret =3D 0; - const char *sysfs =3D sysfs__mountpoint(); - - if (!sysfs) - return -1; - - snprintf(path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); - - if (access(path, R_OK) < 0) - return -1; - - file =3D fopen(path, "r"); - if (!file) - return -EINVAL; - - if (1 !=3D fscanf(file, "%u", type)) - ret =3D -1; - - fclose(file); - return ret; -} - /* Add all pmus in sysfs to pmu list: */ static void pmu_read_sysfs(void) { char path[PATH_MAX]; DIR *dir; struct dirent *dent; - const char *sysfs =3D sysfs__mountpoint(); =20 - if (!sysfs) + if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) return; =20 - snprintf(path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); - dir =3D opendir(path); if (!dir) return; @@ -697,14 +653,9 @@ static char *pmu_id(const char *name) static int is_arm_pmu_core(const char *name) { char path[PATH_MAX]; - const char *sysfs =3D sysfs__mountpoint(); =20 - if (!sysfs) + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus")) return 0; - - /* Look for cpu sysfs (specific to arm) */ - scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", - sysfs, name); return file_available(path); } =20 @@ -970,11 +921,8 @@ static struct perf_pmu *pmu_lookup(const char *lookup_= name) return NULL; =20 /* - * Check the type first to avoid unnecessary work. + * Check the aliases first to avoid unnecessary work. */ - if (pmu_type(name, &type)) - return NULL; - if (pmu_aliases(name, &aliases)) return NULL; =20 @@ -984,9 +932,14 @@ static struct perf_pmu *pmu_lookup(const char *lookup_= name) =20 pmu->cpus =3D pmu_cpumask(name); pmu->name =3D strdup(name); + if (!pmu->name) goto err; =20 + /* Read type, and ensure that type value is successfully assigned (return= 1) */ + if (perf_pmu__scan_file(pmu, "type", "%u", &type) !=3D 1) + goto err; + alias_name =3D pmu_find_alias_name(name); if (alias_name) { pmu->alias_name =3D strdup(alias_name); @@ -1787,16 +1740,11 @@ bool pmu_have_event(const char *pname, const char *= name) static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) { char path[PATH_MAX]; - const char *sysfs; =20 - sysfs =3D sysfs__mountpoint(); - if (!sysfs) + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) || + !file_available(path)) return NULL; =20 - snprintf(path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); - if (!file_available(path)) - return NULL; return fopen(path, "r"); } =20 @@ -1850,7 +1798,6 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu) { struct stat st; char caps_path[PATH_MAX]; - const char *sysfs =3D sysfs__mountpoint(); DIR *caps_dir; struct dirent *evt_ent; =20 @@ -1859,12 +1806,9 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu) =20 pmu->nr_caps =3D 0; =20 - if (!sysfs) + if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name= , "caps")) return -1; =20 - snprintf(caps_path, PATH_MAX, - "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name); - if (stat(caps_path, &st) < 0) { pmu->caps_initialized =3D true; return 0; /* no error if caps does not exist */ @@ -1999,3 +1943,31 @@ double __weak perf_pmu__cpu_slots_per_cycle(void) { return NAN; } + +int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) +{ + const char *sysfs =3D sysfs__mountpoint(); + + if (!sysfs) + return 0; + return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); +} + +/* + * Fill 'buf' with the path to a file or folder in 'pmu_name' in + * sysfs. For example if pmu_name =3D "cs_etm" and 'filename' =3D "format" + * then pathname will be filled with + * "/sys/bus/event_source/devices/cs_etm/format" + * + * Return 0 if the sysfs mountpoint couldn't be found or if no + * characters were written. + */ +int perf_pmu__pathname_scnprintf(char *buf, size_t size, + const char *pmu_name, const char *filename) +{ + char base_path[PATH_MAX]; + + if (!perf_pmu__event_source_devices_scnprintf(base_path, sizeof(base_path= ))) + return 0; + return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); +} diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index fd414ba1d776..96d030c8b3b3 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -22,7 +22,6 @@ enum { }; =20 #define PERF_PMU_FORMAT_BITS 64 -#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" #define MAX_PMU_NAME_LEN 128 =20 @@ -260,4 +259,8 @@ int perf_pmu__cpus_match(struct perf_pmu *pmu, struct p= erf_cpu_map *cpus, char *pmu_find_real_name(const char *name); char *pmu_find_alias_name(const char *name); double perf_pmu__cpu_slots_per_cycle(void); +int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size); +int perf_pmu__pathname_scnprintf(char *buf, size_t size, + const char *pmu_name, const char *filename); + #endif /* __PMU_H */ --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 248ABC25B4E for ; Fri, 20 Jan 2023 14:39:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229730AbjATOj5 (ORCPT ); Fri, 20 Jan 2023 09:39:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229540AbjATOjz (ORCPT ); Fri, 20 Jan 2023 09:39:55 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 54BB072C36; Fri, 20 Jan 2023 06:39:16 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id EDA7D1516; Fri, 20 Jan 2023 06:38:42 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 74A7A3F67D; Fri, 20 Jan 2023 06:37:58 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 2/8] perf: Use perf_pmu__open_file() and perf_pmu__scan_file() Date: Fri, 20 Jan 2023 14:36:55 +0000 Message-Id: <20230120143702.4035046-3-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Remove some code that duplicates existing methods. Copy strings where const strings are required. No functional changes. Reviewed-by: Leo Yan Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/util/cputopo.c | 9 +------- tools/perf/util/pmu-hybrid.c | 27 +++++------------------- tools/perf/util/pmu.c | 40 +++++++++++------------------------- tools/perf/util/pmu.h | 3 ++- 4 files changed, 20 insertions(+), 59 deletions(-) diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c index 1a3ff6449158..e08797c3cdbc 100644 --- a/tools/perf/util/cputopo.c +++ b/tools/perf/util/cputopo.c @@ -422,8 +422,6 @@ void numa_topology__delete(struct numa_topology *tp) static int load_hybrid_node(struct hybrid_topology_node *node, struct perf_pmu *pmu) { - const char *sysfs; - char path[PATH_MAX]; char *buf =3D NULL, *p; FILE *fp; size_t len =3D 0; @@ -432,12 +430,7 @@ static int load_hybrid_node(struct hybrid_topology_nod= e *node, if (!node->pmu_name) return -1; =20 - sysfs =3D sysfs__mountpoint(); - if (!sysfs) - goto err; - - snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, pmu->name); - fp =3D fopen(path, "r"); + fp =3D perf_pmu__open_file(pmu, "cpus"); if (!fp) goto err; =20 diff --git a/tools/perf/util/pmu-hybrid.c b/tools/perf/util/pmu-hybrid.c index f51ccaac60ee..38628805a952 100644 --- a/tools/perf/util/pmu-hybrid.c +++ b/tools/perf/util/pmu-hybrid.c @@ -20,32 +20,15 @@ LIST_HEAD(perf_pmu__hybrid_pmus); =20 bool perf_pmu__hybrid_mounted(const char *name) { - char path[PATH_MAX]; - const char *sysfs; - FILE *file; - int n, cpu; + int cpu; + char pmu_name[PATH_MAX]; + struct perf_pmu pmu =3D {.name =3D pmu_name}; =20 if (strncmp(name, "cpu_", 4)) return false; =20 - sysfs =3D sysfs__mountpoint(); - if (!sysfs) - return false; - - snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, name); - if (!file_available(path)) - return false; - - file =3D fopen(path, "r"); - if (!file) - return false; - - n =3D fscanf(file, "%u", &cpu); - fclose(file); - if (n <=3D 0) - return false; - - return true; + strlcpy(pmu_name, name, sizeof(pmu_name)); + return perf_pmu__scan_file(&pmu, "cpus", "%u", &cpu) > 0; } =20 struct perf_pmu *perf_pmu__find_hybrid_pmu(const char *name) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 1edbb714ff32..a771a5972fc5 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -571,45 +571,31 @@ static void pmu_read_sysfs(void) closedir(dir); } =20 -static struct perf_cpu_map *__pmu_cpumask(const char *path) -{ - FILE *file; - struct perf_cpu_map *cpus; - - file =3D fopen(path, "r"); - if (!file) - return NULL; - - cpus =3D perf_cpu_map__read(file); - fclose(file); - return cpus; -} - /* * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/ar= m64) * may have a "cpus" file. */ #define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" -#define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" =20 static struct perf_cpu_map *pmu_cpumask(const char *name) { - char path[PATH_MAX]; struct perf_cpu_map *cpus; - const char *sysfs =3D sysfs__mountpoint(); const char *templates[] =3D { - CPUS_TEMPLATE_UNCORE, - CPUS_TEMPLATE_CPU, + "cpumask", + "cpus", NULL }; const char **template; + char pmu_name[PATH_MAX]; + struct perf_pmu pmu =3D {.name =3D pmu_name}; + FILE *file; =20 - if (!sysfs) - return NULL; - + strlcpy(pmu_name, name, sizeof(pmu_name)); for (template =3D templates; *template; template++) { - snprintf(path, PATH_MAX, *template, sysfs, name); - cpus =3D __pmu_cpumask(path); + file =3D perf_pmu__open_file(&pmu, *template); + if (!file) + continue; + cpus =3D perf_cpu_map__read(file); if (cpus) return cpus; } @@ -620,13 +606,11 @@ static struct perf_cpu_map *pmu_cpumask(const char *n= ame) static bool pmu_is_uncore(const char *name) { char path[PATH_MAX]; - const char *sysfs; =20 if (perf_pmu__hybrid_mounted(name)) return false; =20 - sysfs =3D sysfs__mountpoint(); - snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); + perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpumask"); return file_available(path); } =20 @@ -1737,7 +1721,7 @@ bool pmu_have_event(const char *pname, const char *na= me) return false; } =20 -static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) +FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) { char path[PATH_MAX]; =20 diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 96d030c8b3b3..742d4db319a0 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "parse-events.h" #include "pmu-events/pmu-events.h" =20 @@ -22,7 +23,6 @@ enum { }; =20 #define PERF_PMU_FORMAT_BITS 64 -#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" #define MAX_PMU_NAME_LEN 128 =20 struct perf_event_attr; @@ -262,5 +262,6 @@ double perf_pmu__cpu_slots_per_cycle(void); int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size); int perf_pmu__pathname_scnprintf(char *buf, size_t size, const char *pmu_name, const char *filename); +FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name); =20 #endif /* __PMU_H */ --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F237CC25B4E for ; Fri, 20 Jan 2023 14:50:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230056AbjATOur (ORCPT ); Fri, 20 Jan 2023 09:50:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229635AbjATOuo (ORCPT ); Fri, 20 Jan 2023 09:50:44 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id AB2A513B; Fri, 20 Jan 2023 06:50:42 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 577A5152B; Fri, 20 Jan 2023 06:38:47 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id D1E673F67D; Fri, 20 Jan 2023 06:38:02 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 3/8] perf: Remove remaining duplication of bus/event_source/devices/... Date: Fri, 20 Jan 2023 14:36:56 +0000 Message-Id: <20230120143702.4035046-4-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Use the new perf_pmu__pathname_scnprintf() instead. No functional changes. Reviewed-by: Leo Yan Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/util/pmu.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index a771a5972fc5..23e1d70fa343 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -575,8 +575,6 @@ static void pmu_read_sysfs(void) * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/ar= m64) * may have a "cpus" file. */ -#define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" - static struct perf_cpu_map *pmu_cpumask(const char *name) { struct perf_cpu_map *cpus; @@ -619,9 +617,9 @@ static char *pmu_id(const char *name) char path[PATH_MAX], *str; size_t len; =20 - snprintf(path, PATH_MAX, SYS_TEMPLATE_ID, name); + perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier"); =20 - if (sysfs__read_str(path, &str, &len) < 0) + if (filename__read_str(path, &str, &len) < 0) return NULL; =20 str[len - 1] =3D 0; /* remove line feed */ @@ -867,16 +865,11 @@ pmu_find_alias_name(const char *name __maybe_unused) return NULL; } =20 -static int pmu_max_precise(const char *name) +static int pmu_max_precise(struct perf_pmu *pmu) { - char path[PATH_MAX]; int max_precise =3D -1; =20 - scnprintf(path, PATH_MAX, - "bus/event_source/devices/%s/caps/max_precise", - name); - - sysfs__read_int(path, &max_precise); + perf_pmu__scan_file(pmu, "caps/max_precise", "%d", &max_precise); return max_precise; } =20 @@ -935,7 +928,7 @@ static struct perf_pmu *pmu_lookup(const char *lookup_n= ame) pmu->is_uncore =3D pmu_is_uncore(name); if (pmu->is_uncore) pmu->id =3D pmu_id(name); - pmu->max_precise =3D pmu_max_precise(name); + pmu->max_precise =3D pmu_max_precise(pmu); pmu_add_cpu_aliases(&aliases, pmu); pmu_add_sys_aliases(&aliases, pmu); =20 --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 62448C27C7C for ; Fri, 20 Jan 2023 14:40:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229904AbjATOkI (ORCPT ); Fri, 20 Jan 2023 09:40:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230042AbjATOkE (ORCPT ); Fri, 20 Jan 2023 09:40:04 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C6BB96191; Fri, 20 Jan 2023 06:39:25 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D4A671576; Fri, 20 Jan 2023 06:38:51 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3F5FB3F67D; Fri, 20 Jan 2023 06:38:07 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, German Gomez , James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 4/8] perf pmu: Add function to check if a pmu file exists Date: Fri, 20 Jan 2023 14:36:57 +0000 Message-Id: <20230120143702.4035046-5-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: German Gomez Add a utility function perf_pmu__file_exists() to check if a given pmu file exists in the sysfs filesystem. Signed-off-by: German Gomez Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/util/pmu.c | 10 ++++++++++ tools/perf/util/pmu.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 23e1d70fa343..8abf5b8439a7 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1742,6 +1742,16 @@ int perf_pmu__scan_file(struct perf_pmu *pmu, const = char *name, const char *fmt, return ret; } =20 +bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name) +{ + char path[PATH_MAX]; + + if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name)) + return false; + + return file_available(path); +} + static int perf_pmu__new_caps(struct list_head *list, char *name, char *va= lue) { struct perf_pmu_caps *caps =3D zalloc(sizeof(*caps)); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 742d4db319a0..2bdc560f19c7 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -230,6 +230,8 @@ bool pmu_have_event(const char *pname, const char *name= ); =20 int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char= *fmt, ...) __scanf(3, 4); =20 +bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name); + int perf_pmu__test(void); =20 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CCB52C27C7C for ; Fri, 20 Jan 2023 14:41:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230271AbjATOlS (ORCPT ); Fri, 20 Jan 2023 09:41:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230437AbjATOlQ (ORCPT ); Fri, 20 Jan 2023 09:41:16 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1414D51C52; Fri, 20 Jan 2023 06:40:54 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 61C851595; Fri, 20 Jan 2023 06:38:56 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C0E4E3F67D; Fri, 20 Jan 2023 06:38:11 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, German Gomez , James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 5/8] perf cs_etm: Keep separate symbols for ETMv4 and ETE parameters Date: Fri, 20 Jan 2023 14:36:58 +0000 Message-Id: <20230120143702.4035046-6-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: German Gomez Previously, adding a new parameter at the end of ETMv4 meant adding it somewhere in the middle of ETE, which is not supported by the current header version. Reviewed-by: Mike Leach Signed-off-by: German Gomez Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/arch/arm/util/cs-etm.c | 43 ++++++++++++++++++++++++++----- tools/perf/util/cs-etm-base.c | 32 +++++++++++++++++------ tools/perf/util/cs-etm.c | 12 ++++----- tools/perf/util/cs-etm.h | 11 +++++++- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/c= s-etm.c index a346d5f3dafa..b526ffe550a5 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -53,7 +53,15 @@ static const char * const metadata_etmv4_ro[] =3D { [CS_ETMV4_TRCIDR2] =3D "trcidr/trcidr2", [CS_ETMV4_TRCIDR8] =3D "trcidr/trcidr8", [CS_ETMV4_TRCAUTHSTATUS] =3D "mgmt/trcauthstatus", - [CS_ETE_TRCDEVARCH] =3D "mgmt/trcdevarch" +}; + +static const char * const metadata_ete_ro[] =3D { + [CS_ETE_TRCIDR0] =3D "trcidr/trcidr0", + [CS_ETE_TRCIDR1] =3D "trcidr/trcidr1", + [CS_ETE_TRCIDR2] =3D "trcidr/trcidr2", + [CS_ETE_TRCIDR8] =3D "trcidr/trcidr8", + [CS_ETE_TRCAUTHSTATUS] =3D "mgmt/trcauthstatus", + [CS_ETE_TRCDEVARCH] =3D "mgmt/trcdevarch", }; =20 static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); @@ -617,7 +625,7 @@ static bool cs_etm_is_ete(struct auxtrace_record *itr, = int cpu) { struct cs_etm_recording *ptr =3D container_of(itr, struct cs_etm_recordin= g, itr); struct perf_pmu *cs_etm_pmu =3D ptr->cs_etm_pmu; - int trcdevarch =3D cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ET= E_TRCDEVARCH]); + int trcdevarch =3D cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_= TRCDEVARCH]); =20 /* * ETE if ARCHVER is 5 (ARCHVER is 4 for ETM) and ARCHPART is 0xA13. @@ -648,6 +656,31 @@ static void cs_etm_save_etmv4_header(__u64 data[], str= uct auxtrace_record *itr, metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); } =20 +static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *i= tr, int cpu) +{ + struct cs_etm_recording *ptr =3D container_of(itr, struct cs_etm_recordin= g, itr); + struct perf_pmu *cs_etm_pmu =3D ptr->cs_etm_pmu; + + /* Get trace configuration register */ + data[CS_ETE_TRCCONFIGR] =3D cs_etmv4_get_config(itr); + /* Get traceID from the framework */ + data[CS_ETE_TRCTRACEIDR] =3D coresight_get_trace_id(cpu); + /* Get read-only information from sysFS */ + data[CS_ETE_TRCIDR0] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCIDR0]); + data[CS_ETE_TRCIDR1] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCIDR1]); + data[CS_ETE_TRCIDR2] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCIDR2]); + data[CS_ETE_TRCIDR8] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCIDR8]); + data[CS_ETE_TRCAUTHSTATUS] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCAUTHSTATUS]); + /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ + data[CS_ETE_TRCDEVARCH] =3D cs_etm_get_ro(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TRCDEVARCH]); +} + static void cs_etm_get_metadata(int cpu, u32 *offset, struct auxtrace_record *itr, struct perf_record_auxtrace_info *info) @@ -661,11 +694,7 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, /* first see what kind of tracer this cpu is affined to */ if (cs_etm_is_ete(itr, cpu)) { magic =3D __perf_cs_ete_magic; - /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ - cs_etm_save_etmv4_header(&info->priv[*offset], itr, cpu); - info->priv[*offset + CS_ETE_TRCDEVARCH] =3D - cs_etm_get_ro(cs_etm_pmu, cpu, - metadata_etmv4_ro[CS_ETE_TRCDEVARCH]); + cs_etm_save_ete_header(&info->priv[*offset], itr, cpu); =20 /* How much space was used */ increment =3D CS_ETE_PRIV_MAX; diff --git a/tools/perf/util/cs-etm-base.c b/tools/perf/util/cs-etm-base.c index 597542410854..282042c6e944 100644 --- a/tools/perf/util/cs-etm-base.c +++ b/tools/perf/util/cs-etm-base.c @@ -36,7 +36,20 @@ static const char * const cs_etmv4_priv_fmts[] =3D { [CS_ETMV4_TRCIDR2] =3D " TRCIDR2 %llx\n", [CS_ETMV4_TRCIDR8] =3D " TRCIDR8 %llx\n", [CS_ETMV4_TRCAUTHSTATUS] =3D " TRCAUTHSTATUS %llx\n", - [CS_ETE_TRCDEVARCH] =3D " TRCDEVARCH %llx\n" +}; + +static const char * const cs_ete_priv_fmts[] =3D { + [CS_ETM_MAGIC] =3D " Magic number %llx\n", + [CS_ETM_CPU] =3D " CPU %lld\n", + [CS_ETM_NR_TRC_PARAMS] =3D " NR_TRC_PARAMS %llx\n", + [CS_ETE_TRCCONFIGR] =3D " TRCCONFIGR %llx\n", + [CS_ETE_TRCTRACEIDR] =3D " TRCTRACEIDR %llx\n", + [CS_ETE_TRCIDR0] =3D " TRCIDR0 %llx\n", + [CS_ETE_TRCIDR1] =3D " TRCIDR1 %llx\n", + [CS_ETE_TRCIDR2] =3D " TRCIDR2 %llx\n", + [CS_ETE_TRCIDR8] =3D " TRCIDR8 %llx\n", + [CS_ETE_TRCAUTHSTATUS] =3D " TRCAUTHSTATUS %llx\n", + [CS_ETE_TRCDEVARCH] =3D " TRCDEVARCH %llx\n", }; =20 static const char * const param_unk_fmt =3D @@ -96,19 +109,22 @@ static int cs_etm__print_cpu_metadata_v1(u64 *val, int= *offset) else fprintf(stdout, cs_etm_priv_fmts[j], val[i]); } - } else if (magic =3D=3D __perf_cs_etmv4_magic || magic =3D=3D __perf_cs_e= te_magic) { - /* - * ETE and ETMv4 can be printed in the same block because the number of = parameters - * is saved and they share the list of parameter names. ETE is also only= supported - * in V1 files. - */ + } else if (magic =3D=3D __perf_cs_etmv4_magic) { for (j =3D 0; j < total_params; j++, i++) { /* if newer record - could be excess params */ - if (j >=3D CS_ETE_PRIV_MAX) + if (j >=3D CS_ETMV4_PRIV_MAX) fprintf(stdout, param_unk_fmt, j, val[i]); else fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]); } + } else if (magic =3D=3D __perf_cs_ete_magic) { + for (j =3D 0; j < total_params; j++, i++) { + /* if newer record - could be excess params */ + if (j >=3D CS_ETE_PRIV_MAX) + fprintf(stdout, param_unk_fmt, j, val[i]); + else + fprintf(stdout, cs_ete_priv_fmts[j], val[i]); + } } else { /* failure - note bad magic value and error out */ fprintf(stdout, magic_unk_fmt, magic); diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 33303d03c2fa..879576d5f899 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -464,12 +464,12 @@ static void cs_etm__set_trace_param_ete(struct cs_etm= _trace_params *t_params, u64 **metadata =3D etm->metadata; =20 t_params[idx].protocol =3D CS_ETM_PROTO_ETE; - t_params[idx].ete.reg_idr0 =3D metadata[idx][CS_ETMV4_TRCIDR0]; - t_params[idx].ete.reg_idr1 =3D metadata[idx][CS_ETMV4_TRCIDR1]; - t_params[idx].ete.reg_idr2 =3D metadata[idx][CS_ETMV4_TRCIDR2]; - t_params[idx].ete.reg_idr8 =3D metadata[idx][CS_ETMV4_TRCIDR8]; - t_params[idx].ete.reg_configr =3D metadata[idx][CS_ETMV4_TRCCONFIGR]; - t_params[idx].ete.reg_traceidr =3D metadata[idx][CS_ETMV4_TRCTRACEIDR]; + t_params[idx].ete.reg_idr0 =3D metadata[idx][CS_ETE_TRCIDR0]; + t_params[idx].ete.reg_idr1 =3D metadata[idx][CS_ETE_TRCIDR1]; + t_params[idx].ete.reg_idr2 =3D metadata[idx][CS_ETE_TRCIDR2]; + t_params[idx].ete.reg_idr8 =3D metadata[idx][CS_ETE_TRCIDR8]; + t_params[idx].ete.reg_configr =3D metadata[idx][CS_ETE_TRCCONFIGR]; + t_params[idx].ete.reg_traceidr =3D metadata[idx][CS_ETE_TRCTRACEIDR]; t_params[idx].ete.reg_devarch =3D metadata[idx][CS_ETE_TRCDEVARCH]; } =20 diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index 5da50d5dae6b..c5925428afa9 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -82,7 +82,16 @@ enum { * added in header V1 */ enum { - CS_ETE_TRCDEVARCH =3D CS_ETMV4_PRIV_MAX, + /* Dynamic, configurable parameters */ + CS_ETE_TRCCONFIGR =3D CS_ETM_COMMON_BLK_MAX_V1, + CS_ETE_TRCTRACEIDR, + /* RO, taken from sysFS */ + CS_ETE_TRCIDR0, + CS_ETE_TRCIDR1, + CS_ETE_TRCIDR2, + CS_ETE_TRCIDR8, + CS_ETE_TRCAUTHSTATUS, + CS_ETE_TRCDEVARCH, CS_ETE_PRIV_MAX }; =20 --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B14ECC05027 for ; Fri, 20 Jan 2023 14:41:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231226AbjATOl2 (ORCPT ); Fri, 20 Jan 2023 09:41:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45276 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230437AbjATOlV (ORCPT ); Fri, 20 Jan 2023 09:41:21 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0B05BD05EA; Fri, 20 Jan 2023 06:40:59 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E7BBB1596; Fri, 20 Jan 2023 06:39:00 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 52B493F67D; Fri, 20 Jan 2023 06:38:16 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, German Gomez , James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 6/8] perf cs_etm: Record ts_source in AUXTRACE_INFO for ETMv4 and ETE Date: Fri, 20 Jan 2023 14:36:59 +0000 Message-Id: <20230120143702.4035046-7-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: German Gomez Read the value of ts_source exposed by the driver and store it in the ETMv4 and ETE header. If the interface doesn't exist (such as in older Kernels), defaults to a safe value of -1. Signed-off-by: German Gomez Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- tools/perf/arch/arm/util/cs-etm.c | 48 +++++++++++++++++++++++++++++++ tools/perf/util/cs-etm-base.c | 2 ++ tools/perf/util/cs-etm.h | 2 ++ 3 files changed, 52 insertions(+) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/c= s-etm.c index b526ffe550a5..481e170cd3f1 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -53,6 +53,7 @@ static const char * const metadata_etmv4_ro[] =3D { [CS_ETMV4_TRCIDR2] =3D "trcidr/trcidr2", [CS_ETMV4_TRCIDR8] =3D "trcidr/trcidr8", [CS_ETMV4_TRCAUTHSTATUS] =3D "mgmt/trcauthstatus", + [CS_ETMV4_TS_SOURCE] =3D "ts_source", }; =20 static const char * const metadata_ete_ro[] =3D { @@ -62,6 +63,7 @@ static const char * const metadata_ete_ro[] =3D { [CS_ETE_TRCIDR8] =3D "trcidr/trcidr8", [CS_ETE_TRCAUTHSTATUS] =3D "mgmt/trcauthstatus", [CS_ETE_TRCDEVARCH] =3D "mgmt/trcdevarch", + [CS_ETE_TS_SOURCE] =3D "ts_source", }; =20 static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); @@ -613,6 +615,32 @@ static int cs_etm_get_ro(struct perf_pmu *pmu, int cpu= , const char *path) return val; } =20 +static int cs_etm_get_ro_signed(struct perf_pmu *pmu, int cpu, const char = *path) +{ + char pmu_path[PATH_MAX]; + int scan; + int val =3D 0; + + /* Get RO metadata from sysfs */ + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); + + scan =3D perf_pmu__scan_file(pmu, pmu_path, "%d", &val); + if (scan !=3D 1) + pr_err("%s: error reading: %s\n", __func__, pmu_path); + + return val; +} + +static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, int cpu, const ch= ar *path) +{ + char pmu_path[PATH_MAX]; + + /* Get RO metadata from sysfs */ + snprintf(pmu_path, PATH_MAX, "cpu%d/%s", cpu, path); + + return perf_pmu__file_exists(pmu, pmu_path); +} + #define TRCDEVARCH_ARCHPART_SHIFT 0 #define TRCDEVARCH_ARCHPART_MASK GENMASK(11, 0) #define TRCDEVARCH_ARCHPART(x) (((x) & TRCDEVARCH_ARCHPART_MASK) >> TRC= DEVARCH_ARCHPART_SHIFT) @@ -654,6 +682,16 @@ static void cs_etm_save_etmv4_header(__u64 data[], str= uct auxtrace_record *itr, metadata_etmv4_ro[CS_ETMV4_TRCIDR8]); data[CS_ETMV4_TRCAUTHSTATUS] =3D cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCAUTHSTATUS]); + + /* Kernels older than 5.19 may not expose ts_source */ + if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TS= _SOURCE])) + data[CS_ETMV4_TS_SOURCE] =3D (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cp= u, + metadata_etmv4_ro[CS_ETMV4_TS_SOURCE]); + else { + pr_warning("[%03d] pmu file 'ts_source' not found. Fallback to safe valu= e (-1)\n", + cpu); + data[CS_ETMV4_TS_SOURCE] =3D (__u64) -1; + } } =20 static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *i= tr, int cpu) @@ -679,6 +717,16 @@ static void cs_etm_save_ete_header(__u64 data[], struc= t auxtrace_record *itr, in /* ETE uses the same registers as ETMv4 plus TRCDEVARCH */ data[CS_ETE_TRCDEVARCH] =3D cs_etm_get_ro(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TRCDEVARCH]); + + /* Kernels older than 5.19 may not expose ts_source */ + if (cs_etm_pmu_path_exists(cs_etm_pmu, cpu, metadata_ete_ro[CS_ETE_TS_SOU= RCE])) + data[CS_ETE_TS_SOURCE] =3D (__u64) cs_etm_get_ro_signed(cs_etm_pmu, cpu, + metadata_ete_ro[CS_ETE_TS_SOURCE]); + else { + pr_warning("[%03d] pmu file 'ts_source' not found. Fallback to safe valu= e (-1)\n", + cpu); + data[CS_ETE_TS_SOURCE] =3D (__u64) -1; + } } =20 static void cs_etm_get_metadata(int cpu, u32 *offset, diff --git a/tools/perf/util/cs-etm-base.c b/tools/perf/util/cs-etm-base.c index 282042c6e944..5f48b756c4cf 100644 --- a/tools/perf/util/cs-etm-base.c +++ b/tools/perf/util/cs-etm-base.c @@ -36,6 +36,7 @@ static const char * const cs_etmv4_priv_fmts[] =3D { [CS_ETMV4_TRCIDR2] =3D " TRCIDR2 %llx\n", [CS_ETMV4_TRCIDR8] =3D " TRCIDR8 %llx\n", [CS_ETMV4_TRCAUTHSTATUS] =3D " TRCAUTHSTATUS %llx\n", + [CS_ETMV4_TS_SOURCE] =3D " TS_SOURCE %lld\n", }; =20 static const char * const cs_ete_priv_fmts[] =3D { @@ -50,6 +51,7 @@ static const char * const cs_ete_priv_fmts[] =3D { [CS_ETE_TRCIDR8] =3D " TRCIDR8 %llx\n", [CS_ETE_TRCAUTHSTATUS] =3D " TRCAUTHSTATUS %llx\n", [CS_ETE_TRCDEVARCH] =3D " TRCDEVARCH %llx\n", + [CS_ETE_TS_SOURCE] =3D " TS_SOURCE %lld\n", }; =20 static const char * const param_unk_fmt =3D diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index c5925428afa9..ad790930bcbc 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -71,6 +71,7 @@ enum { CS_ETMV4_TRCIDR2, CS_ETMV4_TRCIDR8, CS_ETMV4_TRCAUTHSTATUS, + CS_ETMV4_TS_SOURCE, CS_ETMV4_PRIV_MAX, }; =20 @@ -92,6 +93,7 @@ enum { CS_ETE_TRCIDR8, CS_ETE_TRCAUTHSTATUS, CS_ETE_TRCDEVARCH, + CS_ETE_TS_SOURCE, CS_ETE_PRIV_MAX }; =20 --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2953FC25B4E for ; Fri, 20 Jan 2023 14:41:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231209AbjATOlZ (ORCPT ); Fri, 20 Jan 2023 09:41:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45304 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230498AbjATOlW (ORCPT ); Fri, 20 Jan 2023 09:41:22 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 8D402D0D88; Fri, 20 Jan 2023 06:40:59 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7C23A1650; Fri, 20 Jan 2023 06:39:05 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id DAF573F67D; Fri, 20 Jan 2023 06:38:20 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, German Gomez , James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 7/8] perf cs_etm: Set the time field in the synthetic samples Date: Fri, 20 Jan 2023 14:37:00 +0000 Message-Id: <20230120143702.4035046-8-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: German Gomez If virtual timestamps are detected, set sample time field accordingly, otherwise warn the user that the samples will not include accurate time data. | Test notes (FEAT_TRF platform) | | $ ./perf record -e cs_etm//u -a -- sleep 4 | $ ./perf script --fields +time | perf 422 [000] 163.375100: 1 branches:uH: = 0 [unknown] ([unknown]) | perf 422 [000] 163.375100: 1 branches:uH: ffffb80= 09544 ioctl+0x14 (/lib/aarch64-linux-gnu/libc-2.27.so) | perf 422 [000] 163.375100: 1 branches:uH: aaaaab6= bebf4 perf_evsel__run_ioctl+0x90 (/home/german/linux/tools/perf/perf) | [...] | perf 422 [000] 167.393100: 1 branches:uH: aaaaab6= bda00 __xyarray__entry+0x74 (/home/german/linux/tools/perf/perf) | perf 422 [000] 167.393099: 1 branches:uH: aaaaab6= bda0c __xyarray__entry+0x80 (/home/german/linux/tools/perf/perf) | perf 422 [000] 167.393099: 1 branches:uH: ffffb80= 09538 ioctl+0x8 (/lib/aarch64-linux-gnu/libc-2.27.so) | | The time from the first sample to the last sample is 4 seconds Now that times are converted to nanoseconds, also try to estimate the timestamps more accurately be dividing by some fixed value for instructions per ns. This prevents long ranges from being estimated too far in the past than would be realistic. Signed-off-by: German Gomez Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 47 +++++++++-- tools/perf/util/cs-etm.c | 83 ++++++++++++++++++- tools/perf/util/cs-etm.h | 3 +- 3 files changed, 120 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/u= til/cs-etm-decoder/cs-etm-decoder.c index 31fa3b45134a..440fe844ed17 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -30,6 +30,15 @@ #endif #endif =20 +/* + * Assume a maximum of 0.1ns elapsed per instruction. This would be the + * case with a theoretical 10GHz core executing 1 instruction per cycle. + * Used to estimate the sample time for synthesized instructions because + * Coresight only emits a timestamp for a range of instructions rather + * than per instruction. + */ +const u32 INSTR_PER_NS =3D 10; + struct cs_etm_decoder { void *data; void (*packet_printer)(const char *msg); @@ -112,6 +121,20 @@ int cs_etm_decoder__get_packet(struct cs_etm_packet_qu= eue *packet_queue, return 1; } =20 +/* + * Calculate the number of nanoseconds elapsed. + * + * instr_count is updated in place with the remainder of the instructions + * which didn't make up a whole nanosecond. + */ +static u32 cs_etm_decoder__dec_instr_count_to_ns(u32 *instr_count) +{ + const u32 instr_copy =3D *instr_count; + + *instr_count %=3D INSTR_PER_NS; + return instr_copy / INSTR_PER_NS; +} + static int cs_etm_decoder__gen_etmv3_config(struct cs_etm_trace_params *pa= rams, ocsd_etmv3_cfg *config) { @@ -267,8 +290,8 @@ cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue *= etmq, packet_queue->cs_timestamp =3D packet_queue->next_cs_timestamp; =20 /* Estimate the timestamp for the next range packet */ - packet_queue->next_cs_timestamp +=3D packet_queue->instr_count; - packet_queue->instr_count =3D 0; + packet_queue->next_cs_timestamp +=3D + cs_etm_decoder__dec_instr_count_to_ns(&packet_queue->instr_count); =20 /* Tell the front end which traceid_queue needs attention */ cs_etm__etmq_set_traceid_queue_timestamp(etmq, trace_chan_id); @@ -283,24 +306,31 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue= *etmq, const ocsd_trc_index_t indx) { struct cs_etm_packet_queue *packet_queue; + u64 converted_timestamp; =20 /* First get the packet queue for this traceID */ packet_queue =3D cs_etm__etmq_get_packet_queue(etmq, trace_chan_id); if (!packet_queue) return OCSD_RESP_FATAL_SYS_ERR; =20 + /* + * Coresight timestamps are raw timer values which need to be scaled to n= s. Assume + * 0 is a bad value so don't try to convert it. + */ + converted_timestamp =3D elem->timestamp ? + cs_etm__convert_sample_time(etmq, elem->timestamp) : 0; + /* * We've seen a timestamp packet before - simply record the new value. * Function do_soft_timestamp() will report the value to the front end, * hence asking the decoder to keep decoding rather than stopping. */ if (packet_queue->cs_timestamp) { - packet_queue->next_cs_timestamp =3D elem->timestamp; + packet_queue->next_cs_timestamp =3D converted_timestamp; return OCSD_RESP_CONT; } =20 - - if (!elem->timestamp) { + if (!converted_timestamp) { /* * Zero timestamps can be seen due to misconfiguration or hardware bugs. * Warn once, and don't try to subtract instr_count as it would result i= n an @@ -312,7 +342,7 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *= etmq, ". Decoding may be improved by prepending 'Z' to your current --itrac= e arguments.\n", indx); =20 - } else if (packet_queue->instr_count > elem->timestamp) { + } else if (packet_queue->instr_count / INSTR_PER_NS > converted_timestamp= ) { /* * Sanity check that the elem->timestamp - packet_queue->instr_count wou= ld not * result in an underflow. Warn and clamp at 0 if it would. @@ -327,9 +357,10 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue = *etmq, * which instructions started by subtracting the number of instructions * executed to the timestamp. */ - packet_queue->cs_timestamp =3D elem->timestamp - packet_queue->instr_cou= nt; + packet_queue->cs_timestamp =3D converted_timestamp - + (packet_queue->instr_count / INSTR_PER_NS); } - packet_queue->next_cs_timestamp =3D elem->timestamp; + packet_queue->next_cs_timestamp =3D converted_timestamp; packet_queue->instr_count =3D 0; =20 /* Tell the front end which traceid_queue needs attention */ diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 879576d5f899..f65bac5ddbdb 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -35,6 +35,7 @@ #include "tool.h" #include "thread.h" #include "thread-stack.h" +#include "tsc.h" #include #include "util/synthetic-events.h" =20 @@ -46,10 +47,12 @@ struct cs_etm_auxtrace { struct perf_session *session; struct machine *machine; struct thread *unknown_thread; + struct perf_tsc_conversion tc; =20 u8 timeless_decoding; u8 snapshot_mode; u8 data_queued; + u8 has_virtual_ts; /* Virtual/Kernel timestamps in the trace. */ =20 int num_cpu; u64 latest_kernel_timestamp; @@ -1161,6 +1164,30 @@ static void cs_etm__copy_insn(struct cs_etm_queue *e= tmq, sample->insn_len, (void *)sample->insn); } =20 +u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestam= p) +{ + struct cs_etm_auxtrace *etm =3D etmq->etm; + + if (etm->has_virtual_ts) + return tsc_to_perf_time(cs_timestamp, &etm->tc); + else + return cs_timestamp; +} + +static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq, + struct cs_etm_traceid_queue *tidq) +{ + struct cs_etm_auxtrace *etm =3D etmq->etm; + struct cs_etm_packet_queue *packet_queue =3D &tidq->packet_queue; + + if (etm->timeless_decoding) + return 0; + else if (etm->has_virtual_ts) + return packet_queue->cs_timestamp; + else + return etm->latest_kernel_timestamp; +} + static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, struct cs_etm_traceid_queue *tidq, u64 addr, u64 period) @@ -1174,8 +1201,9 @@ static int cs_etm__synth_instruction_sample(struct cs= _etm_queue *etmq, event->sample.header.misc =3D cs_etm__cpu_mode(etmq, addr); event->sample.header.size =3D sizeof(struct perf_event_header); =20 - if (!etm->timeless_decoding) - sample.time =3D etm->latest_kernel_timestamp; + /* Set time field based on etm auxtrace config. */ + sample.time =3D cs_etm__resolve_sample_time(etmq, tidq); + sample.ip =3D addr; sample.pid =3D tidq->pid; sample.tid =3D tidq->tid; @@ -1232,8 +1260,9 @@ static int cs_etm__synth_branch_sample(struct cs_etm_= queue *etmq, event->sample.header.misc =3D cs_etm__cpu_mode(etmq, ip); event->sample.header.size =3D sizeof(struct perf_event_header); =20 - if (!etm->timeless_decoding) - sample.time =3D etm->latest_kernel_timestamp; + /* Set time field based on etm auxtrace config. */ + sample.time =3D cs_etm__resolve_sample_time(etmq, tidq); + sample.ip =3D ip; sample.pid =3D tidq->pid; sample.tid =3D tidq->tid; @@ -2746,12 +2775,42 @@ static int cs_etm__queue_aux_records(struct perf_se= ssion *session) return 0; } =20 +#define HAS_PARAM(j, type, param) (metadata[(j)][CS_ETM_NR_TRC_PARAMS] <= =3D \ + (CS_##type##_##param - CS_ETM_COMMON_BLK_MAX_V1)) + +/* + * Loop through the ETMs and complain if we find at least one where ts_sou= rce !=3D 1 (virtual + * timestamps). + */ +static bool cs_etm__has_virtual_ts(u64 **metadata, int num_cpu) +{ + int j; + + for (j =3D 0; j < num_cpu; j++) { + switch (metadata[j][CS_ETM_MAGIC]) { + case __perf_cs_etmv4_magic: + if (HAS_PARAM(j, ETMV4, TS_SOURCE) || metadata[j][CS_ETMV4_TS_SOURCE] != =3D 1) + return false; + break; + case __perf_cs_ete_magic: + if (HAS_PARAM(j, ETE, TS_SOURCE) || metadata[j][CS_ETE_TS_SOURCE] !=3D = 1) + return false; + break; + default: + /* Unknown / unsupported magic number. */ + return false; + } + } + return true; +} + int cs_etm__process_auxtrace_info_full(union perf_event *event, struct perf_session *session) { struct perf_record_auxtrace_info *auxtrace_info =3D &event->auxtrace_info; struct cs_etm_auxtrace *etm =3D NULL; struct int_node *inode; + struct perf_record_time_conv *tc =3D &session->time_conv; int event_header_size =3D sizeof(struct perf_event_header); int total_size =3D auxtrace_info->header.size; int priv_size =3D 0; @@ -2886,6 +2945,13 @@ int cs_etm__process_auxtrace_info_full(union perf_ev= ent *event, etm->auxtrace_type =3D auxtrace_info->type; etm->timeless_decoding =3D cs_etm__is_timeless_decoding(etm); =20 + /* Use virtual timestamps if all ETMs report ts_source =3D 1 */ + etm->has_virtual_ts =3D cs_etm__has_virtual_ts(metadata, num_cpu); + + if (!etm->has_virtual_ts) + ui__warning("Virtual timestamps are not enabled, or not supported by the= traced system.\n" + "The time field of the samples will not be set accurately.\n\n"); + etm->auxtrace.process_event =3D cs_etm__process_event; etm->auxtrace.process_auxtrace_event =3D cs_etm__process_auxtrace_event; etm->auxtrace.flush_events =3D cs_etm__flush_events; @@ -2915,6 +2981,15 @@ int cs_etm__process_auxtrace_info_full(union perf_ev= ent *event, goto err_delete_thread; } =20 + etm->tc.time_shift =3D tc->time_shift; + etm->tc.time_mult =3D tc->time_mult; + etm->tc.time_zero =3D tc->time_zero; + if (event_contains(*tc, time_cycles)) { + etm->tc.time_cycles =3D tc->time_cycles; + etm->tc.time_mask =3D tc->time_mask; + etm->tc.cap_user_time_zero =3D tc->cap_user_time_zero; + etm->tc.cap_user_time_short =3D tc->cap_user_time_short; + } err =3D cs_etm__synth_events(etm, session); if (err) goto err_delete_thread; diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index ad790930bcbc..98a4f7113d2f 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -192,7 +192,7 @@ struct cs_etm_packet_queue { u32 head; u32 tail; u32 instr_count; - u64 cs_timestamp; + u64 cs_timestamp; /* Timestamp from trace data, converted to ns if possib= le */ u64 next_cs_timestamp; struct cs_etm_packet packet_buffer[CS_ETM_PACKET_MAX_BUFFER]; }; @@ -231,6 +231,7 @@ struct cs_etm_packet_queue *cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id= ); int cs_etm__process_auxtrace_info_full(union perf_event *event __maybe_unu= sed, struct perf_session *session __maybe_unused); +u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestam= p); #else static inline int cs_etm__process_auxtrace_info_full(union perf_event *event __maybe_unused, --=20 2.25.1 From nobody Sun Sep 14 14:31:04 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F654C25B4E for ; Fri, 20 Jan 2023 14:41:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230415AbjATOlg (ORCPT ); Fri, 20 Jan 2023 09:41:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231224AbjATOl1 (ORCPT ); Fri, 20 Jan 2023 09:41:27 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 25BBCDA8EA; Fri, 20 Jan 2023 06:41:04 -0800 (PST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DB1B61688; Fri, 20 Jan 2023 06:39:09 -0800 (PST) Received: from e126815.warwick.arm.com (e126815.arm.com [10.32.32.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6180D3F67D; Fri, 20 Jan 2023 06:38:25 -0800 (PST) From: James Clark To: linux-perf-users@vger.kernel.org, tanmay@marvell.com, leo.yan@linaro.org, mike.leach@linaro.org Cc: sgoutham@marvell.com, gcherian@marvell.com, lcherian@marvell.com, bbhushan2@marvell.com, James Clark , Mathieu Poirier , Suzuki K Poulose , John Garry , Will Deacon , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 8/8] perf: cs-etm: Ensure that Coresight timestamps don't go backwards Date: Fri, 20 Jan 2023 14:37:01 +0000 Message-Id: <20230120143702.4035046-9-james.clark@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230120143702.4035046-1-james.clark@arm.com> References: <20230120143702.4035046-1-james.clark@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" There are some edge cases around estimated timestamps that can result in them going backwards. One is that after a discontinuity, the last used timestamp is set to 0. The duration of the next range is then subtracted which could result in an earlier timestamp than the last instruction. Fix this by not resetting the last timestamp used on a discontinuity, and make sure that new estimated timestamps are clamped to be later than that. Another case is that estimated timestamps could compound over time to end up being more than the next real timestamp in the trace. Fix this by clamping the estimates in cs_etm_decoder__do_soft_timestamp() to be no later than it. cs_etm_decoder__do_soft_timestamp() also updated next_cs_timestamp, which meant that the next real timestamp was lost and not stored anywhere. Fix that by only updating cs_timestamp for estimates and keep next_cs_timestamp untouched. Finally, use next_cs_timestamp to signify if a timestamp has been received previously. Because cs_timestamp has the first range subtracted, it could technically go to 0 which would break the logic. Testing =3D=3D=3D=3D=3D=3D=3D It can be verified that timestamps don't go backwards when tracing on a single core with the following commands. Across multiple cores it's expected that timestamps are interleaved: $ perf record -e cs_etm/@tmc_etr0/k -C 4 taskset -c 4 sleep 1 $ perf script --itrace=3Di1ns --ns -Fcomm,tid,pid,time,cpu,event,ip,sym,ad= dr,symoff,flags,callindent > itrace $ sed 's/://g' itrace | awk -F ' ' ' { print $4 } ' | awk '{ if ($1 < prev= ) { print "line:" NR " " $0 } {prev=3D$1}}' Reported-by: Tanmay Jagdale Signed-off-by: James Clark Acked-by: Suzuki K Poulose Tested-by: Tanmay Jagdale --- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/u= til/cs-etm-decoder/cs-etm-decoder.c index 440fe844ed17..63afa2d05b46 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -283,15 +283,17 @@ cs_etm_decoder__do_soft_timestamp(struct cs_etm_queue= *etmq, struct cs_etm_packet_queue *packet_queue, const uint8_t trace_chan_id) { + u64 estimated_ts; + /* No timestamp packet has been received, nothing to do */ - if (!packet_queue->cs_timestamp) + if (!packet_queue->next_cs_timestamp) return OCSD_RESP_CONT; =20 - packet_queue->cs_timestamp =3D packet_queue->next_cs_timestamp; + estimated_ts =3D packet_queue->cs_timestamp + + cs_etm_decoder__dec_instr_count_to_ns(&packet_queue->instr_count); =20 - /* Estimate the timestamp for the next range packet */ - packet_queue->next_cs_timestamp +=3D - cs_etm_decoder__dec_instr_count_to_ns(&packet_queue->instr_count); + /* Estimated TS can never be higher than the next real one in the trace */ + packet_queue->cs_timestamp =3D min(packet_queue->next_cs_timestamp, estim= ated_ts); =20 /* Tell the front end which traceid_queue needs attention */ cs_etm__etmq_set_traceid_queue_timestamp(etmq, trace_chan_id); @@ -307,6 +309,7 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *= etmq, { struct cs_etm_packet_queue *packet_queue; u64 converted_timestamp; + u64 estimated_first_ts; =20 /* First get the packet queue for this traceID */ packet_queue =3D cs_etm__etmq_get_packet_queue(etmq, trace_chan_id); @@ -325,7 +328,12 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue = *etmq, * Function do_soft_timestamp() will report the value to the front end, * hence asking the decoder to keep decoding rather than stopping. */ - if (packet_queue->cs_timestamp) { + if (packet_queue->next_cs_timestamp) { + /* + * What was next is now where new ranges start from, overwriting + * any previous estimate in cs_timestamp + */ + packet_queue->cs_timestamp =3D packet_queue->next_cs_timestamp; packet_queue->next_cs_timestamp =3D converted_timestamp; return OCSD_RESP_CONT; } @@ -355,10 +363,12 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue= *etmq, * or a discontinuity. Since timestamps packets are generated *after* * range packets have been generated, we need to estimate the time at * which instructions started by subtracting the number of instructions - * executed to the timestamp. + * executed to the timestamp. Don't estimate earlier than the last used + * timestamp though. */ - packet_queue->cs_timestamp =3D converted_timestamp - - (packet_queue->instr_count / INSTR_PER_NS); + estimated_first_ts =3D converted_timestamp - + (packet_queue->instr_count / INSTR_PER_NS); + packet_queue->cs_timestamp =3D max(packet_queue->cs_timestamp, estimated= _first_ts); } packet_queue->next_cs_timestamp =3D converted_timestamp; packet_queue->instr_count =3D 0; @@ -373,7 +383,6 @@ cs_etm_decoder__do_hard_timestamp(struct cs_etm_queue *= etmq, static void cs_etm_decoder__reset_timestamp(struct cs_etm_packet_queue *packet_queue) { - packet_queue->cs_timestamp =3D 0; packet_queue->next_cs_timestamp =3D 0; packet_queue->instr_count =3D 0; } --=20 2.25.1