2019-10-25 20:52:33

by Andi Kleen

[permalink] [raw]
Subject: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

From: Andi Kleen <[email protected]>

Add some common code that is needed to iterate over all events
in CPU order. Used in followon patches

Signed-off-by: Andi Kleen <[email protected]>

---

v2: Add cpumap__for_each_cpu macro to factor out some common code
---
tools/perf/util/cpumap.h | 8 ++++++++
tools/perf/util/evlist.c | 33 +++++++++++++++++++++++++++++++++
tools/perf/util/evlist.h | 4 ++++
tools/perf/util/evsel.h | 1 +
4 files changed, 46 insertions(+)

diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2553bef1279d..a9b13d72fd29 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -60,4 +60,12 @@ int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res,

int cpu_map__cpu(struct perf_cpu_map *cpus, int idx);
bool cpu_map__has(struct perf_cpu_map *cpus, int cpu);
+
+#define __cpumap__for_each_cpu(cpus, index, cpu, maxcpu)\
+ for ((index) = 0; \
+ (cpu) = (index) < (maxcpu) ? (cpus)->map[index] : -1, (index) < (maxcpu); \
+ (index)++)
+#define cpumap__for_each_cpu(cpus, index, cpu) \
+ __cpumap__for_each_cpu(cpus, index, cpu, (cpus)->nr)
+
#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index fdce590d2278..da3c8f8ef68e 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -342,6 +342,39 @@ static int perf_evlist__nr_threads(struct evlist *evlist,
return perf_thread_map__nr(evlist->core.threads);
}

