Re: [PATCH v4.13.y] perf pmu: Unbreak perf record for arm/arm64 with events with explicit PMU

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sorry all, I messed up, and this was generated from my v4.12 backports
branch.

There's a small difference in the context, so I will send the correct
patch shortly.

Sorry for the noise.

Thanks,
Mark.

On Tue, Oct 17, 2017 at 02:29:09PM +0100, Mark Rutland wrote:
> Commit 66ec11919a0f96e936bb731fdbc2851316077d26 upstream.
> 
> Currently, perf record is broken on arm/arm64 systems when the PMU is
> specified explicitly as part of the event, e.g.
> 
> $ ./perf record -e armv8_cortex_a53/cpu_cycles/u true
> 
> In such cases, perf record fails to open events unless
> perf_event_paranoid is set to -1, even if the PMU in question supports
> mode exclusion. Further, even when perf_event_paranoid is toggled, no
> samples are recorded.
> 
> This is an unintended side effect of commit:
> 
>   e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
> 
> ... which assumes that if a PMU has an associated cpu_map, it is an
> uncore PMU, and forces events for such PMUs to be system-wide.
> 
> This is not true for arm/arm64 systems, which can have heterogeneous
> CPUs. To account for this, multiple CPU PMUs are exposed, each with a
> "cpus" field under sysfs, which the perf tool parses into a cpu_map. ARM
> PMUs do not have a "cpumask" file, and only have a "cpus" file. For the
> gory details as to why, see commit:
> 
>  7e3fcffe95544010 ("perf pmu: Support alternative sysfs cpumask")
> 
> Given all of this, we can instead identify uncore PMUs by explicitly
> checking for a "cpumask" file, and restore arm/arm64 PMU support back to
> a working state. This patch does so, adding a new perf_pmu::is_uncore
> field, and splitting the existing cpumask parsing so that it can be
> reused.
> 
> Signed-off-by: Mark Rutland <mark.rutland@xxxxxxx>
> Tested-by Will Deacon <will.deacon@xxxxxxx>
> Acked-by: Jiri Olsa <jolsa@xxxxxxxxxx>
> Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
> Cc: Borislav Petkov <bp@xxxxxxxxx>
> Cc: David Ahern <dsahern@xxxxxxxxx>
> Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> Cc: 4.12+ <stable@xxxxxxxxxxxxxxx>
> Fixes: e3ba76deef23064f ("perf tools: Force uncore events to system wide monitoring)
> Link: http://lkml.kernel.org/r/1507315102-5942-1-git-send-email-mark.rutland@xxxxxxx
> Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
> ---
>  tools/perf/util/parse-events.c |  9 ++++---
>  tools/perf/util/pmu.c          | 56 +++++++++++++++++++++++++++++++-----------
>  tools/perf/util/pmu.h          |  1 +
>  3 files changed, 47 insertions(+), 19 deletions(-)
> 
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 01e779b91c8e..2e3ffc3bc483 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -309,10 +309,11 @@ static char *get_config_name(struct list_head *head_terms)
>  static struct perf_evsel *
>  __add_event(struct list_head *list, int *idx,
>  	    struct perf_event_attr *attr,
> -	    char *name, struct cpu_map *cpus,
> +	    char *name, struct perf_pmu *pmu,
>  	    struct list_head *config_terms)
>  {
>  	struct perf_evsel *evsel;
> +	struct cpu_map *cpus = pmu ? pmu->cpus : NULL;
>  
>  	event_attr_init(attr);
>  
> @@ -323,7 +324,7 @@ __add_event(struct list_head *list, int *idx,
>  	(*idx)++;
>  	evsel->cpus        = cpu_map__get(cpus);
>  	evsel->own_cpus    = cpu_map__get(cpus);
> -	evsel->system_wide = !!cpus;
> +	evsel->system_wide = pmu ? pmu->is_uncore : false;
>  
>  	if (name)
>  		evsel->name = strdup(name);
> @@ -1232,7 +1233,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
>  
>  	if (!head_config) {
>  		attr.type = pmu->type;
> -		evsel = __add_event(list, &data->idx, &attr, NULL, pmu->cpus, NULL);
> +		evsel = __add_event(list, &data->idx, &attr, NULL, pmu, NULL);
>  		return evsel ? 0 : -ENOMEM;
>  	}
>  
> @@ -1253,7 +1254,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
>  		return -EINVAL;
>  
>  	evsel = __add_event(list, &data->idx, &attr,
> -			    get_config_name(head_config), pmu->cpus,
> +			    get_config_name(head_config), pmu,
>  			    &config_terms);
>  	if (evsel) {
>  		evsel->unit = info.unit;
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index ac16a9db1fb5..1c4d7b4e4fb5 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -470,17 +470,36 @@ static void pmu_read_sysfs(void)
>  	closedir(dir);
>  }
>  
> +static struct cpu_map *__pmu_cpumask(const char *path)
> +{
> +	FILE *file;
> +	struct cpu_map *cpus;
> +
> +	file = fopen(path, "r");
> +	if (!file)
> +		return NULL;
> +
> +	cpus = cpu_map__read(file);
> +	fclose(file);
> +	return cpus;
> +}
> +
> +/*
> + * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64)
> + * may have a "cpus" file.
> + */
> +#define CPUS_TEMPLATE_UNCORE	"%s/bus/event_source/devices/%s/cpumask"
> +#define CPUS_TEMPLATE_CPU	"%s/bus/event_source/devices/%s/cpus"
> +
>  static struct cpu_map *pmu_cpumask(const char *name)
>  {
> -	struct stat st;
>  	char path[PATH_MAX];
> -	FILE *file;
>  	struct cpu_map *cpus;
>  	const char *sysfs = sysfs__mountpoint();
>  	const char *templates[] = {
> -		 "%s/bus/event_source/devices/%s/cpumask",
> -		 "%s/bus/event_source/devices/%s/cpus",
> -		 NULL
> +		CPUS_TEMPLATE_UNCORE,
> +		CPUS_TEMPLATE_CPU,
> +		NULL
>  	};
>  	const char **template;
>  
> @@ -489,20 +508,25 @@ static struct cpu_map *pmu_cpumask(const char *name)
>  
>  	for (template = templates; *template; template++) {
>  		snprintf(path, PATH_MAX, *template, sysfs, name);
> -		if (stat(path, &st) == 0)
> -			break;
> +		cpus = __pmu_cpumask(path);
> +		if (cpus)
> +			return cpus;
>  	}
>  
> -	if (!*template)
> -		return NULL;
> +	return NULL;
> +}
>  
> -	file = fopen(path, "r");
> -	if (!file)
> -		return NULL;
> +static bool pmu_is_uncore(const char *name)
> +{
> +	char path[PATH_MAX];
> +	struct cpu_map *cpus;
> +	const char *sysfs = sysfs__mountpoint();
>  
> -	cpus = cpu_map__read(file);
> -	fclose(file);
> -	return cpus;
> +	snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
> +	cpus = __pmu_cpumask(path);
> +	cpu_map__put(cpus);
> +
> +	return !!cpus;
>  }
>  
>  /*
> @@ -617,6 +641,8 @@ static struct perf_pmu *pmu_lookup(const char *name)
>  
>  	pmu->cpus = pmu_cpumask(name);
>  
> +	pmu->is_uncore = pmu_is_uncore(name);
> +
>  	INIT_LIST_HEAD(&pmu->format);
>  	INIT_LIST_HEAD(&pmu->aliases);
>  	list_splice(&format, &pmu->format);
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index ea7f450dc609..50abef2eb689 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -21,6 +21,7 @@ struct perf_pmu {
>  	char *name;
>  	__u32 type;
>  	bool selectable;
> +	bool is_uncore;
>  	struct perf_event_attr *default_config;
>  	struct cpu_map *cpus;
>  	struct list_head format;  /* HEAD struct perf_pmu_format -> list */
> -- 
> 2.11.0
> 



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]