Re: [PATCH v2 07/27] perf evlist: Hybrid event uses its own cpus

2021-03-14 Thread Jin, Yao

Hi Jiri,

On 3/13/2021 3:15 AM, Jiri Olsa wrote:

On Thu, Mar 11, 2021 at 03:07:22PM +0800, Jin Yao wrote:

On hybrid platform, atom events can be only enabled on atom CPUs. Core
events can be only enabled on core CPUs. So for a hybrid event, it can
be only enabled on it's own CPUs.

But the problem for current perf is, the cpus for evsel (via PMU sysfs)
have been merged to evsel_list->core.all_cpus. It might be all CPUs.

So we need to figure out one way to let the hybrid event only use it's
own CPUs.

The idea is to create a new evlist__invalidate_all_cpus to invalidate
the evsel_list->core.all_cpus then evlist__for_each_cpu returns cpu -1
for hybrid evsel. If cpu is -1, hybrid evsel will use it's own cpus.


that's wild.. I don't understand when you say we don't have
cpus for evsel, because they have been merged.. each evsel
has evsel->core.own_cpus coming from pmu->cpus, right?

why can't you just filter out cpus that are in there?

jirka



Yes, you're right. This patch is wide and actually it's not very necessary.

The current framework has processed the cpus for evsel well even for hybrid evsel. So this patch can 
be dropped.


Thanks
Jin Yao



Re: [PATCH v2 07/27] perf evlist: Hybrid event uses its own cpus

2021-03-12 Thread Jiri Olsa
On Thu, Mar 11, 2021 at 03:07:22PM +0800, Jin Yao wrote:
> On hybrid platform, atom events can be only enabled on atom CPUs. Core
> events can be only enabled on core CPUs. So for a hybrid event, it can
> be only enabled on it's own CPUs.
> 
> But the problem for current perf is, the cpus for evsel (via PMU sysfs)
> have been merged to evsel_list->core.all_cpus. It might be all CPUs.
> 
> So we need to figure out one way to let the hybrid event only use it's
> own CPUs.
> 
> The idea is to create a new evlist__invalidate_all_cpus to invalidate
> the evsel_list->core.all_cpus then evlist__for_each_cpu returns cpu -1
> for hybrid evsel. If cpu is -1, hybrid evsel will use it's own cpus.

that's wild.. I don't understand when you say we don't have
cpus for evsel, because they have been merged.. each evsel
has evsel->core.own_cpus coming from pmu->cpus, right?

why can't you just filter out cpus that are in there?

jirka

> 
> We will see following code piece in patch.
> 
> if (cpu == -1 && !evlist->thread_mode)
> evsel__enable_cpus(pos);
> 
> It lets the event be enabled on event's own cpus.
> 
> Signed-off-by: Jin Yao 
> ---
>  tools/perf/builtin-stat.c  | 37 ++-
>  tools/perf/util/evlist.c   | 72 --
>  tools/perf/util/evlist.h   |  4 ++
>  tools/perf/util/evsel.h|  8 
>  tools/perf/util/python-ext-sources |  2 +
>  5 files changed, 117 insertions(+), 6 deletions(-)
> 
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index 2e2e4a8345ea..68ecf68699a9 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -393,6 +393,18 @@ static int read_counter_cpu(struct evsel *counter, 
> struct timespec *rs, int cpu)
>   return 0;
>  }
>  
> +static int read_counter_cpus(struct evsel *counter, struct timespec *rs)
> +{
> + int cpu, nr_cpus, err = 0;
> + struct perf_cpu_map *cpus = evsel__cpus(counter);
> +
> + nr_cpus = cpus ? cpus->nr : 1;
> + for (cpu = 0; cpu < nr_cpus; cpu++)
> + err = read_counter_cpu(counter, rs, cpu);
> +
> + return err;
> +}
> +
>  static int read_affinity_counters(struct timespec *rs)
>  {
>   struct evsel *counter;
> @@ -414,8 +426,14 @@ static int read_affinity_counters(struct timespec *rs)
>   if (evsel__cpu_iter_skip(counter, cpu))
>   continue;
>   if (!counter->err) {
> - counter->err = read_counter_cpu(counter, rs,
> - 
> counter->cpu_iter - 1);
> + if (cpu == -1 && !evsel_list->thread_mode) {
> + counter->err = 
> read_counter_cpus(counter, rs);
> + } else if (evsel_list->thread_mode) {
> + counter->err = 
> read_counter_cpu(counter, rs, 0);
> + } else {
> + counter->err = 
> read_counter_cpu(counter, rs,
> + 
> counter->cpu_iter - 1);
> + }
>   }
>   }
>   }
> @@ -781,6 +799,21 @@ static int __run_perf_stat(int argc, const char **argv, 
> int run_idx)
>   if (group)
>   evlist__set_leader(evsel_list);
>  
> + /*
> +  * On hybrid platform, the cpus for evsel (via PMU sysfs) have been
> +  * merged to evsel_list->core.all_cpus. We use 
> evlist__invalidate_all_cpus
> +  * to invalidate the evsel_list->core.all_cpus then evlist__for_each_cpu
> +  * returns cpu -1 for hybrid evsel. If cpu is -1, hybrid evsel will
> +  * use it's own cpus.
> +  */
> + if (evlist__has_hybrid_events(evsel_list)) {
> + evlist__invalidate_all_cpus(evsel_list);
> + if (!target__has_cpu() ||
> + target__has_per_thread()) {
> + evsel_list->thread_mode = true;
> + }
> + }
> +
>   if (affinity__setup() < 0)
>   return -1;
>  
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 882cd1f721d9..3ee12fcd0c9f 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -381,7 +381,8 @@ bool evsel__cpu_iter_skip_no_inc(struct evsel *ev, int 
> cpu)
>  bool evsel__cpu_iter_skip(struct evsel *ev, int cpu)
>  {
>   if (!evsel__cpu_iter_skip_no_inc(ev, cpu)) {
> - ev->cpu_iter++;
> + if (cpu != -1)
> + ev->cpu_iter++;
>   return false;
>   }
>   return true;
> @@ -410,6 +411,16 @@ static int evlist__is_enabled(struct evlist *evlist)
>   return false;
>  }
>  
> +static void evsel__disable_cpus(struct evsel *evsel)
> +{
> + int cpu, nr_cpus;
> + struct perf_cpu_map *cpus = evsel__cpus(evsel);
> +
> + nr_cpus = cpus ? cpus->nr : 

[PATCH v2 07/27] perf evlist: Hybrid event uses its own cpus

2021-03-10 Thread Jin Yao
On hybrid platform, atom events can be only enabled on atom CPUs. Core
events can be only enabled on core CPUs. So for a hybrid event, it can
be only enabled on it's own CPUs.

But the problem for current perf is, the cpus for evsel (via PMU sysfs)
have been merged to evsel_list->core.all_cpus. It might be all CPUs.

So we need to figure out one way to let the hybrid event only use it's
own CPUs.

The idea is to create a new evlist__invalidate_all_cpus to invalidate
the evsel_list->core.all_cpus then evlist__for_each_cpu returns cpu -1
for hybrid evsel. If cpu is -1, hybrid evsel will use it's own cpus.

We will see following code piece in patch.

if (cpu == -1 && !evlist->thread_mode)
evsel__enable_cpus(pos);

It lets the event be enabled on event's own cpus.

Signed-off-by: Jin Yao 
---
 tools/perf/builtin-stat.c  | 37 ++-
 tools/perf/util/evlist.c   | 72 --
 tools/perf/util/evlist.h   |  4 ++
 tools/perf/util/evsel.h|  8 
 tools/perf/util/python-ext-sources |  2 +
 5 files changed, 117 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2e2e4a8345ea..68ecf68699a9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -393,6 +393,18 @@ static int read_counter_cpu(struct evsel *counter, struct 
timespec *rs, int cpu)
return 0;
 }
 