+struct perf_cpu_map *evlist__cpu_iter_start(struct evlist *evlist)
+{
+ struct perf_cpu_map *cpus;
+ struct evsel *pos;
+
+ /*
+ * evlist->cpus is not necessarily a superset of all the
+ * event's cpus, so compute our own super set. This
+ * assume that there is a super set
+ */
+ cpus = evlist->core.cpus;
+ evlist__for_each_entry(evlist, pos) {
+ pos->cpu_index = 0;
+ if (pos->core.cpus->nr > cpus->nr)
+ cpus = pos->core.cpus;
+ }
+ return cpus;
+}
+
+bool evlist__cpu_iter_skip(struct evsel *ev, int cpu)
+{
+ if (ev->cpu_index >= ev->core.cpus->nr)
+ return true;
+ if (cpu >= 0 && ev->core.cpus->map[ev->cpu_index] != cpu)
+ return true;
+ return false;
+}
+
+void evlist__cpu_iter_next(struct evsel *ev)
+{
+ ev->cpu_index++;
+}
+
void evlist__disable(struct evlist *evlist)
{
struct evsel *pos;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 13051409fd22..c1deb8ebdcea 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -336,6 +336,10 @@ void perf_evlist__to_front(struct evlist *evlist,
void perf_evlist__set_tracking_event(struct evlist *evlist,
struct evsel *tracking_evsel);

+struct perf_cpu_map *evlist__cpu_iter_start(struct evlist *evlist);
+bool evlist__cpu_iter_skip(struct evsel *ev, int cpu);
+void evlist__cpu_iter_next(struct evsel *ev);
+
struct evsel *
perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str);

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index ddc5ee6f6592..cf90019ae744 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -95,6 +95,7 @@ struct evsel {
bool collect_stat;
bool weak_group;
bool percore;
+ int cpu_index;
const char *pmu_name;
struct {
perf_evsel__sb_cb_t *cb;
--
2.21.0


2019-10-30 10:09:14

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

On Fri, Oct 25, 2019 at 11:14:13AM -0700, Andi Kleen wrote:
> From: Andi Kleen <[email protected]>
>
> Add some common code that is needed to iterate over all events
> in CPU order. Used in followon patches
>
> Signed-off-by: Andi Kleen <[email protected]>
>
> ---
>
> v2: Add cpumap__for_each_cpu macro to factor out some common code
> ---
> tools/perf/util/cpumap.h | 8 ++++++++
> tools/perf/util/evlist.c | 33 +++++++++++++++++++++++++++++++++
> tools/perf/util/evlist.h | 4 ++++
> tools/perf/util/evsel.h | 1 +
> 4 files changed, 46 insertions(+)
>
> diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
> index 2553bef1279d..a9b13d72fd29 100644
> --- a/tools/perf/util/cpumap.h
> +++ b/tools/perf/util/cpumap.h
> @@ -60,4 +60,12 @@ int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res,
>
> int cpu_map__cpu(struct perf_cpu_map *cpus, int idx);
> bool cpu_map__has(struct perf_cpu_map *cpus, int cpu);
> +
> +#define __cpumap__for_each_cpu(cpus, index, cpu, maxcpu)\
> + for ((index) = 0; \
> + (cpu) = (index) < (maxcpu) ? (cpus)->map[index] : -1, (index) < (maxcpu); \
> + (index)++)
> +#define cpumap__for_each_cpu(cpus, index, cpu) \
> + __cpumap__for_each_cpu(cpus, index, cpu, (cpus)->nr)

there's perf_cpu_map__for_each_cpu macro in libperf

jirka

2019-10-30 10:10:53

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

On Fri, Oct 25, 2019 at 11:14:13AM -0700, Andi Kleen wrote:
> From: Andi Kleen <[email protected]>
>
> Add some common code that is needed to iterate over all events
> in CPU order. Used in followon patches
>
> Signed-off-by: Andi Kleen <[email protected]>
>
> ---
>
> v2: Add cpumap__for_each_cpu macro to factor out some common code
> ---
> tools/perf/util/cpumap.h | 8 ++++++++
> tools/perf/util/evlist.c | 33 +++++++++++++++++++++++++++++++++
> tools/perf/util/evlist.h | 4 ++++
> tools/perf/util/evsel.h | 1 +
> 4 files changed, 46 insertions(+)
>
> diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
> index 2553bef1279d..a9b13d72fd29 100644
> --- a/tools/perf/util/cpumap.h
> +++ b/tools/perf/util/cpumap.h
> @@ -60,4 +60,12 @@ int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res,
>
> int cpu_map__cpu(struct perf_cpu_map *cpus, int idx);
> bool cpu_map__has(struct perf_cpu_map *cpus, int cpu);
> +
> +#define __cpumap__for_each_cpu(cpus, index, cpu, maxcpu)\
> + for ((index) = 0; \
> + (cpu) = (index) < (maxcpu) ? (cpus)->map[index] : -1, (index) < (maxcpu); \
> + (index)++)
> +#define cpumap__for_each_cpu(cpus, index, cpu) \
> + __cpumap__for_each_cpu(cpus, index, cpu, (cpus)->nr)
> +
> #endif /* __PERF_CPUMAP_H */
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index fdce590d2278..da3c8f8ef68e 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -342,6 +342,39 @@ static int perf_evlist__nr_threads(struct evlist *evlist,
> return perf_thread_map__nr(evlist->core.threads);
> }
>
> +struct perf_cpu_map *evlist__cpu_iter_start(struct evlist *evlist)
> +{
> + struct perf_cpu_map *cpus;
> + struct evsel *pos;
> +
> + /*
> + * evlist->cpus is not necessarily a superset of all the
> + * event's cpus, so compute our own super set. This
> + * assume that there is a super set
> + */
> + cpus = evlist->core.cpus;
> + evlist__for_each_entry(evlist, pos) {
> + pos->cpu_index = 0;
> + if (pos->core.cpus->nr > cpus->nr)
> + cpus = pos->core.cpus;
> + }
> + return cpus;

I might not understand the reason for cpu_index, but
imagine something like below should be enough, no?

make evlist->all_cpus that contains all events cpus + evlist->core.cpus,
and iterate it via:

evlist__for_each_cpu(evlist, cpu) {
affinity__set(&affinity, cpu);

evlist__for_each_entry(evlist, evsel) {
if (!cpu_map__has(perf_evsel__cpus(&evsel->core), cpu)
continue;

// here we have evsel with its cpu running on given cpu
}
}

jirka

2019-10-30 18:30:31

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

On Wed, Oct 30, 2019 at 11:06:06AM +0100, Jiri Olsa wrote:
> > +struct perf_cpu_map *evlist__cpu_iter_start(struct evlist *evlist)
> > +{
> > + struct perf_cpu_map *cpus;
> > + struct evsel *pos;
> > +
> > + /*
> > + * evlist->cpus is not necessarily a superset of all the
> > + * event's cpus, so compute our own super set. This
> > + * assume that there is a super set
> > + */
> > + cpus = evlist->core.cpus;
> > + evlist__for_each_entry(evlist, pos) {
> > + pos->cpu_index = 0;
> > + if (pos->core.cpus->nr > cpus->nr)
> > + cpus = pos->core.cpus;
> > + }
> > + return cpus;
>
> I might not understand the reason for cpu_index, but

This is just so that we can iterate each event's map
independently.

> imagine something like below should be enough, no?

Well it's more complicated because evlist->all_cpus doesn't exist.
The exists evlist->cpus cannot be used (I tried that)
I also don't think we have an existing function to merge
two maps, so that would need to be added to create it.
Just using ->cpu_index is a much simpler change.


-Andi

2019-10-30 19:08:39

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

On Wed, Oct 30, 2019 at 08:51:08AM -0700, Andi Kleen wrote:
> On Wed, Oct 30, 2019 at 11:06:06AM +0100, Jiri Olsa wrote:
> > > +struct perf_cpu_map *evlist__cpu_iter_start(struct evlist *evlist)
> > > +{
> > > + struct perf_cpu_map *cpus;
> > > + struct evsel *pos;
> > > +
> > > + /*
> > > + * evlist->cpus is not necessarily a superset of all the
> > > + * event's cpus, so compute our own super set. This
> > > + * assume that there is a super set
> > > + */
> > > + cpus = evlist->core.cpus;
> > > + evlist__for_each_entry(evlist, pos) {
> > > + pos->cpu_index = 0;
> > > + if (pos->core.cpus->nr > cpus->nr)
> > > + cpus = pos->core.cpus;
> > > + }
> > > + return cpus;
> >
> > I might not understand the reason for cpu_index, but
>
> This is just so that we can iterate each event's map
> independently.
>
> > imagine something like below should be enough, no?
>
> Well it's more complicated because evlist->all_cpus doesn't exist.

yes, I suggest to create it

> The exists evlist->cpus cannot be used (I tried that)
> I also don't think we have an existing function to merge
> two maps, so that would need to be added to create it.
> Just using ->cpu_index is a much simpler change.

I dont think that would be lot of code
and it would simplify this one

jirka

2019-10-30 19:14:01

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

>
> > The exists evlist->cpus cannot be used (I tried that)
> > I also don't think we have an existing function to merge
> > two maps, so that would need to be added to create it.
> > Just using ->cpu_index is a much simpler change.
>
> I dont think that would be lot of code
> and it would simplify this one

AFAIK they're not guaranteed to be sorted, which makes merging
complicated. I'm not sure it's safe to just sort existing maps
because someone might have a index.

So you'll need to create temporary maps, sort them and then
merge. Won't be simple.

-Andi

2019-11-01 09:32:35

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v3 3/7] perf evsel: Add iterator to iterate over events ordered by CPU

On Wed, Oct 30, 2019 at 12:03:28PM -0700, Andi Kleen wrote:
> >
> > > The exists evlist->cpus cannot be used (I tried that)
> > > I also don't think we have an existing function to merge
> > > two maps, so that would need to be added to create it.
> > > Just using ->cpu_index is a much simpler change.
> >
> > I dont think that would be lot of code
> > and it would simplify this one
>
> AFAIK they're not guaranteed to be sorted, which makes merging
> complicated. I'm not sure it's safe to just sort existing maps
> because someone might have a index.

we could add bitmap to maps, then combining them
would be just a matter of or-ing them

>
> So you'll need to create temporary maps, sort them and then
> merge. Won't be simple.

it's also not simple to read simple event close code now

jirka