+static int read_counter_cpus(struct evsel *counter, struct timespec *rs)
+{
+   int cpu, nr_cpus, err = 0;
+   struct perf_cpu_map *cpus = evsel__cpus(counter);
+
+   nr_cpus = cpus ? cpus->nr : 1;
+   for (cpu = 0; cpu < nr_cpus; cpu++)
+   err = read_counter_cpu(counter, rs, cpu);
+
+   return err;
+}
+
 static int read_affinity_counters(struct timespec *rs)
 {
struct evsel *counter;
@@ -414,8 +426,14 @@ static int read_affinity_counters(struct timespec *rs)
if (evsel__cpu_iter_skip(counter, cpu))
continue;
if (!counter->err) {
-   counter->err = read_counter_cpu(counter, rs,
-   
counter->cpu_iter - 1);
+   if (cpu == -1 && !evsel_list->thread_mode) {
+   counter->err = 
read_counter_cpus(counter, rs);
+   } else if (evsel_list->thread_mode) {
+   counter->err = 
read_counter_cpu(counter, rs, 0);
+   } else {
+   counter->err = 
read_counter_cpu(counter, rs,
+   
counter->cpu_iter - 1);
+   }
}
}
}
@@ -781,6 +799,21 @@ static int __run_perf_stat(int argc, const char **argv, 
int run_idx)
if (group)
evlist__set_leader(evsel_list);
 
+   /*
+* On hybrid platform, the cpus for evsel (via PMU sysfs) have been
+* merged to evsel_list->core.all_cpus. We use 
evlist__invalidate_all_cpus
+* to invalidate the evsel_list->core.all_cpus then evlist__for_each_cpu
+* returns cpu -1 for hybrid evsel. If cpu is -1, hybrid evsel will
+* use it's own cpus.
+*/
+   if (evlist__has_hybrid_events(evsel_list)) {
+   evlist__invalidate_all_cpus(evsel_list);
+   if (!target__has_cpu() ||
+   target__has_per_thread()) {
+   evsel_list->thread_mode = true;
+   }
+   }
+
if (affinity__setup() < 0)
return -1;
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 882cd1f721d9..3ee12fcd0c9f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -381,7 +381,8 @@ bool evsel__cpu_iter_skip_no_inc(struct evsel *ev, int cpu)
 bool evsel__cpu_iter_skip(struct evsel *ev, int cpu)
 {
if (!evsel__cpu_iter_skip_no_inc(ev, cpu)) {
-   ev->cpu_iter++;
+   if (cpu != -1)
+   ev->cpu_iter++;
return false;
}
return true;
@@ -410,6 +411,16 @@ static int evlist__is_enabled(struct evlist *evlist)
return false;
 }
 
+static void evsel__disable_cpus(struct evsel *evsel)
+{
+   int cpu, nr_cpus;
+   struct perf_cpu_map *cpus = evsel__cpus(evsel);
+
+   nr_cpus = cpus ? cpus->nr : 1;
+   for (cpu = 0; cpu < nr_cpus; cpu++)
+   evsel__disable_cpu(evsel, cpu);
+}
+
 static void __evlist__disable(struct evlist *evlist, char *evsel_name)
 {
struct evsel *pos;
@@ -436,7 +447,12 @@ static void __evlist__disable(struct evlist *evlist, char 
*evsel_name)
has_imm = true;
if (pos->immediate != imm)