linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu
@ 2022-05-06 12:25 Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band Adrian Hunter
                   ` (23 more replies)
  0 siblings, 24 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Hi

Here are V2 patches to support capturing Intel PT sideband events such as
mmap, task, context switch, text poke etc, on every CPU even when tracing
selected user_requested_cpus.  That is, when using the perf record -C or
 --cpu option.

This is needed for:
1. text poke: a text poke on any CPU affects all CPUs
2. tracing user space: a user space process can migrate between CPUs so
mmap events that happen on a different CPU can be needed to decode a
user_requested_cpus CPU.

For example:

	Trace on CPU 1:

	perf record --kcore -C 1 -e intel_pt// &

	Start a task on CPU 0:

	taskset 0x1 testprog &

	Migrate it to CPU 1:

	taskset -p 0x2 <testprog pid>

	Stop tracing:

	kill %1

	Prior to these changes there will be errors decoding testprog
	in userspace because the comm and mmap events for testprog will not
	have been captured.

There is quite a bit of preparation:

The first patch is a small Intel PT test for system-wide side band.  The
test fails before the patches are applied, passed afterwards.

      perf intel-pt: Add a test for system-wide side band [new in V1]

The next 5 patches stop auxtrace mixing up mmap idx between evlist and
evsel.  That is going to matter when
evlist->all_cpus != evlist->user_requested_cpus != evsel->cpus:

      libperf evsel: Factor out perf_evsel__ioctl() [now applied]
      libperf evsel: Add perf_evsel__enable_thread()
      perf evlist: Use libperf functions in evlist__enable_event_idx()
      perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c
      perf auxtrace: Do not mix up mmap idx

The next 6 patches stop attempts to auxtrace mmap when it is not an
auxtrace event e.g. when mmapping the CPUs on which only sideband is
captured:

      libperf evlist: Remove ->idx() per_cpu parameter
      libperf evlist: Move ->idx() into mmap_per_evsel()
      libperf evlist: Add evsel as a parameter to ->idx()
      perf auxtrace: Record whether an auxtrace mmap is needed
      perf auxctrace: Add mmap_needed to auxtrace_mmap_params
      perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter

The next 5 patches switch to setting up dummy event maps before adding the
evsel so that the evsel is subject to map propagation, primarily to cause
addition of the evsel's CPUs to all_cpus.

      perf evlist: Factor out evlist__dummy_event()
      perf evlist: Add evlist__add_system_wide_dummy()
      perf record: Use evlist__add_system_wide_dummy() in record__config_text_poke()
      perf intel-pt: Use evlist__add_system_wide_dummy() for switch tracking
      perf intel-pt: Track sideband system-wide when needed

The remaining patches make more significant changes.

First change from using user_requested_cpus to using all_cpus where necessary:

      perf tools: Allow all_cpus to be a superset of user_requested_cpus

Secondly, mmap all per-thread and all per-cpu events:

      libperf evlist: Allow mixing per-thread and per-cpu mmaps
      libperf evlist: Check nr_mmaps is correct [new in V1]

Stop using system_wide flag for uncore because it will not work anymore:

      perf stat: Add requires_cpu flag for uncore
      libperf evsel: Add comments for booleans [new in V1]

Finally change map propagation so that system-wide events retain their cpus and
(dummy) threads:

      perf tools: Allow system-wide events to keep their own CPUs
      perf tools: Allow system-wide events to keep their own threads


Changes in V2:

	Added some Acked-by: Ian Rogers <irogers@google.com>

      libperf evsel: Add perf_evsel__enable_thread()
	Use perf_cpu_map__for_each_cpu()

      perf auxtrace: Add mmap_needed to auxtrace_mmap_params
	Add documentation comment for mmap_needed

      perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter
	Fix missing auxtrace_mmap_params__set_idx change

      libperf evlist: Check nr_mmaps is correct
	Remove unused code

      libperf evsel: Add comments for booleans
	Amend comments

      perf evlist: Add evlist__add_dummy_on_all_cpus()
	Rename evlist__add_system_wide -> evlist__add_on_all_cpus
	Changed patch subject accordingly

      perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke()
	Rename evlist__add_system_wide -> evlist__add_on_all_cpus
	Changed patch subject accordingly

      perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking
	Rename evlist__add_system_wide -> evlist__add_on_all_cpus
	Changed patch subject accordingly

Changes in V1:

      perf intel-pt: Add a test for system-wide side band
	New patch

      libperf evsel: Factor out perf_evsel__ioctl()
	Dropped because it has been applied.

      libperf evsel: Add perf_evsel__enable_thread()
	Rename variable i -> idx

      perf auxtrace: Do not mix up mmap idx
	Rename variable cpu to cpu_map_idx

      perf tools: Allow all_cpus to be a superset of user_requested_cpus
	Add Acked-by: Ian Rogers <irogers@google.com>

      libperf evlist: Allow mixing per-thread and per-cpu mmaps
	Fix perf_evlist__nr_mmaps() calculation

      libperf evlist: Check nr_mmaps is correct
	New patch

      libperf evsel: Add comments for booleans
	New patch

      perf tools: Allow system-wide events to keep their own CPUs
      perf tools: Allow system-wide events to keep their own threads


Adrian Hunter (23):
      perf intel-pt: Add a test for system-wide side band
      libperf evsel: Add perf_evsel__enable_thread()
      perf evlist: Use libperf functions in evlist__enable_event_idx()
      perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c
      perf auxtrace: Do not mix up mmap idx
      libperf evlist: Remove ->idx() per_cpu parameter
      libperf evlist: Move ->idx() into mmap_per_evsel()
      libperf evlist: Add evsel as a parameter to ->idx()
      perf auxtrace: Record whether an auxtrace mmap is needed
      perf auxtrace: Add mmap_needed to auxtrace_mmap_params
      perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter
      perf evlist: Factor out evlist__dummy_event()
      perf evlist: Add evlist__add_dummy_on_all_cpus()
      perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke()
      perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking
      perf intel-pt: Track sideband system-wide when needed
      perf tools: Allow all_cpus to be a superset of user_requested_cpus
      libperf evlist: Allow mixing per-thread and per-cpu mmaps
      libperf evlist: Check nr_mmaps is correct
      perf stat: Add requires_cpu flag for uncore
      libperf evsel: Add comments for booleans
      perf tools: Allow system-wide events to keep their own CPUs
      perf tools: Allow system-wide events to keep their own threads

 tools/lib/perf/evlist.c                  |  80 ++++++++++-------------
 tools/lib/perf/evsel.c                   |  15 +++++
 tools/lib/perf/include/internal/evlist.h |   3 +-
 tools/lib/perf/include/internal/evsel.h  |  10 +++
 tools/lib/perf/include/perf/evsel.h      |   1 +
 tools/perf/arch/arm/util/cs-etm.c        |   1 +
 tools/perf/arch/arm64/util/arm-spe.c     |   1 +
 tools/perf/arch/s390/util/auxtrace.c     |   1 +
 tools/perf/arch/x86/util/intel-bts.c     |   1 +
 tools/perf/arch/x86/util/intel-pt.c      |  32 ++++------
 tools/perf/builtin-record.c              |  39 +++++-------
 tools/perf/builtin-stat.c                |   5 +-
 tools/perf/tests/shell/test_intel_pt.sh  |  71 +++++++++++++++++++++
 tools/perf/util/auxtrace.c               |  31 +++++++--
 tools/perf/util/auxtrace.h               |  10 +--
 tools/perf/util/evlist.c                 | 106 +++++++++++++++----------------
 tools/perf/util/evlist.h                 |   7 +-
 tools/perf/util/evsel.c                  |   1 +
 tools/perf/util/evsel.h                  |   1 +
 tools/perf/util/mmap.c                   |   4 +-
 tools/perf/util/parse-events.c           |   2 +-
 21 files changed, 261 insertions(+), 161 deletions(-)
 create mode 100755 tools/perf/tests/shell/test_intel_pt.sh


Regards
Adrian

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:18   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread() Adrian Hunter
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add a test for system-wide side band even when tracing selected CPUs.

Tested-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/tests/shell/test_intel_pt.sh | 71 +++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100755 tools/perf/tests/shell/test_intel_pt.sh

diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
new file mode 100755
index 000000000000..a3298643884d
--- /dev/null
+++ b/tools/perf/tests/shell/test_intel_pt.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+# Miscellaneous Intel PT testing
+# SPDX-License-Identifier: GPL-2.0
+
+set -e
+
+# Skip if no Intel PT
+perf list | grep -q 'intel_pt//' || exit 2
+
+skip_cnt=0
+ok_cnt=0
+err_cnt=0
+
+tmpfile=`mktemp`
+perfdatafile=`mktemp`
+
+can_cpu_wide()
+{
+	perf record -o ${tmpfile} -B -N --no-bpf-event -e dummy:u -C $1 true 2>&1 >/dev/null || return 2
+	return 0
+}
+
+test_system_wide_side_band()
+{
+	# Need CPU 0 and CPU 1
+	can_cpu_wide 0 || return $?
+	can_cpu_wide 1 || return $?
+
+	# Record on CPU 0 a task running on CPU 1
+	perf record -B -N --no-bpf-event -o ${perfdatafile} -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
+
+	# Should get MMAP events from CPU 1 because they can be needed to decode
+	mmap_cnt=`perf script -i ${perfdatafile} --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l`
+
+	if [ ${mmap_cnt} -gt 0 ] ; then
+		return 0
+	fi
+
+	echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
+	return 1
+}
+
+count_result()
+{
+	if [ $1 -eq 2 ] ; then
+		skip_cnt=`expr ${skip_cnt} \+ 1`
+		return
+	fi
+	if [ $1 -eq 0 ] ; then
+		ok_cnt=`expr ${ok_cnt} \+ 1`
+		return
+	fi
+	err_cnt=`expr ${err_cnt} \+ 1`
+}
+
+test_system_wide_side_band
+
+count_result $?
+
+rm -f ${tmpfile}
+rm -f ${perfdatafile}
+
+if [ ${err_cnt} -gt 0 ] ; then
+	exit 1
+fi
+
+if [ ${ok_cnt} -gt 0 ] ; then
+	exit 0
+fi
+
+exit 2
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 17:06   ` Ian Rogers
  2022-05-10 17:19   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx() Adrian Hunter
                   ` (21 subsequent siblings)
  23 siblings, 2 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add perf_evsel__enable_thread() as a counterpart to
perf_evsel__enable_cpu(), to enable all events for a thread.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evsel.c              | 15 +++++++++++++++
 tools/lib/perf/include/perf/evsel.h |  1 +
 2 files changed, 16 insertions(+)

diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
index 20ae9f5f8b30..c1d58673f6ef 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -360,6 +360,21 @@ int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
 	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
 }
 
+int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
+{
+	struct perf_cpu cpu __maybe_unused;
+	int idx;
+	int err;
+
+	perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
+		err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel)
 {
 	int i;
diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
index 2a9516b42d15..699c0ed97d34 100644
--- a/tools/lib/perf/include/perf/evsel.h
+++ b/tools/lib/perf/include/perf/evsel.h
@@ -36,6 +36,7 @@ LIBPERF_API int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int
 				 struct perf_counts_values *count);
 LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel);
 LIBPERF_API int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
+LIBPERF_API int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread);
 LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel);
 LIBPERF_API int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
 LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:23   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c Adrian Hunter
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

evlist__enable_event_idx() is used only for auxtrace events which are never
system_wide. Simplify by using libperf enable event functions.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/evlist.c | 44 ++--------------------------------------
 1 file changed, 2 insertions(+), 42 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 52ea004ba01e..9fcecf7daa62 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -334,14 +334,6 @@ int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name,
 	return 0;
 }
 
-static int evlist__nr_threads(struct evlist *evlist, struct evsel *evsel)
-{
-	if (evsel->core.system_wide)
-		return 1;
-	else
-		return perf_thread_map__nr(evlist->core.threads);
-}
-
 struct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affinity *affinity)
 {
 	struct evlist_cpu_iterator itr = {
@@ -546,46 +538,14 @@ void evlist__toggle_enable(struct evlist *evlist)
 	(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
 }
 
-static int evlist__enable_event_cpu(struct evlist *evlist, struct evsel *evsel, int cpu)
-{
-	int thread;
-	int nr_threads = evlist__nr_threads(evlist, evsel);
-
-	if (!evsel->core.fd)
-		return -EINVAL;
-
-	for (thread = 0; thread < nr_threads; thread++) {
-		int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
-static int evlist__enable_event_thread(struct evlist *evlist, struct evsel *evsel, int thread)
-{
-	int cpu;
-	int nr_cpus = perf_cpu_map__nr(evlist->core.user_requested_cpus);
-
-	if (!evsel->core.fd)
-		return -EINVAL;
-
-	for (cpu = 0; cpu < nr_cpus; cpu++) {
-		int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
-		if (err)
-			return err;
-	}
-	return 0;
-}
-
 int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
 {
 	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
 
 	if (per_cpu_mmaps)
-		return evlist__enable_event_cpu(evlist, evsel, idx);
+		return perf_evsel__enable_cpu(&evsel->core, idx);
 
-	return evlist__enable_event_thread(evlist, evsel, idx);
+	return perf_evsel__enable_thread(&evsel->core, idx);
 }
 
 int evlist__add_pollfd(struct evlist *evlist, int fd)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (2 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:24   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx Adrian Hunter
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

evlist__enable_event_idx() is used only by auxtrace. Move it to auxtrace.c
in preparation for making it even more auxtrace specific.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/auxtrace.c | 10 ++++++++++
 tools/perf/util/evlist.c   | 10 ----------
 tools/perf/util/evlist.h   |  2 --
 3 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index df1c5bbbaa0d..10936a38031f 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -636,6 +636,16 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
 	return -EINVAL;
 }
 
+static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
+{
+	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
+
+	if (per_cpu_mmaps)
+		return perf_evsel__enable_cpu(&evsel->core, idx);
+
+	return perf_evsel__enable_thread(&evsel->core, idx);
+}
+
 int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
 {
 	struct evsel *evsel;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 9fcecf7daa62..f1309b39afe4 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -538,16 +538,6 @@ void evlist__toggle_enable(struct evlist *evlist)
 	(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
 }
 
-int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
-{
-	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
-
-	if (per_cpu_mmaps)
-		return perf_evsel__enable_cpu(&evsel->core, idx);
-
-	return perf_evsel__enable_thread(&evsel->core, idx);
-}
-
 int evlist__add_pollfd(struct evlist *evlist, int fd)
 {
 	return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, fdarray_flag__default);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index a21daaa5fc1b..4062f5aebfc1 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -196,8 +196,6 @@ void evlist__toggle_enable(struct evlist *evlist);
 void evlist__disable_evsel(struct evlist *evlist, char *evsel_name);
 void evlist__enable_evsel(struct evlist *evlist, char *evsel_name);
 
-int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx);
-
 void evlist__set_selected(struct evlist *evlist, struct evsel *evsel);
 
 int evlist__create_maps(struct evlist *evlist, struct target *target);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (3 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:25   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter Adrian Hunter
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

The idx is with respect to evlist not evsel. That hasn't mattered because
they are the same at present. Prepare for that not being the case, which it
won't be when sideband tracking events are allowed on all CPUs even when
auxtrace is limited to selected CPUs.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/auxtrace.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 10936a38031f..b11549ae39df 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -640,8 +640,14 @@ static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel,
 {
 	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
 
-	if (per_cpu_mmaps)
-		return perf_evsel__enable_cpu(&evsel->core, idx);
+	if (per_cpu_mmaps) {
+		struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);
+		int cpu_map_idx = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu);
+
+		if (cpu_map_idx == -1)
+			return -EINVAL;
+		return perf_evsel__enable_cpu(&evsel->core, cpu_map_idx);
+	}
 
 	return perf_evsel__enable_thread(&evsel->core, idx);
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (4 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel() Adrian Hunter
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Remove ->idx() per_cpu parameter because it isn't needed.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c                  | 4 ++--
 tools/lib/perf/include/internal/evlist.h | 2 +-
 tools/perf/util/evlist.c                 | 3 ++-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 974b4585f93e..5e8ad854fa8a 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -521,7 +521,7 @@ mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 		int output_overwrite = -1;
 
 		if (ops->idx)
-			ops->idx(evlist, mp, thread, false);
+			ops->idx(evlist, mp, thread);
 
 		if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread,
 				   &output, &output_overwrite))
@@ -548,7 +548,7 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 		int output_overwrite = -1;
 
 		if (ops->idx)
-			ops->idx(evlist, mp, cpu, true);
+			ops->idx(evlist, mp, cpu);
 
 		for (thread = 0; thread < nr_threads; thread++) {
 			if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h
index e3e64f37db7b..0d5c830431a7 100644
--- a/tools/lib/perf/include/internal/evlist.h
+++ b/tools/lib/perf/include/internal/evlist.h
@@ -38,7 +38,7 @@ struct perf_evlist {
 };
 
 typedef void
-(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int, bool);
+(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int);
 typedef struct perf_mmap*
 (*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int);
 typedef int
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f1309b39afe4..09a1d3400fd9 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -748,10 +748,11 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
 static void
 perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
 			 struct perf_mmap_param *_mp,
-			 int idx, bool per_cpu)
+			 int idx)
 {
 	struct evlist *evlist = container_of(_evlist, struct evlist, core);
 	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
+	bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
 
 	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (5 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx() Adrian Hunter
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Move ->idx() into mmap_per_evsel() in preparation for adding evsel as a
parameter.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 5e8ad854fa8a..4fce417432aa 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -478,6 +478,9 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 			 */
 			refcount_set(&map->refcnt, 2);
 
+			if (ops->idx)
+				ops->idx(evlist, mp, idx);
+
 			if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
 				return -1;
 
@@ -520,9 +523,6 @@ mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 		int output = -1;
 		int output_overwrite = -1;
 
-		if (ops->idx)
-			ops->idx(evlist, mp, thread);
-
 		if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread,
 				   &output, &output_overwrite))
 			goto out_unmap;
@@ -547,9 +547,6 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 		int output = -1;
 		int output_overwrite = -1;
 
-		if (ops->idx)
-			ops->idx(evlist, mp, cpu);
-
 		for (thread = 0; thread < nr_threads; thread++) {
 			if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
 					   thread, &output, &output_overwrite))
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (6 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed Adrian Hunter
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add evsel as a parameter to ->idx() in preparation for correctly
determining whether an auxtrace mmap is needed.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c                  | 2 +-
 tools/lib/perf/include/internal/evlist.h | 3 ++-
 tools/perf/util/evlist.c                 | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 4fce417432aa..ed66f2e38464 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -479,7 +479,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 			refcount_set(&map->refcnt, 2);
 
 			if (ops->idx)
-				ops->idx(evlist, mp, idx);
+				ops->idx(evlist, evsel, mp, idx);
 
 			if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
 				return -1;
diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h
index 0d5c830431a7..6f89aec3e608 100644
--- a/tools/lib/perf/include/internal/evlist.h
+++ b/tools/lib/perf/include/internal/evlist.h
@@ -38,7 +38,8 @@ struct perf_evlist {
 };
 
 typedef void
-(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int);
+(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_evsel*,
+			      struct perf_mmap_param*, int);
 typedef struct perf_mmap*
 (*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int);
 typedef int
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 09a1d3400fd9..7ae56b062f44 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -747,6 +747,7 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
 
 static void
 perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
+			 struct perf_evsel *_evsel __maybe_unused,
 			 struct perf_mmap_param *_mp,
 			 int idx)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (7 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-10 17:27   ` Arnaldo Carvalho de Melo
  2022-05-06 12:25 ` [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params Adrian Hunter
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add a flag needs_auxtrace_mmap to record whether an auxtrace mmap is
needed, in preparation for correctly determining whether or not an
auxtrace mmap is needed.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/arch/arm/util/cs-etm.c    | 1 +
 tools/perf/arch/arm64/util/arm-spe.c | 1 +
 tools/perf/arch/s390/util/auxtrace.c | 1 +
 tools/perf/arch/x86/util/intel-bts.c | 1 +
 tools/perf/arch/x86/util/intel-pt.c  | 1 +
 tools/perf/util/evsel.h              | 1 +
 6 files changed, 6 insertions(+)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 11c71aa219f7..1b54638d53b0 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -319,6 +319,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
 			}
 			evsel->core.attr.freq = 0;
 			evsel->core.attr.sample_period = 1;
+			evsel->needs_auxtrace_mmap = true;
 			cs_etm_evsel = evsel;
 			opts->full_auxtrace = true;
 		}
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
index e8b577d33e53..6f4db2ac5420 100644
--- a/tools/perf/arch/arm64/util/arm-spe.c
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -160,6 +160,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
 			}
 			evsel->core.attr.freq = 0;
 			evsel->core.attr.sample_period = arm_spe_pmu->default_config->sample_period;
+			evsel->needs_auxtrace_mmap = true;
 			arm_spe_evsel = evsel;
 			opts->full_auxtrace = true;
 		}
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
index 0db5c58c98e8..5068baa3e092 100644
--- a/tools/perf/arch/s390/util/auxtrace.c
+++ b/tools/perf/arch/s390/util/auxtrace.c
@@ -98,6 +98,7 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
 	evlist__for_each_entry(evlist, pos) {
 		if (pos->core.attr.config == PERF_EVENT_CPUM_SF_DIAG) {
 			diagnose = 1;
+			pos->needs_auxtrace_mmap = true;
 			break;
 		}
 	}
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index d68a0f48e41e..bcccfbade5c6 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -129,6 +129,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr,
 			}
 			evsel->core.attr.freq = 0;
 			evsel->core.attr.sample_period = 1;
+			evsel->needs_auxtrace_mmap = true;
 			intel_bts_evsel = evsel;
 			opts->full_auxtrace = true;
 		}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 38ec2666ec12..2eaac4638aab 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -649,6 +649,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 			evsel->core.attr.freq = 0;
 			evsel->core.attr.sample_period = 1;
 			evsel->no_aux_samples = true;
+			evsel->needs_auxtrace_mmap = true;
 			intel_pt_evsel = evsel;
 			opts->full_auxtrace = true;
 		}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 45d674812239..544fbed98df1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -124,6 +124,7 @@ struct evsel {
 	bool			merged_stat;
 	bool			reset_group;
 	bool			errored;
+	bool			needs_auxtrace_mmap;
 	struct hashmap		*per_pkg_mask;
 	int			err;
 	struct {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (8 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 20:16   ` Ian Rogers
  2022-05-11  7:01   ` [PATCH V3 " Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter Adrian Hunter
                   ` (13 subsequent siblings)
  23 siblings, 2 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add mmap_needed to auxtrace_mmap_params.

Currently an auxtrace mmap is always attempted even if the event is not an
auxtrace event. That works because, when AUX area tracing, there is always
an auxtrace event first for every mmap. Prepare for that not being the
case, which it won't be when sideband tracking events are allowed on
all CPUs even when auxtrace is limited to selected CPUs.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/auxtrace.c | 10 ++++++++--
 tools/perf/util/auxtrace.h |  8 ++++++--
 tools/perf/util/evlist.c   |  5 +++--
 tools/perf/util/mmap.c     |  1 +
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index b11549ae39df..b446cfa66469 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -125,7 +125,7 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
 	mm->tid = mp->tid;
 	mm->cpu = mp->cpu.cpu;
 
-	if (!mp->len) {
+	if (!mp->len || !mp->mmap_needed) {
 		mm->base = NULL;
 		return 0;
 	}
@@ -168,9 +168,15 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 }
 
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu)
 {
+	mp->mmap_needed = evsel->needs_auxtrace_mmap;
+
+	if (!mp->mmap_needed)
+		return;
+
 	mp->idx = idx;
 
 	if (per_cpu) {
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index dc38b6f57232..37feae003904 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -344,6 +344,7 @@ struct auxtrace_mmap {
  * @idx: index of this mmap
  * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
  *       mmap) otherwise %0
+ * @mmap_needed: set to %false for non-auxtrace events
  * @cpu: cpu number for a per-cpu mmap otherwise %-1
  */
 struct auxtrace_mmap_params {
@@ -353,6 +354,7 @@ struct auxtrace_mmap_params {
 	int		prot;
 	int		idx;
 	pid_t		tid;
+	bool		mmap_needed;
 	struct perf_cpu	cpu;
 };
 
@@ -490,7 +492,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				unsigned int auxtrace_pages,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu);
 
 typedef int (*process_auxtrace_t)(struct perf_tool *tool,
@@ -863,7 +866,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				unsigned int auxtrace_pages,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu);
 
 #define ITRACE_HELP ""
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 7ae56b062f44..996bdc203616 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -747,15 +747,16 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
 
 static void
 perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
-			 struct perf_evsel *_evsel __maybe_unused,
+			 struct perf_evsel *_evsel,
 			 struct perf_mmap_param *_mp,
 			 int idx)
 {
 	struct evlist *evlist = container_of(_evlist, struct evlist, core);
 	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
 	bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
+	struct evsel *evsel = container_of(_evsel, struct evsel, core);
 
-	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
+	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
 }
 
 static struct perf_mmap*
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index 50502b4a7ca4..de59c4da852b 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -62,6 +62,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
 
 void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
 					  struct evlist *evlist __maybe_unused,
+					  struct evsel *evsel __maybe_unused,
 					  int idx __maybe_unused,
 					  bool per_cpu __maybe_unused)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (9 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 20:19   ` Ian Rogers
  2022-05-06 12:25 ` [PATCH V2 12/23] perf evlist: Factor out evlist__dummy_event() Adrian Hunter
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Remove auxtrace_mmap_params__set_idx() per_cpu parameter because it isn't
needed.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/auxtrace.c | 5 +++--
 tools/perf/util/auxtrace.h | 6 ++----
 tools/perf/util/evlist.c   | 3 +--
 tools/perf/util/mmap.c     | 3 +--
 4 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index b446cfa66469..ac4e4660932d 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -169,9 +169,10 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
 				   struct evlist *evlist,
-				   struct evsel *evsel, int idx,
-				   bool per_cpu)
+				   struct evsel *evsel, int idx)
 {
+	bool per_cpu = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
+
 	mp->mmap_needed = evsel->needs_auxtrace_mmap;
 
 	if (!mp->mmap_needed)
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index 37feae003904..87a3b564a7de 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -493,8 +493,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
 				   struct evlist *evlist,
-				   struct evsel *evsel, int idx,
-				   bool per_cpu);
+				   struct evsel *evsel, int idx);
 
 typedef int (*process_auxtrace_t)(struct perf_tool *tool,
 				  struct mmap *map,
@@ -867,8 +866,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
 				   struct evlist *evlist,
-				   struct evsel *evsel, int idx,
-				   bool per_cpu);
+				   struct evsel *evsel, int idx);
 
 #define ITRACE_HELP ""
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 996bdc203616..25eae096bdac 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -753,10 +753,9 @@ perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
 {
 	struct evlist *evlist = container_of(_evlist, struct evlist, core);
 	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
-	bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
 	struct evsel *evsel = container_of(_evsel, struct evsel, core);
 
-	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
+	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx);
 }
 
 static struct perf_mmap*
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index de59c4da852b..a4dff881be39 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -63,8 +63,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
 void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
 					  struct evlist *evlist __maybe_unused,
 					  struct evsel *evsel __maybe_unused,
-					  int idx __maybe_unused,
-					  bool per_cpu __maybe_unused)
+					  int idx __maybe_unused)
 {
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 12/23] perf evlist: Factor out evlist__dummy_event()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (10 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus() Adrian Hunter
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Factor out evlist__dummy_event() so it can be reused.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/evlist.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 25eae096bdac..78c47cbafbc2 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -242,14 +242,20 @@ int __evlist__add_default(struct evlist *evlist, bool precise)
 	return 0;
 }
 
-int evlist__add_dummy(struct evlist *evlist)
+static struct evsel *evlist__dummy_event(struct evlist *evlist)
 {
 	struct perf_event_attr attr = {
 		.type	= PERF_TYPE_SOFTWARE,
 		.config = PERF_COUNT_SW_DUMMY,
 		.size	= sizeof(attr), /* to capture ABI version */
 	};
-	struct evsel *evsel = evsel__new_idx(&attr, evlist->core.nr_entries);
+
+	return evsel__new_idx(&attr, evlist->core.nr_entries);
+}
+
+int evlist__add_dummy(struct evlist *evlist)
+{
+	struct evsel *evsel = evlist__dummy_event(evlist);
 
 	if (evsel == NULL)
 		return -ENOMEM;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (11 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 12/23] perf evlist: Factor out evlist__dummy_event() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 13:47   ` Ian Rogers
  2022-05-11  7:02   ` [PATCH V3 " Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 14/23] perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke() Adrian Hunter
                   ` (10 subsequent siblings)
  23 siblings, 2 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
event that sets up the system-wide maps before map propagation.

For convenience, add evlist__add_aux_dummy() so that the logic can be used
whether or not the event needs to be system-wide.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  5 +++++
 2 files changed, 45 insertions(+)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 78c47cbafbc2..c16bd4836314 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
 	return 0;
 }
 
+static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
+{
+	evsel->core.system_wide = true;
+
+	/* All CPUs */
+	perf_cpu_map__put(evsel->core.own_cpus);
+	evsel->core.own_cpus = perf_cpu_map__new(NULL);
+	perf_cpu_map__put(evsel->core.cpus);
+	evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
+
+	/* No threads */
+	perf_thread_map__put(evsel->core.threads);
+	evsel->core.threads = perf_thread_map__new_dummy();
+
+	evlist__add(evlist, evsel);
+}
+
+struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
+{
+	struct evsel *evsel = evlist__dummy_event(evlist);
+
+	if (!evsel)
+		return NULL;
+
+	evsel->core.attr.exclude_kernel = 1;
+	evsel->core.attr.exclude_guest = 1;
+	evsel->core.attr.exclude_hv = 1;
+	evsel->core.attr.freq = 0;
+	evsel->core.attr.sample_period = 1;
+	evsel->no_aux_samples = true;
+	evsel->name = strdup("dummy:u");
+
+	if (system_wide)
+		evlist__add_on_all_cpus(evlist, evsel);
+	else
+		evlist__add(evlist, evsel);
+
+	return evsel;
+}
+
 static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
 {
 	struct evsel *evsel, *n;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 4062f5aebfc1..1bde9ccf4e7d 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
 struct evsel *arch_evlist__leader(struct list_head *list);
 
 int evlist__add_dummy(struct evlist *evlist);
+struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
+static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
+{
+	return evlist__add_aux_dummy(evlist, true);
+}
 
 int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
 			 evsel__sb_cb_t cb, void *data);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 14/23] perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke()
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (12 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 15/23] perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking Adrian Hunter
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Use evlist__add_dummy_on_all_cpus() in record__config_text_poke() in
preparation for allowing system-wide events on all CPUs while the user
requested events are on only user requested CPUs.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-record.c | 21 +++------------------
 1 file changed, 3 insertions(+), 18 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a5cf6a99d67f..c8a79f3a8dff 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -869,7 +869,6 @@ static int record__auxtrace_init(struct record *rec __maybe_unused)
 static int record__config_text_poke(struct evlist *evlist)
 {
 	struct evsel *evsel;
-	int err;
 
 	/* Nothing to do if text poke is already configured */
 	evlist__for_each_entry(evlist, evsel) {
@@ -877,27 +876,13 @@ static int record__config_text_poke(struct evlist *evlist)
 			return 0;
 	}
 
-	err = parse_events(evlist, "dummy:u", NULL);
-	if (err)
-		return err;
-
-	evsel = evlist__last(evlist);
+	evsel = evlist__add_dummy_on_all_cpus(evlist);
+	if (!evsel)
+		return -ENOMEM;
 
-	evsel->core.attr.freq = 0;
-	evsel->core.attr.sample_period = 1;
 	evsel->core.attr.text_poke = 1;
 	evsel->core.attr.ksymbol = 1;
-
-	evsel->core.system_wide = true;
-	evsel->no_aux_samples = true;
 	evsel->immediate = true;
-
-	/* Text poke must be collected on all CPUs */
-	perf_cpu_map__put(evsel->core.own_cpus);
-	evsel->core.own_cpus = perf_cpu_map__new(NULL);
-	perf_cpu_map__put(evsel->core.cpus);
-	evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
-
 	evsel__set_sample_bit(evsel, TIME);
 
 	return 0;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 15/23] perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (13 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 14/23] perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke() Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 16/23] perf intel-pt: Track sideband system-wide when needed Adrian Hunter
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Use evlist__add_dummy_on_all_cpus() for switch tracking in preparation for
allowing system-wide events on all CPUs while the user requested events are
on only user requested CPUs.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/arch/x86/util/intel-pt.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 2eaac4638aab..0ee93894a0da 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -811,18 +811,11 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 			if (!cpu_wide && perf_can_record_cpu_wide()) {
 				struct evsel *switch_evsel;
 
-				err = parse_events(evlist, "dummy:u", NULL);
-				if (err)
-					return err;
+				switch_evsel = evlist__add_dummy_on_all_cpus(evlist);
+				if (!switch_evsel)
+					return -ENOMEM;
 
-				switch_evsel = evlist__last(evlist);
-
-				switch_evsel->core.attr.freq = 0;
-				switch_evsel->core.attr.sample_period = 1;
 				switch_evsel->core.attr.context_switch = 1;
-
-				switch_evsel->core.system_wide = true;
-				switch_evsel->no_aux_samples = true;
 				switch_evsel->immediate = true;
 
 				evsel__set_sample_bit(switch_evsel, TID);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 16/23] perf intel-pt: Track sideband system-wide when needed
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (14 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 15/23] perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 17/23] perf tools: Allow all_cpus to be a superset of user_requested_cpus Adrian Hunter
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

User space tasks can migrate between CPUs, so when tracing selected CPUs,
sideband for all CPUs is still needed. This is in preparation for allowing
system-wide events on all CPUs while the user requested events are on only
user requested CPUs.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/arch/x86/util/intel-pt.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 0ee93894a0da..06c2cdfd8f2f 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -864,20 +864,22 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 
 	/* Add dummy event to keep tracking */
 	if (opts->full_auxtrace) {
+		bool need_system_wide_tracking;
 		struct evsel *tracking_evsel;
 
-		err = parse_events(evlist, "dummy:u", NULL);
-		if (err)
-			return err;
+		/*
+		 * User space tasks can migrate between CPUs, so when tracing
+		 * selected CPUs, sideband for all CPUs is still needed.
+		 */
+		need_system_wide_tracking = evlist->core.has_user_cpus &&
+					    !intel_pt_evsel->core.attr.exclude_user;
 
-		tracking_evsel = evlist__last(evlist);
+		tracking_evsel = evlist__add_aux_dummy(evlist, need_system_wide_tracking);
+		if (!tracking_evsel)
+			return -ENOMEM;
 
 		evlist__set_tracking_event(evlist, tracking_evsel);
 
-		tracking_evsel->core.attr.freq = 0;
-		tracking_evsel->core.attr.sample_period = 1;
-
-		tracking_evsel->no_aux_samples = true;
 		if (need_immediate)
 			tracking_evsel->immediate = true;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 17/23] perf tools: Allow all_cpus to be a superset of user_requested_cpus
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (15 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 16/23] perf intel-pt: Track sideband system-wide when needed Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 18/23] libperf evlist: Allow mixing per-thread and per-cpu mmaps Adrian Hunter
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

To support collection of system-wide events with user requested CPUs,
all_cpus must be a superset of user_requested_cpus.

In order to support all_cpus to be a superset of user_requested_cpus,
all_cpus must be used instead of user_requested_cpus when dealing with CPUs
of all events instead of CPUs of requested events.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c     | 12 ++++++------
 tools/perf/builtin-record.c | 18 ++++++++++++------
 tools/perf/util/auxtrace.c  |  2 +-
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index ed66f2e38464..ec0e4b5da874 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -298,7 +298,7 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist,
 
 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
-	int nr_cpus = perf_cpu_map__nr(evlist->user_requested_cpus);
+	int nr_cpus = perf_cpu_map__nr(evlist->all_cpus);
 	int nr_threads = perf_thread_map__nr(evlist->threads);
 	int nfds = 0;
 	struct perf_evsel *evsel;
@@ -430,7 +430,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 	       int idx, struct perf_mmap_param *mp, int cpu_idx,
 	       int thread, int *_output, int *_output_overwrite)
 {
-	struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->user_requested_cpus, cpu_idx);
+	struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->all_cpus, cpu_idx);
 	struct perf_evsel *evsel;
 	int revent;
 
@@ -540,7 +540,7 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 	     struct perf_mmap_param *mp)
 {
 	int nr_threads = perf_thread_map__nr(evlist->threads);
-	int nr_cpus    = perf_cpu_map__nr(evlist->user_requested_cpus);
+	int nr_cpus    = perf_cpu_map__nr(evlist->all_cpus);
 	int cpu, thread;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
@@ -565,8 +565,8 @@ static int perf_evlist__nr_mmaps(struct perf_evlist *evlist)
 {
 	int nr_mmaps;
 
-	nr_mmaps = perf_cpu_map__nr(evlist->user_requested_cpus);
-	if (perf_cpu_map__empty(evlist->user_requested_cpus))
+	nr_mmaps = perf_cpu_map__nr(evlist->all_cpus);
+	if (perf_cpu_map__empty(evlist->all_cpus))
 		nr_mmaps = perf_thread_map__nr(evlist->threads);
 
 	return nr_mmaps;
@@ -577,7 +577,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
 			  struct perf_mmap_param *mp)
 {
 	struct perf_evsel *evsel;
-	const struct perf_cpu_map *cpus = evlist->user_requested_cpus;
+	const struct perf_cpu_map *cpus = evlist->all_cpus;
 
 	if (!ops || !ops->get || !ops->mmap)
 		return -EINVAL;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index c8a79f3a8dff..cf9a7ce429df 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -967,14 +967,20 @@ static void record__thread_data_close_pipes(struct record_thread *thread_data)
 	}
 }
 
+static bool evlist__per_thread(struct evlist *evlist)
+{
+	return cpu_map__is_dummy(evlist->core.user_requested_cpus);
+}
+
 static int record__thread_data_init_maps(struct record_thread *thread_data, struct evlist *evlist)
 {
 	int m, tm, nr_mmaps = evlist->core.nr_mmaps;
 	struct mmap *mmap = evlist->mmap;
 	struct mmap *overwrite_mmap = evlist->overwrite_mmap;
-	struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
+	struct perf_cpu_map *cpus = evlist->core.all_cpus;
+	bool per_thread = evlist__per_thread(evlist);
 
-	if (cpu_map__is_dummy(cpus))
+	if (per_thread)
 		thread_data->nr_mmaps = nr_mmaps;
 	else
 		thread_data->nr_mmaps = bitmap_weight(thread_data->mask->maps.bits,
@@ -995,7 +1001,7 @@ static int record__thread_data_init_maps(struct record_thread *thread_data, stru
 		 thread_data->nr_mmaps, thread_data->maps, thread_data->overwrite_maps);
 
 	for (m = 0, tm = 0; m < nr_mmaps && tm < thread_data->nr_mmaps; m++) {
-		if (cpu_map__is_dummy(cpus) ||
+		if (per_thread ||
 		    test_bit(perf_cpu_map__cpu(cpus, m).cpu, thread_data->mask->maps.bits)) {
 			if (thread_data->maps) {
 				thread_data->maps[tm] = &mmap[m];
@@ -1870,7 +1876,7 @@ static int record__synthesize(struct record *rec, bool tail)
 		return err;
 	}
 
-	err = perf_event__synthesize_cpu_map(&rec->tool, rec->evlist->core.user_requested_cpus,
+	err = perf_event__synthesize_cpu_map(&rec->tool, rec->evlist->core.all_cpus,
 					     process_synthesized_event, NULL);
 	if (err < 0) {
 		pr_err("Couldn't synthesize cpu map.\n");
@@ -3668,12 +3674,12 @@ static int record__init_thread_default_masks(struct record *rec, struct perf_cpu
 static int record__init_thread_masks(struct record *rec)
 {
 	int ret = 0;
-	struct perf_cpu_map *cpus = rec->evlist->core.user_requested_cpus;
+	struct perf_cpu_map *cpus = rec->evlist->core.all_cpus;
 
 	if (!record__threads_enabled(rec))
 		return record__init_thread_default_masks(rec, cpus);
 
-	if (cpu_map__is_dummy(cpus)) {
+	if (evlist__per_thread(rec->evlist)) {
 		pr_err("--per-thread option is mutually exclusive to parallel streaming mode.\n");
 		return -EINVAL;
 	}
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index ac4e4660932d..511dd3caa1bc 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -181,7 +181,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
 	mp->idx = idx;
 
 	if (per_cpu) {
-		mp->cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, idx);
+		mp->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);
 		if (evlist->core.threads)
 			mp->tid = perf_thread_map__pid(evlist->core.threads, 0);
 		else
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 18/23] libperf evlist: Allow mixing per-thread and per-cpu mmaps
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (16 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 17/23] perf tools: Allow all_cpus to be a superset of user_requested_cpus Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct Adrian Hunter
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

mmap_per_evsel() will skip events that do not match the CPU, so all CPUs
can be iterated in any case.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c | 36 +++++++-----------------------------
 1 file changed, 7 insertions(+), 29 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index ec0e4b5da874..eae1f6179dad 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -512,29 +512,6 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 	return 0;
 }
 
-static int
-mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
-		struct perf_mmap_param *mp)
-{
-	int thread;
-	int nr_threads = perf_thread_map__nr(evlist->threads);
-
-	for (thread = 0; thread < nr_threads; thread++) {
-		int output = -1;
-		int output_overwrite = -1;
-
-		if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread,
-				   &output, &output_overwrite))
-			goto out_unmap;
-	}
-
-	return 0;
-
-out_unmap:
-	perf_evlist__munmap(evlist);
-	return -1;
-}
-
 static int
 mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 	     struct perf_mmap_param *mp)
@@ -565,9 +542,14 @@ static int perf_evlist__nr_mmaps(struct perf_evlist *evlist)
 {
 	int nr_mmaps;
 
+	/* One for each CPU */
 	nr_mmaps = perf_cpu_map__nr(evlist->all_cpus);
-	if (perf_cpu_map__empty(evlist->all_cpus))
-		nr_mmaps = perf_thread_map__nr(evlist->threads);
+	if (perf_cpu_map__empty(evlist->all_cpus)) {
+		/* Plus one for each thread */
+		nr_mmaps += perf_thread_map__nr(evlist->threads);
+		/* Minus the per-thread CPU (-1) */
+		nr_mmaps -= 1;
+	}
 
 	return nr_mmaps;
 }
@@ -577,7 +559,6 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
 			  struct perf_mmap_param *mp)
 {
 	struct perf_evsel *evsel;
-	const struct perf_cpu_map *cpus = evlist->all_cpus;
 
 	if (!ops || !ops->get || !ops->mmap)
 		return -EINVAL;
@@ -596,9 +577,6 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
 	if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
 		return -ENOMEM;
 
-	if (perf_cpu_map__empty(cpus))
-		return mmap_per_thread(evlist, ops, mp);
-
 	return mmap_per_cpu(evlist, ops, mp);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (17 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 18/23] libperf evlist: Allow mixing per-thread and per-cpu mmaps Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 20:20   ` Ian Rogers
  2022-05-06 12:25 ` [PATCH V2 20/23] perf stat: Add requires_cpu flag for uncore Adrian Hunter
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Print an error message if the predetermined number of mmaps is
incorrect.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index eae1f6179dad..f51fdb899d19 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -23,6 +23,7 @@
 #include <perf/cpumap.h>
 #include <perf/threadmap.h>
 #include <api/fd/array.h>
+#include "internal.h"
 
 void perf_evlist__init(struct perf_evlist *evlist)
 {
@@ -428,7 +429,7 @@ static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_
 static int
 mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 	       int idx, struct perf_mmap_param *mp, int cpu_idx,
-	       int thread, int *_output, int *_output_overwrite)
+	       int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
 {
 	struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->all_cpus, cpu_idx);
 	struct perf_evsel *evsel;
@@ -484,6 +485,8 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 			if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
 				return -1;
 
+			*nr_mmaps += 1;
+
 			if (!idx)
 				perf_evlist__set_mmap_first(evlist, map, overwrite);
 		} else {
@@ -518,6 +521,7 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 {
 	int nr_threads = perf_thread_map__nr(evlist->threads);
 	int nr_cpus    = perf_cpu_map__nr(evlist->all_cpus);
+	int nr_mmaps = 0;
 	int cpu, thread;
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
@@ -526,11 +530,14 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
 
 		for (thread = 0; thread < nr_threads; thread++) {
 			if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
-					   thread, &output, &output_overwrite))
+					   thread, &output, &output_overwrite, &nr_mmaps))
 				goto out_unmap;
 		}
 	}
 
+	if (nr_mmaps != evlist->nr_mmaps)
+		pr_err("Miscounted nr_mmaps %d vs %d\n", nr_mmaps, evlist->nr_mmaps);
+
 	return 0;
 
 out_unmap:
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 20/23] perf stat: Add requires_cpu flag for uncore
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (18 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 12:25 ` [PATCH V2 21/23] libperf evsel: Add comments for booleans Adrian Hunter
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Uncore events require a CPU i.e. it cannot be -1.

The evsel system_wide flag is intended for events that should be on every
CPU, which does not make sense for uncore events because uncore events do
not map one-to-one with CPUs.

These 2 requirements are not exactly the same, so introduce a new flag
'requires_cpu' for the uncore case.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c                 | 4 +++-
 tools/lib/perf/include/internal/evsel.h | 1 +
 tools/perf/builtin-stat.c               | 5 +----
 tools/perf/util/evsel.c                 | 1 +
 tools/perf/util/parse-events.c          | 2 +-
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index f51fdb899d19..1c801f8da44f 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -43,7 +43,9 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
 	if (!evsel->own_cpus || evlist->has_user_cpus) {
 		perf_cpu_map__put(evsel->cpus);
 		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
-	} else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
+	} else if (!evsel->system_wide &&
+		   !evsel->requires_cpu &&
+		   perf_cpu_map__empty(evlist->user_requested_cpus)) {
 		perf_cpu_map__put(evsel->cpus);
 		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
 	} else if (evsel->cpus != evsel->own_cpus) {
diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
index cfc9ebd7968e..77fbb8b97e5c 100644
--- a/tools/lib/perf/include/internal/evsel.h
+++ b/tools/lib/perf/include/internal/evsel.h
@@ -50,6 +50,7 @@ struct perf_evsel {
 	/* parse modifier helper */
 	int			 nr_members;
 	bool			 system_wide;
+	bool			 requires_cpu;
 	int			 idx;
 };
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1b96636df01e..c049533f74e4 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -385,9 +385,6 @@ static int read_counter_cpu(struct evsel *counter, struct timespec *rs, int cpu_
 	if (!counter->supported)
 		return -ENOENT;
 
-	if (counter->core.system_wide)
-		nthreads = 1;
-
 	for (thread = 0; thread < nthreads; thread++) {
 		struct perf_counts_values *count;
 
@@ -2264,7 +2261,7 @@ static void setup_system_wide(int forks)
 		struct evsel *counter;
 
 		evlist__for_each_entry(evsel_list, counter) {
-			if (!counter->core.system_wide &&
+			if (!counter->core.requires_cpu &&
 			    strcmp(counter->name, "duration_time")) {
 				return;
 			}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d38722560e80..12346293706b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -382,6 +382,7 @@ struct evsel *evsel__clone(struct evsel *orig)
 	evsel->core.threads = perf_thread_map__get(orig->core.threads);
 	evsel->core.nr_members = orig->core.nr_members;
 	evsel->core.system_wide = orig->core.system_wide;
+	evsel->core.requires_cpu = orig->core.requires_cpu;
 
 	if (orig->name) {
 		evsel->name = strdup(orig->name);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 937f6c9434a2..5227174099b5 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -365,7 +365,7 @@ __add_event(struct list_head *list, int *idx,
 	(*idx)++;
 	evsel->core.cpus = cpus;
 	evsel->core.own_cpus = perf_cpu_map__get(cpus);
-	evsel->core.system_wide = pmu ? pmu->is_uncore : false;
+	evsel->core.requires_cpu = pmu ? pmu->is_uncore : false;
 	evsel->auto_merge_stats = auto_merge_stats;
 
 	if (name)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 21/23] libperf evsel: Add comments for booleans
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (19 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 20/23] perf stat: Add requires_cpu flag for uncore Adrian Hunter
@ 2022-05-06 12:25 ` Adrian Hunter
  2022-05-06 20:51   ` Ian Rogers
  2022-05-06 12:26 ` [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs Adrian Hunter
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add comments for 'system_wide' and 'requires_cpu' booleans

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/include/internal/evsel.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
index 77fbb8b97e5c..cc8f1ba790bd 100644
--- a/tools/lib/perf/include/internal/evsel.h
+++ b/tools/lib/perf/include/internal/evsel.h
@@ -49,7 +49,16 @@ struct perf_evsel {
 
 	/* parse modifier helper */
 	int			 nr_members;
+	/*
+	 * system_wide is for events that need to be on every CPU, irrespective
+	 * of user requested CPUs or threads. Map propagation will not override
+	 * this events own_cpus, which will contribute to evlist all_cpus.
+	 */
 	bool			 system_wide;
+	/*
+	 * Some events, for example uncore events, require a CPU.
+	 * i.e. it cannot be the 'any CPU' value of -1.
+	 */
 	bool			 requires_cpu;
 	int			 idx;
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (20 preceding siblings ...)
  2022-05-06 12:25 ` [PATCH V2 21/23] libperf evsel: Add comments for booleans Adrian Hunter
@ 2022-05-06 12:26 ` Adrian Hunter
  2022-05-12  5:27   ` Namhyung Kim
  2022-05-06 12:26 ` [PATCH V2 23/23] perf tools: Allow system-wide events to keep their own threads Adrian Hunter
  2022-05-08 15:08 ` [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Leo Yan
  23 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:26 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Currently, user_requested_cpus supplants system-wide CPUs when the evlist
has_user_cpus. Change that so that system-wide events retain their own
CPUs and they are added to all_cpus.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 1c801f8da44f..9a6801b53274 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
 	 * We already have cpus for evsel (via PMU sysfs) so
 	 * keep it, if there's no target cpu list defined.
 	 */
-	if (!evsel->own_cpus || evlist->has_user_cpus) {
-		perf_cpu_map__put(evsel->cpus);
-		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
-	} else if (!evsel->system_wide &&
-		   !evsel->requires_cpu &&
-		   perf_cpu_map__empty(evlist->user_requested_cpus)) {
+	if (!evsel->own_cpus ||
+	    (!evsel->system_wide && evlist->has_user_cpus) ||
+	    (!evsel->system_wide &&
+	     !evsel->requires_cpu &&
+	     perf_cpu_map__empty(evlist->user_requested_cpus))) {
 		perf_cpu_map__put(evsel->cpus);
 		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
 	} else if (evsel->cpus != evsel->own_cpus) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH V2 23/23] perf tools: Allow system-wide events to keep their own threads
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (21 preceding siblings ...)
  2022-05-06 12:26 ` [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs Adrian Hunter
@ 2022-05-06 12:26 ` Adrian Hunter
  2022-05-08 15:08 ` [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Leo Yan
  23 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 12:26 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

System-wide events do not have threads, so do not propagate threads to
them.

Acked-by: Ian Rogers <irogers@google.com>
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/evlist.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index 9a6801b53274..e6c98a6e3908 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -52,8 +52,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
 		evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
 	}
 
-	perf_thread_map__put(evsel->threads);
-	evsel->threads = perf_thread_map__get(evlist->threads);
+	if (!evsel->system_wide) {
+		perf_thread_map__put(evsel->threads);
+		evsel->threads = perf_thread_map__get(evlist->threads);
+	}
+
 	evlist->all_cpus = perf_cpu_map__merge(evlist->all_cpus, evsel->cpus);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 12:25 ` [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus() Adrian Hunter
@ 2022-05-06 13:47   ` Ian Rogers
  2022-05-06 15:07     ` Adrian Hunter
  2022-05-11  7:02   ` [PATCH V3 " Adrian Hunter
  1 sibling, 1 reply; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 13:47 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> event that sets up the system-wide maps before map propagation.
>
> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> whether or not the event needs to be system-wide.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/evlist.h |  5 +++++
>  2 files changed, 45 insertions(+)
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 78c47cbafbc2..c16bd4836314 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
>         return 0;
>  }
>
> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> +{
> +       evsel->core.system_wide = true;
> +
> +       /* All CPUs */
> +       perf_cpu_map__put(evsel->core.own_cpus);
> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> +       perf_cpu_map__put(evsel->core.cpus);
> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> +
> +       /* No threads */
> +       perf_thread_map__put(evsel->core.threads);
> +       evsel->core.threads = perf_thread_map__new_dummy();
> +
> +       evlist__add(evlist, evsel);
> +}
> +
> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
> +{
> +       struct evsel *evsel = evlist__dummy_event(evlist);
> +
> +       if (!evsel)
> +               return NULL;
> +
> +       evsel->core.attr.exclude_kernel = 1;
> +       evsel->core.attr.exclude_guest = 1;
> +       evsel->core.attr.exclude_hv = 1;
> +       evsel->core.attr.freq = 0;
> +       evsel->core.attr.sample_period = 1;
> +       evsel->no_aux_samples = true;
> +       evsel->name = strdup("dummy:u");
> +
> +       if (system_wide)
> +               evlist__add_on_all_cpus(evlist, evsel);
> +       else
> +               evlist__add(evlist, evsel);
> +
> +       return evsel;
> +}
> +
>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>  {
>         struct evsel *evsel, *n;
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 4062f5aebfc1..1bde9ccf4e7d 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>  struct evsel *arch_evlist__leader(struct list_head *list);
>
>  int evlist__add_dummy(struct evlist *evlist);
> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)

Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:

empty == dummy == any CPU
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279

Given every CPU map should be empty or contain any CPU then it seems
they all meet the definition of empty - so something is wrong.

The cpu map here is explicitly opened so that it gets all online CPUs:
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174

From:
https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
there are example topologies like:
kernel_max: 31
   offline: 2,4-31,32-63
    online: 0-1,3
  possible: 0-31
   present: 0-31

all_cpus could mean the union of offline and online CPUs, possible
CPUs or present CPUs. You are saying that in the perf code all_cpus
should be the same as all online cpus as only those CPUs are valid
with perf_event_open. That's true but offline CPUs can be made online.
If that happens here then the dummy events will have a CPU map that
rather than being for all CPUs will be for all online CPUs at the
point it was opened. Having online in the function name I think
captures the time dependent nature of this - but if you think that's
too much could we add a comment? I'm trying to avoid a situation, like
with the CPU map code, where all and online are interchangeable
leading to the code being unnecessarily confusing unless you read
every line.

Thanks,
Ian

> +{
> +       return evlist__add_aux_dummy(evlist, true);
> +}
>
>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>                          evsel__sb_cb_t cb, void *data);
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 13:47   ` Ian Rogers
@ 2022-05-06 15:07     ` Adrian Hunter
  2022-05-06 15:35       ` Ian Rogers
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-06 15:07 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On 6/05/22 16:47, Ian Rogers wrote:
> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
>> event that sets up the system-wide maps before map propagation.
>>
>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
>> whether or not the event needs to be system-wide.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
>>  tools/perf/util/evlist.h |  5 +++++
>>  2 files changed, 45 insertions(+)
>>
>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>> index 78c47cbafbc2..c16bd4836314 100644
>> --- a/tools/perf/util/evlist.c
>> +++ b/tools/perf/util/evlist.c
>> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
>>         return 0;
>>  }
>>
>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
>> +{
>> +       evsel->core.system_wide = true;
>> +
>> +       /* All CPUs */
>> +       perf_cpu_map__put(evsel->core.own_cpus);
>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
>> +       perf_cpu_map__put(evsel->core.cpus);
>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
>> +
>> +       /* No threads */
>> +       perf_thread_map__put(evsel->core.threads);
>> +       evsel->core.threads = perf_thread_map__new_dummy();
>> +
>> +       evlist__add(evlist, evsel);
>> +}
>> +
>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
>> +{
>> +       struct evsel *evsel = evlist__dummy_event(evlist);
>> +
>> +       if (!evsel)
>> +               return NULL;
>> +
>> +       evsel->core.attr.exclude_kernel = 1;
>> +       evsel->core.attr.exclude_guest = 1;
>> +       evsel->core.attr.exclude_hv = 1;
>> +       evsel->core.attr.freq = 0;
>> +       evsel->core.attr.sample_period = 1;
>> +       evsel->no_aux_samples = true;
>> +       evsel->name = strdup("dummy:u");
>> +
>> +       if (system_wide)
>> +               evlist__add_on_all_cpus(evlist, evsel);
>> +       else
>> +               evlist__add(evlist, evsel);
>> +
>> +       return evsel;
>> +}
>> +
>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>>  {
>>         struct evsel *evsel, *n;
>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
>> index 4062f5aebfc1..1bde9ccf4e7d 100644
>> --- a/tools/perf/util/evlist.h
>> +++ b/tools/perf/util/evlist.h
>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>>  struct evsel *arch_evlist__leader(struct list_head *list);
>>
>>  int evlist__add_dummy(struct evlist *evlist);
>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
> 
> Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
> 
> empty == dummy == any CPU
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
> 
> Given every CPU map should be empty or contain any CPU then it seems
> they all meet the definition of empty - so something is wrong.

Nothing is wrong.  I am not against clarifying things, but stop assuming
natural language has to mean anything exactly.  That is what computer
languages are for.

Sometimes more abstract language is used, precisely to stop people
making assumptions about the details.

> 
> The cpu map here is explicitly opened so that it gets all online CPUs:
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
> 
> From:
> https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
> there are example topologies like:
> kernel_max: 31
>    offline: 2,4-31,32-63
>     online: 0-1,3
>   possible: 0-31
>    present: 0-31
> 
> all_cpus could mean the union of offline and online CPUs, possible
> CPUs or present CPUs. You are saying that in the perf code all_cpus
> should be the same as all online cpus as only those CPUs are valid
> with perf_event_open. That's true but offline CPUs can be made online.
> If that happens here then the dummy events will have a CPU map that
> rather than being for all CPUs will be for all online CPUs at the
> point it was opened. Having online in the function name I think
> captures the time dependent nature of this - but if you think that's
> too much could we add a comment?

If you ask me it does the exact opposite.  The function of the code
is to put the event on all CPUS without having to know the details
of: well actually perf doesn't automagically retain or restore events
across enabling or disabling CPUs so in fact we deal only in online
CPUs.

> too much could we add a comment? I'm trying to avoid a situation, like
> with the CPU map code, where all and online are interchangeable
> leading to the code being unnecessarily confusing unless you read
> every line.

It is normal to have to read the details of code, and, in my
experience at least, normal for the code not to work exactly the
way I'd imagined.

> 
> Thanks,
> Ian
> 
>> +{
>> +       return evlist__add_aux_dummy(evlist, true);
>> +}
>>
>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>>                          evsel__sb_cb_t cb, void *data);
>> --
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 15:07     ` Adrian Hunter
@ 2022-05-06 15:35       ` Ian Rogers
  2022-05-10 14:55         ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 15:35 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 8:08 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 6/05/22 16:47, Ian Rogers wrote:
> > On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> >> event that sets up the system-wide maps before map propagation.
> >>
> >> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> >> whether or not the event needs to be system-wide.
> >>
> >> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >> ---
> >>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
> >>  tools/perf/util/evlist.h |  5 +++++
> >>  2 files changed, 45 insertions(+)
> >>
> >> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >> index 78c47cbafbc2..c16bd4836314 100644
> >> --- a/tools/perf/util/evlist.c
> >> +++ b/tools/perf/util/evlist.c
> >> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
> >>         return 0;
> >>  }
> >>
> >> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> >> +{
> >> +       evsel->core.system_wide = true;
> >> +
> >> +       /* All CPUs */
> >> +       perf_cpu_map__put(evsel->core.own_cpus);
> >> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> >> +       perf_cpu_map__put(evsel->core.cpus);
> >> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> >> +
> >> +       /* No threads */
> >> +       perf_thread_map__put(evsel->core.threads);
> >> +       evsel->core.threads = perf_thread_map__new_dummy();
> >> +
> >> +       evlist__add(evlist, evsel);
> >> +}
> >> +
> >> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
> >> +{
> >> +       struct evsel *evsel = evlist__dummy_event(evlist);
> >> +
> >> +       if (!evsel)
> >> +               return NULL;
> >> +
> >> +       evsel->core.attr.exclude_kernel = 1;
> >> +       evsel->core.attr.exclude_guest = 1;
> >> +       evsel->core.attr.exclude_hv = 1;
> >> +       evsel->core.attr.freq = 0;
> >> +       evsel->core.attr.sample_period = 1;
> >> +       evsel->no_aux_samples = true;
> >> +       evsel->name = strdup("dummy:u");
> >> +
> >> +       if (system_wide)
> >> +               evlist__add_on_all_cpus(evlist, evsel);
> >> +       else
> >> +               evlist__add(evlist, evsel);
> >> +
> >> +       return evsel;
> >> +}
> >> +
> >>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
> >>  {
> >>         struct evsel *evsel, *n;
> >> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> >> index 4062f5aebfc1..1bde9ccf4e7d 100644
> >> --- a/tools/perf/util/evlist.h
> >> +++ b/tools/perf/util/evlist.h
> >> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
> >>  struct evsel *arch_evlist__leader(struct list_head *list);
> >>
> >>  int evlist__add_dummy(struct evlist *evlist);
> >> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
> >> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
> >
> > Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
> >
> > empty == dummy == any CPU
> > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
> >
> > Given every CPU map should be empty or contain any CPU then it seems
> > they all meet the definition of empty - so something is wrong.
>
> Nothing is wrong.  I am not against clarifying things, but stop assuming
> natural language has to mean anything exactly.  That is what computer
> languages are for.
>
> Sometimes more abstract language is used, precisely to stop people
> making assumptions about the details.
>
> >
> > The cpu map here is explicitly opened so that it gets all online CPUs:
> > https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
> >
> > From:
> > https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
> > there are example topologies like:
> > kernel_max: 31
> >    offline: 2,4-31,32-63
> >     online: 0-1,3
> >   possible: 0-31
> >    present: 0-31
> >
> > all_cpus could mean the union of offline and online CPUs, possible
> > CPUs or present CPUs. You are saying that in the perf code all_cpus
> > should be the same as all online cpus as only those CPUs are valid
> > with perf_event_open. That's true but offline CPUs can be made online.
> > If that happens here then the dummy events will have a CPU map that
> > rather than being for all CPUs will be for all online CPUs at the
> > point it was opened. Having online in the function name I think
> > captures the time dependent nature of this - but if you think that's
> > too much could we add a comment?
>
> If you ask me it does the exact opposite.  The function of the code
> is to put the event on all CPUS without having to know the details
> of: well actually perf doesn't automagically retain or restore events
> across enabling or disabling CPUs so in fact we deal only in online
> CPUs.

But 'any CPU' (-1) could map to an offline CPU brought online. Calling
this function twice could also result in this behavior. Via the
topology documentation we have language to describe exactly the
scenario that's happening and I'd prefer not to muddy that by making
all and online synonyms.

> > too much could we add a comment? I'm trying to avoid a situation, like
> > with the CPU map code, where all and online are interchangeable
> > leading to the code being unnecessarily confusing unless you read
> > every line.
>
> It is normal to have to read the details of code, and, in my
> experience at least, normal for the code not to work exactly the
> way I'd imagined.

:-) The problem is that we all need to work with abstractions at some
point, abstraction is pretty much the whole point of computer science.
We need to fix CPU maps empty function, it is just a fundamental level
of contradiction. As with the CPU map index being often mistaken for
the CPU leading to bugs and crashes, I suspect remedying empty will
fix existing and future bugs. With function naming the point is to be
short and succinct, but also to be intention revealing for the sake of
abstraction. Yes you need to read the code, but as with CPU map empty
even that isn't enough and trying to infer behavior from usage can be
a long and painful process.

Thanks,
Ian

> >
> > Thanks,
> > Ian
> >
> >> +{
> >> +       return evlist__add_aux_dummy(evlist, true);
> >> +}
> >>
> >>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
> >>                          evsel__sb_cb_t cb, void *data);
> >> --
> >> 2.25.1
> >>
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread()
  2022-05-06 12:25 ` [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread() Adrian Hunter
@ 2022-05-06 17:06   ` Ian Rogers
  2022-05-10 17:19   ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 17:06 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Add perf_evsel__enable_thread() as a counterpart to
> perf_evsel__enable_cpu(), to enable all events for a thread.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/lib/perf/evsel.c              | 15 +++++++++++++++
>  tools/lib/perf/include/perf/evsel.h |  1 +
>  2 files changed, 16 insertions(+)
>
> diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
> index 20ae9f5f8b30..c1d58673f6ef 100644
> --- a/tools/lib/perf/evsel.c
> +++ b/tools/lib/perf/evsel.c
> @@ -360,6 +360,21 @@ int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
>         return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
>  }
>
> +int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
> +{
> +       struct perf_cpu cpu __maybe_unused;
> +       int idx;
> +       int err;
> +
> +       perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
> +               err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return 0;
> +}
> +
>  int perf_evsel__enable(struct perf_evsel *evsel)
>  {
>         int i;
> diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
> index 2a9516b42d15..699c0ed97d34 100644
> --- a/tools/lib/perf/include/perf/evsel.h
> +++ b/tools/lib/perf/include/perf/evsel.h
> @@ -36,6 +36,7 @@ LIBPERF_API int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int
>                                  struct perf_counts_values *count);
>  LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
> +LIBPERF_API int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread);
>  LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
>  LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params
  2022-05-06 12:25 ` [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params Adrian Hunter
@ 2022-05-06 20:16   ` Ian Rogers
  2022-05-11  7:02     ` Adrian Hunter
  2022-05-11  7:01   ` [PATCH V3 " Adrian Hunter
  1 sibling, 1 reply; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 20:16 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Add mmap_needed to auxtrace_mmap_params.
>
> Currently an auxtrace mmap is always attempted even if the event is not an
> auxtrace event. That works because, when AUX area tracing, there is always
> an auxtrace event first for every mmap. Prepare for that not being the
> case, which it won't be when sideband tracking events are allowed on
> all CPUs even when auxtrace is limited to selected CPUs.

Should there be a later patch to remove this option and just not do
the auxtrace mmap when it's not necessary?

> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/util/auxtrace.c | 10 ++++++++--
>  tools/perf/util/auxtrace.h |  8 ++++++--
>  tools/perf/util/evlist.c   |  5 +++--
>  tools/perf/util/mmap.c     |  1 +
>  4 files changed, 18 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index b11549ae39df..b446cfa66469 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -125,7 +125,7 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
>         mm->tid = mp->tid;
>         mm->cpu = mp->cpu.cpu;
>
> -       if (!mp->len) {
> +       if (!mp->len || !mp->mmap_needed) {
>                 mm->base = NULL;
>                 return 0;
>         }
> @@ -168,9 +168,15 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>  }
>
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
> -                                  struct evlist *evlist, int idx,
> +                                  struct evlist *evlist,
> +                                  struct evsel *evsel, int idx,
>                                    bool per_cpu)
>  {
> +       mp->mmap_needed = evsel->needs_auxtrace_mmap;
> +
> +       if (!mp->mmap_needed)
> +               return;
> +
>         mp->idx = idx;
>
>         if (per_cpu) {
> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> index dc38b6f57232..37feae003904 100644
> --- a/tools/perf/util/auxtrace.h
> +++ b/tools/perf/util/auxtrace.h
> @@ -344,6 +344,7 @@ struct auxtrace_mmap {
>   * @idx: index of this mmap
>   * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
>   *       mmap) otherwise %0
> + * @mmap_needed: set to %false for non-auxtrace events

Could you add something like:
(ie. we don't want the mmap but we do want the side effects of ...

Thanks,
Ian

>   * @cpu: cpu number for a per-cpu mmap otherwise %-1
>   */
>  struct auxtrace_mmap_params {
> @@ -353,6 +354,7 @@ struct auxtrace_mmap_params {
>         int             prot;
>         int             idx;
>         pid_t           tid;
> +       bool            mmap_needed;
>         struct perf_cpu cpu;
>  };
>
> @@ -490,7 +492,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>                                 unsigned int auxtrace_pages,
>                                 bool auxtrace_overwrite);
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
> -                                  struct evlist *evlist, int idx,
> +                                  struct evlist *evlist,
> +                                  struct evsel *evsel, int idx,
>                                    bool per_cpu);
>
>  typedef int (*process_auxtrace_t)(struct perf_tool *tool,
> @@ -863,7 +866,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>                                 unsigned int auxtrace_pages,
>                                 bool auxtrace_overwrite);
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
> -                                  struct evlist *evlist, int idx,
> +                                  struct evlist *evlist,
> +                                  struct evsel *evsel, int idx,
>                                    bool per_cpu);
>
>  #define ITRACE_HELP ""
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 7ae56b062f44..996bdc203616 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -747,15 +747,16 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
>
>  static void
>  perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
> -                        struct perf_evsel *_evsel __maybe_unused,
> +                        struct perf_evsel *_evsel,
>                          struct perf_mmap_param *_mp,
>                          int idx)
>  {
>         struct evlist *evlist = container_of(_evlist, struct evlist, core);
>         struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
>         bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
> +       struct evsel *evsel = container_of(_evsel, struct evsel, core);
>
> -       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
> +       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
>  }
>
>  static struct perf_mmap*
> diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
> index 50502b4a7ca4..de59c4da852b 100644
> --- a/tools/perf/util/mmap.c
> +++ b/tools/perf/util/mmap.c
> @@ -62,6 +62,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
>
>  void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
>                                           struct evlist *evlist __maybe_unused,
> +                                         struct evsel *evsel __maybe_unused,
>                                           int idx __maybe_unused,
>                                           bool per_cpu __maybe_unused)
>  {
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter
  2022-05-06 12:25 ` [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter Adrian Hunter
@ 2022-05-06 20:19   ` Ian Rogers
  0 siblings, 0 replies; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 20:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Remove auxtrace_mmap_params__set_idx() per_cpu parameter because it isn't
> needed.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/auxtrace.c | 5 +++--
>  tools/perf/util/auxtrace.h | 6 ++----
>  tools/perf/util/evlist.c   | 3 +--
>  tools/perf/util/mmap.c     | 3 +--
>  4 files changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index b446cfa66469..ac4e4660932d 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -169,9 +169,10 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>                                    struct evlist *evlist,
> -                                  struct evsel *evsel, int idx,
> -                                  bool per_cpu)
> +                                  struct evsel *evsel, int idx)
>  {
> +       bool per_cpu = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
> +
>         mp->mmap_needed = evsel->needs_auxtrace_mmap;
>
>         if (!mp->mmap_needed)
> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> index 37feae003904..87a3b564a7de 100644
> --- a/tools/perf/util/auxtrace.h
> +++ b/tools/perf/util/auxtrace.h
> @@ -493,8 +493,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>                                 bool auxtrace_overwrite);
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>                                    struct evlist *evlist,
> -                                  struct evsel *evsel, int idx,
> -                                  bool per_cpu);
> +                                  struct evsel *evsel, int idx);
>
>  typedef int (*process_auxtrace_t)(struct perf_tool *tool,
>                                   struct mmap *map,
> @@ -867,8 +866,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>                                 bool auxtrace_overwrite);
>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>                                    struct evlist *evlist,
> -                                  struct evsel *evsel, int idx,
> -                                  bool per_cpu);
> +                                  struct evsel *evsel, int idx);
>
>  #define ITRACE_HELP ""
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 996bdc203616..25eae096bdac 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -753,10 +753,9 @@ perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
>  {
>         struct evlist *evlist = container_of(_evlist, struct evlist, core);
>         struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
> -       bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
>         struct evsel *evsel = container_of(_evsel, struct evsel, core);
>
> -       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
> +       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx);
>  }
>
>  static struct perf_mmap*
> diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
> index de59c4da852b..a4dff881be39 100644
> --- a/tools/perf/util/mmap.c
> +++ b/tools/perf/util/mmap.c
> @@ -63,8 +63,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
>  void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
>                                           struct evlist *evlist __maybe_unused,
>                                           struct evsel *evsel __maybe_unused,
> -                                         int idx __maybe_unused,
> -                                         bool per_cpu __maybe_unused)
> +                                         int idx __maybe_unused)
>  {
>  }
>
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct
  2022-05-06 12:25 ` [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct Adrian Hunter
@ 2022-05-06 20:20   ` Ian Rogers
  0 siblings, 0 replies; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 20:20 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Print an error message if the predetermined number of mmaps is
> incorrect.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Acked-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/lib/perf/evlist.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> index eae1f6179dad..f51fdb899d19 100644
> --- a/tools/lib/perf/evlist.c
> +++ b/tools/lib/perf/evlist.c
> @@ -23,6 +23,7 @@
>  #include <perf/cpumap.h>
>  #include <perf/threadmap.h>
>  #include <api/fd/array.h>
> +#include "internal.h"
>
>  void perf_evlist__init(struct perf_evlist *evlist)
>  {
> @@ -428,7 +429,7 @@ static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_
>  static int
>  mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>                int idx, struct perf_mmap_param *mp, int cpu_idx,
> -              int thread, int *_output, int *_output_overwrite)
> +              int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
>  {
>         struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->all_cpus, cpu_idx);
>         struct perf_evsel *evsel;
> @@ -484,6 +485,8 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>                         if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
>                                 return -1;
>
> +                       *nr_mmaps += 1;
> +
>                         if (!idx)
>                                 perf_evlist__set_mmap_first(evlist, map, overwrite);
>                 } else {
> @@ -518,6 +521,7 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  {
>         int nr_threads = perf_thread_map__nr(evlist->threads);
>         int nr_cpus    = perf_cpu_map__nr(evlist->all_cpus);
> +       int nr_mmaps = 0;
>         int cpu, thread;
>
>         for (cpu = 0; cpu < nr_cpus; cpu++) {
> @@ -526,11 +530,14 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>
>                 for (thread = 0; thread < nr_threads; thread++) {
>                         if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
> -                                          thread, &output, &output_overwrite))
> +                                          thread, &output, &output_overwrite, &nr_mmaps))
>                                 goto out_unmap;
>                 }
>         }
>
> +       if (nr_mmaps != evlist->nr_mmaps)
> +               pr_err("Miscounted nr_mmaps %d vs %d\n", nr_mmaps, evlist->nr_mmaps);
> +
>         return 0;
>
>  out_unmap:
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 21/23] libperf evsel: Add comments for booleans
  2022-05-06 12:25 ` [PATCH V2 21/23] libperf evsel: Add comments for booleans Adrian Hunter
@ 2022-05-06 20:51   ` Ian Rogers
  2022-05-11  7:03     ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Ian Rogers @ 2022-05-06 20:51 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Add comments for 'system_wide' and 'requires_cpu' booleans
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/lib/perf/include/internal/evsel.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
> index 77fbb8b97e5c..cc8f1ba790bd 100644
> --- a/tools/lib/perf/include/internal/evsel.h
> +++ b/tools/lib/perf/include/internal/evsel.h
> @@ -49,7 +49,16 @@ struct perf_evsel {
>
>         /* parse modifier helper */
>         int                      nr_members;
> +       /*
> +        * system_wide is for events that need to be on every CPU, irrespective
> +        * of user requested CPUs or threads. Map propagation will not override
> +        * this events own_cpus, which will contribute to evlist all_cpus.

So this muddies my understanding of cpus and own_cpus (sigh, again
undocumented). I believe cpus to be the set of CPUs (or any CPU, aka
dummy) that perf_event_open happens on. all_cpus in evlist is the
union of all the evsels cpus (ie not related to own_cpus as described
here). Own_cpus I believe to be what's computed at parse-event time
from sysfs. Is this a typo in the comment or quite likely my error?

Thanks,
Ian

> +        */
>         bool                     system_wide;
> +       /*
> +        * Some events, for example uncore events, require a CPU.
> +        * i.e. it cannot be the 'any CPU' value of -1.
> +        */
>         bool                     requires_cpu;
>         int                      idx;
>  };
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu
  2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
                   ` (22 preceding siblings ...)
  2022-05-06 12:26 ` [PATCH V2 23/23] perf tools: Allow system-wide events to keep their own threads Adrian Hunter
@ 2022-05-08 15:08 ` Leo Yan
  2022-05-09  5:44   ` Adrian Hunter
  23 siblings, 1 reply; 70+ messages in thread
From: Leo Yan @ 2022-05-08 15:08 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Namhyung Kim, linux-kernel, James Clark,
	German Gomez

Hi Adrian,

On Fri, May 06, 2022 at 03:25:38PM +0300, Adrian Hunter wrote:
> Hi
> 
> Here are V2 patches to support capturing Intel PT sideband events such as
> mmap, task, context switch, text poke etc, on every CPU even when tracing
> selected user_requested_cpus.  That is, when using the perf record -C or
>  --cpu option.
> 
> This is needed for:
> 1. text poke: a text poke on any CPU affects all CPUs
> 2. tracing user space: a user space process can migrate between CPUs so
> mmap events that happen on a different CPU can be needed to decode a
> user_requested_cpus CPU.
> 
> For example:
> 
> 	Trace on CPU 1:
> 
> 	perf record --kcore -C 1 -e intel_pt// &
> 
> 	Start a task on CPU 0:
> 
> 	taskset 0x1 testprog &
> 
> 	Migrate it to CPU 1:
> 
> 	taskset -p 0x2 <testprog pid>
> 
> 	Stop tracing:
> 
> 	kill %1
> 
> 	Prior to these changes there will be errors decoding testprog
> 	in userspace because the comm and mmap events for testprog will not
> 	have been captured.

Thanks a lot for this patch set, I believe this is a common issue for
AUX trace (not only for Intel-PT), so I verified this patch set for both
Arm CoreSight and SPE; unfortunately both cannot see MMAP events for
migrated task.  I used below commands:

  # perf record -B -N --no-bpf-event -e cs_etm//u -C 0 -- taskset --cpu-list 1 uname
  # perf script  --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
  0


  # perf record -B -N --no-bpf-event -e arm_spe_0//u -C 0 -- taskset --cpu-list 1 uname
  # perf script --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
  0

I didn't dive into details for this patch set, so I cannot say the
failure is caused by any issue in this patch set.  But it's definitely
we need to look into for Arm platforms to root cause what's the reason
it cannot record MMAP events properly when migrate tasks.  Loop James
and German for this reason.

Thanks,
Leo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu
  2022-05-08 15:08 ` [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Leo Yan
@ 2022-05-09  5:44   ` Adrian Hunter
  2022-05-09  8:46     ` Leo Yan
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-09  5:44 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Namhyung Kim, linux-kernel, James Clark,
	German Gomez

On 8/05/22 18:08, Leo Yan wrote:
> Hi Adrian,
> 
> On Fri, May 06, 2022 at 03:25:38PM +0300, Adrian Hunter wrote:
>> Hi
>>
>> Here are V2 patches to support capturing Intel PT sideband events such as
>> mmap, task, context switch, text poke etc, on every CPU even when tracing
>> selected user_requested_cpus.  That is, when using the perf record -C or
>>  --cpu option.
>>
>> This is needed for:
>> 1. text poke: a text poke on any CPU affects all CPUs
>> 2. tracing user space: a user space process can migrate between CPUs so
>> mmap events that happen on a different CPU can be needed to decode a
>> user_requested_cpus CPU.
>>
>> For example:
>>
>> 	Trace on CPU 1:
>>
>> 	perf record --kcore -C 1 -e intel_pt// &
>>
>> 	Start a task on CPU 0:
>>
>> 	taskset 0x1 testprog &
>>
>> 	Migrate it to CPU 1:
>>
>> 	taskset -p 0x2 <testprog pid>
>>
>> 	Stop tracing:
>>
>> 	kill %1
>>
>> 	Prior to these changes there will be errors decoding testprog
>> 	in userspace because the comm and mmap events for testprog will not
>> 	have been captured.
> 
> Thanks a lot for this patch set, I believe this is a common issue for
> AUX trace (not only for Intel-PT), so I verified this patch set for both
> Arm CoreSight and SPE; unfortunately both cannot see MMAP events for
> migrated task.  I used below commands:
> 
>   # perf record -B -N --no-bpf-event -e cs_etm//u -C 0 -- taskset --cpu-list 1 uname
>   # perf script  --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
>   0
> 
> 
>   # perf record -B -N --no-bpf-event -e arm_spe_0//u -C 0 -- taskset --cpu-list 1 uname
>   # perf script --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
>   0
> 
> I didn't dive into details for this patch set, so I cannot say the
> failure is caused by any issue in this patch set.  But it's definitely
> we need to look into for Arm platforms to root cause what's the reason
> it cannot record MMAP events properly when migrate tasks.  Loop James
> and German for this reason.

You would need the equivalent of patch "perf intel-pt: Track sideband
system-wide when needed" which makes use of new helper
evlist__add_aux_dummy() to set up the dummy event with the option to
make it "system wide".

cs_etm_recording_options() and arm_spe_recording_options() have similar
code.

You will need to decide if it is worth the extra sideband.  I decided
if it became an issue, it could be made optional in the future.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu
  2022-05-09  5:44   ` Adrian Hunter
@ 2022-05-09  8:46     ` Leo Yan
  0 siblings, 0 replies; 70+ messages in thread
From: Leo Yan @ 2022-05-09  8:46 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Namhyung Kim, linux-kernel, James Clark,
	German Gomez

On Mon, May 09, 2022 at 08:44:02AM +0300, Adrian Hunter wrote:

[...]

> > Thanks a lot for this patch set, I believe this is a common issue for
> > AUX trace (not only for Intel-PT), so I verified this patch set for both
> > Arm CoreSight and SPE; unfortunately both cannot see MMAP events for
> > migrated task.  I used below commands:
> > 
> >   # perf record -B -N --no-bpf-event -e cs_etm//u -C 0 -- taskset --cpu-list 1 uname
> >   # perf script  --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
> >   0
> > 
> > 
> >   # perf record -B -N --no-bpf-event -e arm_spe_0//u -C 0 -- taskset --cpu-list 1 uname
> >   # perf script --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
> >   0
> > 
> > I didn't dive into details for this patch set, so I cannot say the
> > failure is caused by any issue in this patch set.  But it's definitely
> > we need to look into for Arm platforms to root cause what's the reason
> > it cannot record MMAP events properly when migrate tasks.  Loop James
> > and German for this reason.
> 
> You would need the equivalent of patch "perf intel-pt: Track sideband
> system-wide when needed" which makes use of new helper
> evlist__add_aux_dummy() to set up the dummy event with the option to
> make it "system wide".
> 
> cs_etm_recording_options() and arm_spe_recording_options() have similar
> code.

Thanks a lot for the guidance.

I applied the simliar change for cs_etm_recording_options() and
arm_spe_recording_options(), both can pass below tests:

  # perf record -B -N --no-bpf-event -e cs_etm//u -C 0 -- taskset --cpu-list 1 uname
  # perf script  --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l
  4

  # perf record -B -N --no-bpf-event -e arm_spe_0//u -C 0 -- taskset --cpu-list 1 uname
  # perf script --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l      
  4

And I tested a more complex case for migrating a test program 'sysbench'
in the middle of perf session, it still fails to parse any samples
testing program 'sysbench'.  I need to do more homework for this part,
but welcome any suggestions, thanks!  The testing script is:

---8<---

export PATH=/mnt/export/arm-linux-kernel/tools/perf/:$PATH

perf record --kcore -C 1 -e cs_etm// &
PERF_PID=$!
echo "Perf PID ${PERF_PID}"

sleep 2

taskset 0x1 ./sysbench --test=memory --max-requests=1000000000 run &
TEST_PROG_PID=$!
echo "Test Prog PID ${TEST_PROG_PID}"

sleep 1

taskset -p 0x2 $TEST_PROG_PID

sleep 1

kill $PERF_PID

> You will need to decide if it is worth the extra sideband.  I decided
> if it became an issue, it could be made optional in the future.

Yeah, the condition checking for system wide tracking in patch 16/23
looks good to me.

Thanks,
Leo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 15:35       ` Ian Rogers
@ 2022-05-10 14:55         ` Adrian Hunter
  2022-05-10 16:19           ` Ian Rogers
  2022-05-10 16:24           ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-10 14:55 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On 6/05/22 18:35, Ian Rogers wrote:
> On Fri, May 6, 2022 at 8:08 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 6/05/22 16:47, Ian Rogers wrote:
>>> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
>>>> event that sets up the system-wide maps before map propagation.
>>>>
>>>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
>>>> whether or not the event needs to be system-wide.
>>>>
>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>> ---
>>>>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
>>>>  tools/perf/util/evlist.h |  5 +++++
>>>>  2 files changed, 45 insertions(+)
>>>>
>>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>>>> index 78c47cbafbc2..c16bd4836314 100644
>>>> --- a/tools/perf/util/evlist.c
>>>> +++ b/tools/perf/util/evlist.c
>>>> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
>>>>         return 0;
>>>>  }
>>>>
>>>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
>>>> +{
>>>> +       evsel->core.system_wide = true;
>>>> +
>>>> +       /* All CPUs */
>>>> +       perf_cpu_map__put(evsel->core.own_cpus);
>>>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
>>>> +       perf_cpu_map__put(evsel->core.cpus);
>>>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
>>>> +
>>>> +       /* No threads */
>>>> +       perf_thread_map__put(evsel->core.threads);
>>>> +       evsel->core.threads = perf_thread_map__new_dummy();
>>>> +
>>>> +       evlist__add(evlist, evsel);
>>>> +}
>>>> +
>>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
>>>> +{
>>>> +       struct evsel *evsel = evlist__dummy_event(evlist);
>>>> +
>>>> +       if (!evsel)
>>>> +               return NULL;
>>>> +
>>>> +       evsel->core.attr.exclude_kernel = 1;
>>>> +       evsel->core.attr.exclude_guest = 1;
>>>> +       evsel->core.attr.exclude_hv = 1;
>>>> +       evsel->core.attr.freq = 0;
>>>> +       evsel->core.attr.sample_period = 1;
>>>> +       evsel->no_aux_samples = true;
>>>> +       evsel->name = strdup("dummy:u");
>>>> +
>>>> +       if (system_wide)
>>>> +               evlist__add_on_all_cpus(evlist, evsel);
>>>> +       else
>>>> +               evlist__add(evlist, evsel);
>>>> +
>>>> +       return evsel;
>>>> +}
>>>> +
>>>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>>>>  {
>>>>         struct evsel *evsel, *n;
>>>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
>>>> index 4062f5aebfc1..1bde9ccf4e7d 100644
>>>> --- a/tools/perf/util/evlist.h
>>>> +++ b/tools/perf/util/evlist.h
>>>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>>>>  struct evsel *arch_evlist__leader(struct list_head *list);
>>>>
>>>>  int evlist__add_dummy(struct evlist *evlist);
>>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
>>>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
>>>
>>> Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
>>>
>>> empty == dummy == any CPU
>>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
>>>
>>> Given every CPU map should be empty or contain any CPU then it seems
>>> they all meet the definition of empty - so something is wrong.
>>
>> Nothing is wrong.  I am not against clarifying things, but stop assuming
>> natural language has to mean anything exactly.  That is what computer
>> languages are for.
>>
>> Sometimes more abstract language is used, precisely to stop people
>> making assumptions about the details.
>>
>>>
>>> The cpu map here is explicitly opened so that it gets all online CPUs:
>>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
>>>
>>> From:
>>> https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
>>> there are example topologies like:
>>> kernel_max: 31
>>>    offline: 2,4-31,32-63
>>>     online: 0-1,3
>>>   possible: 0-31
>>>    present: 0-31
>>>
>>> all_cpus could mean the union of offline and online CPUs, possible
>>> CPUs or present CPUs. You are saying that in the perf code all_cpus
>>> should be the same as all online cpus as only those CPUs are valid
>>> with perf_event_open. That's true but offline CPUs can be made online.
>>> If that happens here then the dummy events will have a CPU map that
>>> rather than being for all CPUs will be for all online CPUs at the
>>> point it was opened. Having online in the function name I think
>>> captures the time dependent nature of this - but if you think that's
>>> too much could we add a comment?
>>
>> If you ask me it does the exact opposite.  The function of the code
>> is to put the event on all CPUS without having to know the details
>> of: well actually perf doesn't automagically retain or restore events
>> across enabling or disabling CPUs so in fact we deal only in online
>> CPUs.
> 
> But 'any CPU' (-1) could map to an offline CPU brought online. Calling
> this function twice could also result in this behavior. Via the
> topology documentation we have language to describe exactly the
> scenario that's happening and I'd prefer not to muddy that by making
> all and online synonyms.

In this case the caller wants all CPUs, not online CPUs.  The detail
that we can't trace offline CPUs that become online is not relevant
to the caller.  Why would the caller call a function limited to online
CPUs when that is not what the caller wants.

> 
>>> too much could we add a comment? I'm trying to avoid a situation, like
>>> with the CPU map code, where all and online are interchangeable
>>> leading to the code being unnecessarily confusing unless you read
>>> every line.
>>
>> It is normal to have to read the details of code, and, in my
>> experience at least, normal for the code not to work exactly the
>> way I'd imagined.
> 
> :-) The problem is that we all need to work with abstractions at some
> point, abstraction is pretty much the whole point of computer science.
> We need to fix CPU maps empty function, it is just a fundamental level
> of contradiction. As with the CPU map index being often mistaken for
> the CPU leading to bugs and crashes, I suspect remedying empty will
> fix existing and future bugs. With function naming the point is to be
> short and succinct, but also to be intention revealing for the sake of
> abstraction. Yes you need to read the code, but as with CPU map empty
> even that isn't enough and trying to infer behavior from usage can be
> a long and painful process.

You seem to be insisting that the function be named for its
implementation (i.e. offline CPUs are not supported) not its
purpose (trace system wide).

I can only suggest we go back to the original name, because the
function has *nothing* to do with whether or not perf supports
tracing per-cpu contexts on offline CPUs that become online.

> 
> Thanks,
> Ian
> 
>>>
>>> Thanks,
>>> Ian
>>>
>>>> +{
>>>> +       return evlist__add_aux_dummy(evlist, true);
>>>> +}
>>>>
>>>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>>>>                          evsel__sb_cb_t cb, void *data);
>>>> --
>>>> 2.25.1
>>>>
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-10 14:55         ` Adrian Hunter
@ 2022-05-10 16:19           ` Ian Rogers
  2022-05-10 16:24           ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 70+ messages in thread
From: Ian Rogers @ 2022-05-10 16:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Tue, May 10, 2022 at 7:55 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 6/05/22 18:35, Ian Rogers wrote:
> > On Fri, May 6, 2022 at 8:08 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> On 6/05/22 16:47, Ian Rogers wrote:
> >>> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>
> >>>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> >>>> event that sets up the system-wide maps before map propagation.
> >>>>
> >>>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> >>>> whether or not the event needs to be system-wide.
> >>>>
> >>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >>>> ---
> >>>>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
> >>>>  tools/perf/util/evlist.h |  5 +++++
> >>>>  2 files changed, 45 insertions(+)
> >>>>
> >>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >>>> index 78c47cbafbc2..c16bd4836314 100644
> >>>> --- a/tools/perf/util/evlist.c
> >>>> +++ b/tools/perf/util/evlist.c
> >>>> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
> >>>>         return 0;
> >>>>  }
> >>>>
> >>>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> >>>> +{
> >>>> +       evsel->core.system_wide = true;
> >>>> +
> >>>> +       /* All CPUs */
> >>>> +       perf_cpu_map__put(evsel->core.own_cpus);
> >>>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> >>>> +       perf_cpu_map__put(evsel->core.cpus);
> >>>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> >>>> +
> >>>> +       /* No threads */
> >>>> +       perf_thread_map__put(evsel->core.threads);
> >>>> +       evsel->core.threads = perf_thread_map__new_dummy();
> >>>> +
> >>>> +       evlist__add(evlist, evsel);
> >>>> +}
> >>>> +
> >>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
> >>>> +{
> >>>> +       struct evsel *evsel = evlist__dummy_event(evlist);
> >>>> +
> >>>> +       if (!evsel)
> >>>> +               return NULL;
> >>>> +
> >>>> +       evsel->core.attr.exclude_kernel = 1;
> >>>> +       evsel->core.attr.exclude_guest = 1;
> >>>> +       evsel->core.attr.exclude_hv = 1;
> >>>> +       evsel->core.attr.freq = 0;
> >>>> +       evsel->core.attr.sample_period = 1;
> >>>> +       evsel->no_aux_samples = true;
> >>>> +       evsel->name = strdup("dummy:u");
> >>>> +
> >>>> +       if (system_wide)
> >>>> +               evlist__add_on_all_cpus(evlist, evsel);
> >>>> +       else
> >>>> +               evlist__add(evlist, evsel);
> >>>> +
> >>>> +       return evsel;
> >>>> +}
> >>>> +
> >>>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
> >>>>  {
> >>>>         struct evsel *evsel, *n;
> >>>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> >>>> index 4062f5aebfc1..1bde9ccf4e7d 100644
> >>>> --- a/tools/perf/util/evlist.h
> >>>> +++ b/tools/perf/util/evlist.h
> >>>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
> >>>>  struct evsel *arch_evlist__leader(struct list_head *list);
> >>>>
> >>>>  int evlist__add_dummy(struct evlist *evlist);
> >>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
> >>>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
> >>>
> >>> Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
> >>>
> >>> empty == dummy == any CPU
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
> >>>
> >>> Given every CPU map should be empty or contain any CPU then it seems
> >>> they all meet the definition of empty - so something is wrong.
> >>
> >> Nothing is wrong.  I am not against clarifying things, but stop assuming
> >> natural language has to mean anything exactly.  That is what computer
> >> languages are for.
> >>
> >> Sometimes more abstract language is used, precisely to stop people
> >> making assumptions about the details.
> >>
> >>>
> >>> The cpu map here is explicitly opened so that it gets all online CPUs:
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
> >>>
> >>> From:
> >>> https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
> >>> there are example topologies like:
> >>> kernel_max: 31
> >>>    offline: 2,4-31,32-63
> >>>     online: 0-1,3
> >>>   possible: 0-31
> >>>    present: 0-31
> >>>
> >>> all_cpus could mean the union of offline and online CPUs, possible
> >>> CPUs or present CPUs. You are saying that in the perf code all_cpus
> >>> should be the same as all online cpus as only those CPUs are valid
> >>> with perf_event_open. That's true but offline CPUs can be made online.
> >>> If that happens here then the dummy events will have a CPU map that
> >>> rather than being for all CPUs will be for all online CPUs at the
> >>> point it was opened. Having online in the function name I think
> >>> captures the time dependent nature of this - but if you think that's
> >>> too much could we add a comment?
> >>
> >> If you ask me it does the exact opposite.  The function of the code
> >> is to put the event on all CPUS without having to know the details
> >> of: well actually perf doesn't automagically retain or restore events
> >> across enabling or disabling CPUs so in fact we deal only in online
> >> CPUs.
> >
> > But 'any CPU' (-1) could map to an offline CPU brought online. Calling
> > this function twice could also result in this behavior. Via the
> > topology documentation we have language to describe exactly the
> > scenario that's happening and I'd prefer not to muddy that by making
> > all and online synonyms.
>
> In this case the caller wants all CPUs, not online CPUs.  The detail
> that we can't trace offline CPUs that become online is not relevant
> to the caller.  Why would the caller call a function limited to online
> CPUs when that is not what the caller wants.
>
> >
> >>> too much could we add a comment? I'm trying to avoid a situation, like
> >>> with the CPU map code, where all and online are interchangeable
> >>> leading to the code being unnecessarily confusing unless you read
> >>> every line.
> >>
> >> It is normal to have to read the details of code, and, in my
> >> experience at least, normal for the code not to work exactly the
> >> way I'd imagined.
> >
> > :-) The problem is that we all need to work with abstractions at some
> > point, abstraction is pretty much the whole point of computer science.
> > We need to fix CPU maps empty function, it is just a fundamental level
> > of contradiction. As with the CPU map index being often mistaken for
> > the CPU leading to bugs and crashes, I suspect remedying empty will
> > fix existing and future bugs. With function naming the point is to be
> > short and succinct, but also to be intention revealing for the sake of
> > abstraction. Yes you need to read the code, but as with CPU map empty
> > even that isn't enough and trying to infer behavior from usage can be
> > a long and painful process.
>
> You seem to be insisting that the function be named for its
> implementation (i.e. offline CPUs are not supported) not its
> purpose (trace system wide).
>
> I can only suggest we go back to the original name, because the
> function has *nothing* to do with whether or not perf supports
> tracing per-cpu contexts on offline CPUs that become online.

Hi Adrian,

Do you understand my concern for 'all' and 'online' not being synonyms
for each other? When I read 'all' I assume online + offline, this
function is explicitly just online and it didn't seem like a big ask
to have that in the function name. My hope is to have intention
revealing function names rather than to have to plod through code when
things don't work as intended. In any case, I already said that a
comment will suffice that in this context 'all' == 'online'. I'm keen
to land this patch series as we clearly need to fix what is meant by
'empty' that is true for:
truly empty: {}
dummy/any: {-1}
dummy/any merged: {-1,0,1,2,3}
ie empty can mean any CPU, actual CPUs or none. I know I'm adopting
the role of language lawyer in doing this but honestly we need this
fixed, and my hope is with tests on it.

Thanks,
Ian

> >
> > Thanks,
> > Ian
> >
> >>>
> >>> Thanks,
> >>> Ian
> >>>
> >>>> +{
> >>>> +       return evlist__add_aux_dummy(evlist, true);
> >>>> +}
> >>>>
> >>>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
> >>>>                          evsel__sb_cb_t cb, void *data);
> >>>> --
> >>>> 2.25.1
> >>>>
> >>
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-10 14:55         ` Adrian Hunter
  2022-05-10 16:19           ` Ian Rogers
@ 2022-05-10 16:24           ` Arnaldo Carvalho de Melo
  2022-05-10 17:32             ` Adrian Hunter
  1 sibling, 1 reply; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 16:24 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Ian Rogers, Jiri Olsa, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Tue, May 10, 2022 at 05:55:34PM +0300, Adrian Hunter escreveu:
> On 6/05/22 18:35, Ian Rogers wrote:
> > On Fri, May 6, 2022 at 8:08 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> On 6/05/22 16:47, Ian Rogers wrote:
> >>> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>
> >>>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> >>>> event that sets up the system-wide maps before map propagation.
> >>>>
> >>>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> >>>> whether or not the event needs to be system-wide.
> >>>>
> >>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >>>> ---
> >>>>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
> >>>>  tools/perf/util/evlist.h |  5 +++++
> >>>>  2 files changed, 45 insertions(+)
> >>>>
> >>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >>>> index 78c47cbafbc2..c16bd4836314 100644
> >>>> --- a/tools/perf/util/evlist.c
> >>>> +++ b/tools/perf/util/evlist.c
> >>>> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
> >>>>         return 0;
> >>>>  }
> >>>>
> >>>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> >>>> +{
> >>>> +       evsel->core.system_wide = true;
> >>>> +
> >>>> +       /* All CPUs */
> >>>> +       perf_cpu_map__put(evsel->core.own_cpus);
> >>>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> >>>> +       perf_cpu_map__put(evsel->core.cpus);
> >>>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> >>>> +
> >>>> +       /* No threads */
> >>>> +       perf_thread_map__put(evsel->core.threads);
> >>>> +       evsel->core.threads = perf_thread_map__new_dummy();
> >>>> +
> >>>> +       evlist__add(evlist, evsel);
> >>>> +}
> >>>> +
> >>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
> >>>> +{
> >>>> +       struct evsel *evsel = evlist__dummy_event(evlist);
> >>>> +
> >>>> +       if (!evsel)
> >>>> +               return NULL;
> >>>> +
> >>>> +       evsel->core.attr.exclude_kernel = 1;
> >>>> +       evsel->core.attr.exclude_guest = 1;
> >>>> +       evsel->core.attr.exclude_hv = 1;
> >>>> +       evsel->core.attr.freq = 0;
> >>>> +       evsel->core.attr.sample_period = 1;
> >>>> +       evsel->no_aux_samples = true;
> >>>> +       evsel->name = strdup("dummy:u");
> >>>> +
> >>>> +       if (system_wide)
> >>>> +               evlist__add_on_all_cpus(evlist, evsel);
> >>>> +       else
> >>>> +               evlist__add(evlist, evsel);
> >>>> +
> >>>> +       return evsel;
> >>>> +}
> >>>> +
> >>>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
> >>>>  {
> >>>>         struct evsel *evsel, *n;
> >>>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> >>>> index 4062f5aebfc1..1bde9ccf4e7d 100644
> >>>> --- a/tools/perf/util/evlist.h
> >>>> +++ b/tools/perf/util/evlist.h
> >>>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
> >>>>  struct evsel *arch_evlist__leader(struct list_head *list);
> >>>>
> >>>>  int evlist__add_dummy(struct evlist *evlist);
> >>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
> >>>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
> >>>
> >>> Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
> >>>
> >>> empty == dummy == any CPU
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
> >>>
> >>> Given every CPU map should be empty or contain any CPU then it seems
> >>> they all meet the definition of empty - so something is wrong.
> >>
> >> Nothing is wrong.  I am not against clarifying things, but stop assuming
> >> natural language has to mean anything exactly.  That is what computer
> >> languages are for.
> >>
> >> Sometimes more abstract language is used, precisely to stop people
> >> making assumptions about the details.
> >>
> >>>
> >>> The cpu map here is explicitly opened so that it gets all online CPUs:
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
> >>>
> >>> From:
> >>> https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
> >>> there are example topologies like:
> >>> kernel_max: 31
> >>>    offline: 2,4-31,32-63
> >>>     online: 0-1,3
> >>>   possible: 0-31
> >>>    present: 0-31
> >>>
> >>> all_cpus could mean the union of offline and online CPUs, possible
> >>> CPUs or present CPUs. You are saying that in the perf code all_cpus
> >>> should be the same as all online cpus as only those CPUs are valid
> >>> with perf_event_open. That's true but offline CPUs can be made online.
> >>> If that happens here then the dummy events will have a CPU map that
> >>> rather than being for all CPUs will be for all online CPUs at the
> >>> point it was opened. Having online in the function name I think
> >>> captures the time dependent nature of this - but if you think that's
> >>> too much could we add a comment?
> >>
> >> If you ask me it does the exact opposite.  The function of the code
> >> is to put the event on all CPUS without having to know the details
> >> of: well actually perf doesn't automagically retain or restore events
> >> across enabling or disabling CPUs so in fact we deal only in online
> >> CPUs.
> > 
> > But 'any CPU' (-1) could map to an offline CPU brought online. Calling
> > this function twice could also result in this behavior. Via the
> > topology documentation we have language to describe exactly the
> > scenario that's happening and I'd prefer not to muddy that by making
> > all and online synonyms.
> 
> In this case the caller wants all CPUs, not online CPUs.  The detail
> that we can't trace offline CPUs that become online is not relevant
> to the caller.  Why would the caller call a function limited to online
> CPUs when that is not what the caller wants.

Agreed, the intention is for all CPUs to be traced, so all that can be
traced should be traced, at the time of the call to this function.

An improvement, that would change the workings of this function, but
that would still do what was asked, would be to have functionality that
remembers such requestgs for tracing all CPUs and when a CPU that was
offline is brought online, gets that CPU added to whoever asked for all
CPUs to be traced.

If this is something critical to the caller, then perhaps it should
provide a callback for when CPUs are made online (or offline).

But then we can add that functionality when the need arises?

- Arnaldo
 
> >>> too much could we add a comment? I'm trying to avoid a situation, like
> >>> with the CPU map code, where all and online are interchangeable
> >>> leading to the code being unnecessarily confusing unless you read
> >>> every line.
> >>
> >> It is normal to have to read the details of code, and, in my
> >> experience at least, normal for the code not to work exactly the
> >> way I'd imagined.
> > 
> > :-) The problem is that we all need to work with abstractions at some
> > point, abstraction is pretty much the whole point of computer science.
> > We need to fix CPU maps empty function, it is just a fundamental level
> > of contradiction. As with the CPU map index being often mistaken for
> > the CPU leading to bugs and crashes, I suspect remedying empty will
> > fix existing and future bugs. With function naming the point is to be
> > short and succinct, but also to be intention revealing for the sake of
> > abstraction. Yes you need to read the code, but as with CPU map empty
> > even that isn't enough and trying to infer behavior from usage can be
> > a long and painful process.
> 
> You seem to be insisting that the function be named for its
> implementation (i.e. offline CPUs are not supported) not its
> purpose (trace system wide).
> 
> I can only suggest we go back to the original name, because the
> function has *nothing* to do with whether or not perf supports
> tracing per-cpu contexts on offline CPUs that become online.
> 
> > 
> > Thanks,
> > Ian
> > 
> >>>
> >>> Thanks,
> >>> Ian
> >>>
> >>>> +{
> >>>> +       return evlist__add_aux_dummy(evlist, true);
> >>>> +}
> >>>>
> >>>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
> >>>>                          evsel__sb_cb_t cb, void *data);
> >>>> --
> >>>> 2.25.1
> >>>>
> >>

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band
  2022-05-06 12:25 ` [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band Adrian Hunter
@ 2022-05-10 17:18   ` Arnaldo Carvalho de Melo
  2022-05-10 17:21     ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:18 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:39PM +0300, Adrian Hunter escreveu:
> Add a test for system-wide side band even when tracing selected CPUs.
> 
> Tested-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>


[root@quaco ~]# uname -a
Linux quaco 5.16.13-200.fc35.x86_64 #1 SMP PREEMPT Tue Mar 8 22:50:58 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
[root@quaco ~]# grep -m1 -i "model name" /proc/cpuinfo 
model name	: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
[root@quaco ~]# perf test -v Misc
 97: Miscellaneous Intel PT testing                                  :
--- start ---
test child forked, pid 769475
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.352 MB /tmp/tmp.Ty4Rqnz4vz ]
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.352 MB /tmp/tmp.Ty4Rqnz4vz ]
Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.446 MB /tmp/tmp.TnEqenwzZv ]
Failed to record MMAP events on CPU 1 when tracing CPU 0
test child finished with -1
---- end ----
Miscellaneous Intel PT testing: FAILED!
[root@quaco ~]# 

Do I need some more recent machine or kernel?

- Arnaldo

> ---
>  tools/perf/tests/shell/test_intel_pt.sh | 71 +++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
>  create mode 100755 tools/perf/tests/shell/test_intel_pt.sh
> 
> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
> new file mode 100755
> index 000000000000..a3298643884d
> --- /dev/null
> +++ b/tools/perf/tests/shell/test_intel_pt.sh
> @@ -0,0 +1,71 @@
> +#!/bin/sh
> +# Miscellaneous Intel PT testing
> +# SPDX-License-Identifier: GPL-2.0
> +
> +set -e
> +
> +# Skip if no Intel PT
> +perf list | grep -q 'intel_pt//' || exit 2
> +
> +skip_cnt=0
> +ok_cnt=0
> +err_cnt=0
> +
> +tmpfile=`mktemp`
> +perfdatafile=`mktemp`
> +
> +can_cpu_wide()
> +{
> +	perf record -o ${tmpfile} -B -N --no-bpf-event -e dummy:u -C $1 true 2>&1 >/dev/null || return 2
> +	return 0
> +}
> +
> +test_system_wide_side_band()
> +{
> +	# Need CPU 0 and CPU 1
> +	can_cpu_wide 0 || return $?
> +	can_cpu_wide 1 || return $?
> +
> +	# Record on CPU 0 a task running on CPU 1
> +	perf record -B -N --no-bpf-event -o ${perfdatafile} -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
> +
> +	# Should get MMAP events from CPU 1 because they can be needed to decode
> +	mmap_cnt=`perf script -i ${perfdatafile} --no-itrace --show-mmap-events -C 1 2>/dev/null | grep MMAP | wc -l`
> +
> +	if [ ${mmap_cnt} -gt 0 ] ; then
> +		return 0
> +	fi
> +
> +	echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
> +	return 1
> +}
> +
> +count_result()
> +{
> +	if [ $1 -eq 2 ] ; then
> +		skip_cnt=`expr ${skip_cnt} \+ 1`
> +		return
> +	fi
> +	if [ $1 -eq 0 ] ; then
> +		ok_cnt=`expr ${ok_cnt} \+ 1`
> +		return
> +	fi
> +	err_cnt=`expr ${err_cnt} \+ 1`
> +}
> +
> +test_system_wide_side_band
> +
> +count_result $?
> +
> +rm -f ${tmpfile}
> +rm -f ${perfdatafile}
> +
> +if [ ${err_cnt} -gt 0 ] ; then
> +	exit 1
> +fi
> +
> +if [ ${ok_cnt} -gt 0 ] ; then
> +	exit 0
> +fi
> +
> +exit 2
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread()
  2022-05-06 12:25 ` [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread() Adrian Hunter
  2022-05-06 17:06   ` Ian Rogers
@ 2022-05-10 17:19   ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:40PM +0300, Adrian Hunter escreveu:
> Add perf_evsel__enable_thread() as a counterpart to
> perf_evsel__enable_cpu(), to enable all events for a thread.

Thanks, applied.

- Arnaldo

 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/lib/perf/evsel.c              | 15 +++++++++++++++
>  tools/lib/perf/include/perf/evsel.h |  1 +
>  2 files changed, 16 insertions(+)
> 
> diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
> index 20ae9f5f8b30..c1d58673f6ef 100644
> --- a/tools/lib/perf/evsel.c
> +++ b/tools/lib/perf/evsel.c
> @@ -360,6 +360,21 @@ int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
>  	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
>  }
>  
> +int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
> +{
> +	struct perf_cpu cpu __maybe_unused;
> +	int idx;
> +	int err;
> +
> +	perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
> +		err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
> +		if (err)
> +			return err;
> +	}
> +
> +	return 0;
> +}
> +
>  int perf_evsel__enable(struct perf_evsel *evsel)
>  {
>  	int i;
> diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
> index 2a9516b42d15..699c0ed97d34 100644
> --- a/tools/lib/perf/include/perf/evsel.h
> +++ b/tools/lib/perf/include/perf/evsel.h
> @@ -36,6 +36,7 @@ LIBPERF_API int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int
>  				 struct perf_counts_values *count);
>  LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
> +LIBPERF_API int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread);
>  LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
>  LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band
  2022-05-10 17:18   ` Arnaldo Carvalho de Melo
@ 2022-05-10 17:21     ` Adrian Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-10 17:21 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

On 10/05/22 20:18, Arnaldo Carvalho de Melo wrote:
> Em Fri, May 06, 2022 at 03:25:39PM +0300, Adrian Hunter escreveu:
>> Add a test for system-wide side band even when tracing selected CPUs.
>>
>> Tested-by: Ian Rogers <irogers@google.com>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> 
> 
> [root@quaco ~]# uname -a
> Linux quaco 5.16.13-200.fc35.x86_64 #1 SMP PREEMPT Tue Mar 8 22:50:58 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
> [root@quaco ~]# grep -m1 -i "model name" /proc/cpuinfo 
> model name	: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
> [root@quaco ~]# perf test -v Misc
>  97: Miscellaneous Intel PT testing                                  :
> --- start ---
> test child forked, pid 769475
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 1.352 MB /tmp/tmp.Ty4Rqnz4vz ]
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 1.352 MB /tmp/tmp.Ty4Rqnz4vz ]
> Linux
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 1.446 MB /tmp/tmp.TnEqenwzZv ]
> Failed to record MMAP events on CPU 1 when tracing CPU 0
> test child finished with -1
> ---- end ----
> Miscellaneous Intel PT testing: FAILED!
> [root@quaco ~]# 
> 
> Do I need some more recent machine or kernel?

I put it only in the cover letter sorry but "The first patch is a small Intel PT test for system-wide side band.  The
test fails before the patches are applied, passed afterwards."

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx()
  2022-05-06 12:25 ` [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx() Adrian Hunter
@ 2022-05-10 17:23   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:23 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:41PM +0300, Adrian Hunter escreveu:
> evlist__enable_event_idx() is used only for auxtrace events which are never
> system_wide. Simplify by using libperf enable event functions.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/perf/util/evlist.c | 44 ++--------------------------------------
>  1 file changed, 2 insertions(+), 42 deletions(-)
> 
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 52ea004ba01e..9fcecf7daa62 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -334,14 +334,6 @@ int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name,
>  	return 0;
>  }
>  
> -static int evlist__nr_threads(struct evlist *evlist, struct evsel *evsel)
> -{
> -	if (evsel->core.system_wide)
> -		return 1;
> -	else
> -		return perf_thread_map__nr(evlist->core.threads);
> -}
> -
>  struct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affinity *affinity)
>  {
>  	struct evlist_cpu_iterator itr = {
> @@ -546,46 +538,14 @@ void evlist__toggle_enable(struct evlist *evlist)
>  	(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
>  }
>  
> -static int evlist__enable_event_cpu(struct evlist *evlist, struct evsel *evsel, int cpu)
> -{
> -	int thread;
> -	int nr_threads = evlist__nr_threads(evlist, evsel);
> -
> -	if (!evsel->core.fd)
> -		return -EINVAL;
> -
> -	for (thread = 0; thread < nr_threads; thread++) {
> -		int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
> -		if (err)
> -			return err;
> -	}
> -	return 0;
> -}
> -
> -static int evlist__enable_event_thread(struct evlist *evlist, struct evsel *evsel, int thread)
> -{
> -	int cpu;
> -	int nr_cpus = perf_cpu_map__nr(evlist->core.user_requested_cpus);
> -
> -	if (!evsel->core.fd)
> -		return -EINVAL;
> -
> -	for (cpu = 0; cpu < nr_cpus; cpu++) {
> -		int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
> -		if (err)
> -			return err;
> -	}
> -	return 0;
> -}
> -
>  int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
>  {
>  	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
>  
>  	if (per_cpu_mmaps)
> -		return evlist__enable_event_cpu(evlist, evsel, idx);
> +		return perf_evsel__enable_cpu(&evsel->core, idx);
>  
> -	return evlist__enable_event_thread(evlist, evsel, idx);
> +	return perf_evsel__enable_thread(&evsel->core, idx);
>  }
>  
>  int evlist__add_pollfd(struct evlist *evlist, int fd)
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c
  2022-05-06 12:25 ` [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c Adrian Hunter
@ 2022-05-10 17:24   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:24 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:42PM +0300, Adrian Hunter escreveu:
> evlist__enable_event_idx() is used only by auxtrace. Move it to auxtrace.c
> in preparation for making it even more auxtrace specific.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/perf/util/auxtrace.c | 10 ++++++++++
>  tools/perf/util/evlist.c   | 10 ----------
>  tools/perf/util/evlist.h   |  2 --
>  3 files changed, 10 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index df1c5bbbaa0d..10936a38031f 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -636,6 +636,16 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
>  	return -EINVAL;
>  }
>  
> +static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
> +{
> +	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
> +
> +	if (per_cpu_mmaps)
> +		return perf_evsel__enable_cpu(&evsel->core, idx);
> +
> +	return perf_evsel__enable_thread(&evsel->core, idx);
> +}
> +
>  int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
>  {
>  	struct evsel *evsel;
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 9fcecf7daa62..f1309b39afe4 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -538,16 +538,6 @@ void evlist__toggle_enable(struct evlist *evlist)
>  	(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
>  }
>  
> -int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
> -{
> -	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
> -
> -	if (per_cpu_mmaps)
> -		return perf_evsel__enable_cpu(&evsel->core, idx);
> -
> -	return perf_evsel__enable_thread(&evsel->core, idx);
> -}
> -
>  int evlist__add_pollfd(struct evlist *evlist, int fd)
>  {
>  	return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, fdarray_flag__default);
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index a21daaa5fc1b..4062f5aebfc1 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -196,8 +196,6 @@ void evlist__toggle_enable(struct evlist *evlist);
>  void evlist__disable_evsel(struct evlist *evlist, char *evsel_name);
>  void evlist__enable_evsel(struct evlist *evlist, char *evsel_name);
>  
> -int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx);
> -
>  void evlist__set_selected(struct evlist *evlist, struct evsel *evsel);
>  
>  int evlist__create_maps(struct evlist *evlist, struct target *target);
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx
  2022-05-06 12:25 ` [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx Adrian Hunter
@ 2022-05-10 17:25   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:25 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:43PM +0300, Adrian Hunter escreveu:
> The idx is with respect to evlist not evsel. That hasn't mattered because
> they are the same at present. Prepare for that not being the case, which it
> won't be when sideband tracking events are allowed on all CPUs even when
> auxtrace is limited to selected CPUs.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/perf/util/auxtrace.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index 10936a38031f..b11549ae39df 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -640,8 +640,14 @@ static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel,
>  {
>  	bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
>  
> -	if (per_cpu_mmaps)
> -		return perf_evsel__enable_cpu(&evsel->core, idx);
> +	if (per_cpu_mmaps) {
> +		struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);
> +		int cpu_map_idx = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu);
> +
> +		if (cpu_map_idx == -1)
> +			return -EINVAL;
> +		return perf_evsel__enable_cpu(&evsel->core, cpu_map_idx);
> +	}
>  
>  	return perf_evsel__enable_thread(&evsel->core, idx);
>  }
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter
  2022-05-06 12:25 ` [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter Adrian Hunter
@ 2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:26 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:44PM +0300, Adrian Hunter escreveu:
> Remove ->idx() per_cpu parameter because it isn't needed.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/lib/perf/evlist.c                  | 4 ++--
>  tools/lib/perf/include/internal/evlist.h | 2 +-
>  tools/perf/util/evlist.c                 | 3 ++-
>  3 files changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> index 974b4585f93e..5e8ad854fa8a 100644
> --- a/tools/lib/perf/evlist.c
> +++ b/tools/lib/perf/evlist.c
> @@ -521,7 +521,7 @@ mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  		int output_overwrite = -1;
>  
>  		if (ops->idx)
> -			ops->idx(evlist, mp, thread, false);
> +			ops->idx(evlist, mp, thread);
>  
>  		if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread,
>  				   &output, &output_overwrite))
> @@ -548,7 +548,7 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  		int output_overwrite = -1;
>  
>  		if (ops->idx)
> -			ops->idx(evlist, mp, cpu, true);
> +			ops->idx(evlist, mp, cpu);
>  
>  		for (thread = 0; thread < nr_threads; thread++) {
>  			if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
> diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h
> index e3e64f37db7b..0d5c830431a7 100644
> --- a/tools/lib/perf/include/internal/evlist.h
> +++ b/tools/lib/perf/include/internal/evlist.h
> @@ -38,7 +38,7 @@ struct perf_evlist {
>  };
>  
>  typedef void
> -(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int, bool);
> +(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int);
>  typedef struct perf_mmap*
>  (*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int);
>  typedef int
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index f1309b39afe4..09a1d3400fd9 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -748,10 +748,11 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
>  static void
>  perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
>  			 struct perf_mmap_param *_mp,
> -			 int idx, bool per_cpu)
> +			 int idx)
>  {
>  	struct evlist *evlist = container_of(_evlist, struct evlist, core);
>  	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
> +	bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
>  
>  	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
>  }
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel()
  2022-05-06 12:25 ` [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel() Adrian Hunter
@ 2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:26 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:45PM +0300, Adrian Hunter escreveu:
> Move ->idx() into mmap_per_evsel() in preparation for adding evsel as a
> parameter.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/lib/perf/evlist.c | 9 +++------
>  1 file changed, 3 insertions(+), 6 deletions(-)
> 
> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> index 5e8ad854fa8a..4fce417432aa 100644
> --- a/tools/lib/perf/evlist.c
> +++ b/tools/lib/perf/evlist.c
> @@ -478,6 +478,9 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  			 */
>  			refcount_set(&map->refcnt, 2);
>  
> +			if (ops->idx)
> +				ops->idx(evlist, mp, idx);
> +
>  			if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
>  				return -1;
>  
> @@ -520,9 +523,6 @@ mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  		int output = -1;
>  		int output_overwrite = -1;
>  
> -		if (ops->idx)
> -			ops->idx(evlist, mp, thread);
> -
>  		if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread,
>  				   &output, &output_overwrite))
>  			goto out_unmap;
> @@ -547,9 +547,6 @@ mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  		int output = -1;
>  		int output_overwrite = -1;
>  
> -		if (ops->idx)
> -			ops->idx(evlist, mp, cpu);
> -
>  		for (thread = 0; thread < nr_threads; thread++) {
>  			if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
>  					   thread, &output, &output_overwrite))
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx()
  2022-05-06 12:25 ` [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx() Adrian Hunter
@ 2022-05-10 17:26   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:26 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:46PM +0300, Adrian Hunter escreveu:
> Add evsel as a parameter to ->idx() in preparation for correctly
> determining whether an auxtrace mmap is needed.
> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

Thanks, applied.

- Arnaldo

> ---
>  tools/lib/perf/evlist.c                  | 2 +-
>  tools/lib/perf/include/internal/evlist.h | 3 ++-
>  tools/perf/util/evlist.c                 | 1 +
>  3 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> index 4fce417432aa..ed66f2e38464 100644
> --- a/tools/lib/perf/evlist.c
> +++ b/tools/lib/perf/evlist.c
> @@ -479,7 +479,7 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
>  			refcount_set(&map->refcnt, 2);
>  
>  			if (ops->idx)
> -				ops->idx(evlist, mp, idx);
> +				ops->idx(evlist, evsel, mp, idx);
>  
>  			if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
>  				return -1;
> diff --git a/tools/lib/perf/include/internal/evlist.h b/tools/lib/perf/include/internal/evlist.h
> index 0d5c830431a7..6f89aec3e608 100644
> --- a/tools/lib/perf/include/internal/evlist.h
> +++ b/tools/lib/perf/include/internal/evlist.h
> @@ -38,7 +38,8 @@ struct perf_evlist {
>  };
>  
>  typedef void
> -(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int);
> +(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_evsel*,
> +			      struct perf_mmap_param*, int);
>  typedef struct perf_mmap*
>  (*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int);
>  typedef int
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 09a1d3400fd9..7ae56b062f44 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -747,6 +747,7 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
>  
>  static void
>  perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
> +			 struct perf_evsel *_evsel __maybe_unused,
>  			 struct perf_mmap_param *_mp,
>  			 int idx)
>  {
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed
  2022-05-06 12:25 ` [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed Adrian Hunter
@ 2022-05-10 17:27   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-10 17:27 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Em Fri, May 06, 2022 at 03:25:47PM +0300, Adrian Hunter escreveu:
> Add a flag needs_auxtrace_mmap to record whether an auxtrace mmap is
> needed, in preparation for correctly determining whether or not an
> auxtrace mmap is needed.

Thanks, applied.

- Arnaldo

> 
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/arch/arm/util/cs-etm.c    | 1 +
>  tools/perf/arch/arm64/util/arm-spe.c | 1 +
>  tools/perf/arch/s390/util/auxtrace.c | 1 +
>  tools/perf/arch/x86/util/intel-bts.c | 1 +
>  tools/perf/arch/x86/util/intel-pt.c  | 1 +
>  tools/perf/util/evsel.h              | 1 +
>  6 files changed, 6 insertions(+)
> 
> diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
> index 11c71aa219f7..1b54638d53b0 100644
> --- a/tools/perf/arch/arm/util/cs-etm.c
> +++ b/tools/perf/arch/arm/util/cs-etm.c
> @@ -319,6 +319,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
>  			}
>  			evsel->core.attr.freq = 0;
>  			evsel->core.attr.sample_period = 1;
> +			evsel->needs_auxtrace_mmap = true;
>  			cs_etm_evsel = evsel;
>  			opts->full_auxtrace = true;
>  		}
> diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
> index e8b577d33e53..6f4db2ac5420 100644
> --- a/tools/perf/arch/arm64/util/arm-spe.c
> +++ b/tools/perf/arch/arm64/util/arm-spe.c
> @@ -160,6 +160,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
>  			}
>  			evsel->core.attr.freq = 0;
>  			evsel->core.attr.sample_period = arm_spe_pmu->default_config->sample_period;
> +			evsel->needs_auxtrace_mmap = true;
>  			arm_spe_evsel = evsel;
>  			opts->full_auxtrace = true;
>  		}
> diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
> index 0db5c58c98e8..5068baa3e092 100644
> --- a/tools/perf/arch/s390/util/auxtrace.c
> +++ b/tools/perf/arch/s390/util/auxtrace.c
> @@ -98,6 +98,7 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
>  	evlist__for_each_entry(evlist, pos) {
>  		if (pos->core.attr.config == PERF_EVENT_CPUM_SF_DIAG) {
>  			diagnose = 1;
> +			pos->needs_auxtrace_mmap = true;
>  			break;
>  		}
>  	}
> diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
> index d68a0f48e41e..bcccfbade5c6 100644
> --- a/tools/perf/arch/x86/util/intel-bts.c
> +++ b/tools/perf/arch/x86/util/intel-bts.c
> @@ -129,6 +129,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr,
>  			}
>  			evsel->core.attr.freq = 0;
>  			evsel->core.attr.sample_period = 1;
> +			evsel->needs_auxtrace_mmap = true;
>  			intel_bts_evsel = evsel;
>  			opts->full_auxtrace = true;
>  		}
> diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
> index 38ec2666ec12..2eaac4638aab 100644
> --- a/tools/perf/arch/x86/util/intel-pt.c
> +++ b/tools/perf/arch/x86/util/intel-pt.c
> @@ -649,6 +649,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
>  			evsel->core.attr.freq = 0;
>  			evsel->core.attr.sample_period = 1;
>  			evsel->no_aux_samples = true;
> +			evsel->needs_auxtrace_mmap = true;
>  			intel_pt_evsel = evsel;
>  			opts->full_auxtrace = true;
>  		}
> diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
> index 45d674812239..544fbed98df1 100644
> --- a/tools/perf/util/evsel.h
> +++ b/tools/perf/util/evsel.h
> @@ -124,6 +124,7 @@ struct evsel {
>  	bool			merged_stat;
>  	bool			reset_group;
>  	bool			errored;
> +	bool			needs_auxtrace_mmap;
>  	struct hashmap		*per_pkg_mask;
>  	int			err;
>  	struct {
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-10 16:24           ` Arnaldo Carvalho de Melo
@ 2022-05-10 17:32             ` Adrian Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-10 17:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ian Rogers, Jiri Olsa, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

On 10/05/22 19:24, Arnaldo Carvalho de Melo wrote:
> Em Tue, May 10, 2022 at 05:55:34PM +0300, Adrian Hunter escreveu:
>> On 6/05/22 18:35, Ian Rogers wrote:
>>> On Fri, May 6, 2022 at 8:08 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> On 6/05/22 16:47, Ian Rogers wrote:
>>>>> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>
>>>>>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
>>>>>> event that sets up the system-wide maps before map propagation.
>>>>>>
>>>>>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
>>>>>> whether or not the event needs to be system-wide.
>>>>>>
>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>>> ---
>>>>>>  tools/perf/util/evlist.c | 40 ++++++++++++++++++++++++++++++++++++++++
>>>>>>  tools/perf/util/evlist.h |  5 +++++
>>>>>>  2 files changed, 45 insertions(+)
>>>>>>
>>>>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>>>>>> index 78c47cbafbc2..c16bd4836314 100644
>>>>>> --- a/tools/perf/util/evlist.c
>>>>>> +++ b/tools/perf/util/evlist.c
>>>>>> @@ -264,6 +264,46 @@ int evlist__add_dummy(struct evlist *evlist)
>>>>>>         return 0;
>>>>>>  }
>>>>>>
>>>>>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
>>>>>> +{
>>>>>> +       evsel->core.system_wide = true;
>>>>>> +
>>>>>> +       /* All CPUs */
>>>>>> +       perf_cpu_map__put(evsel->core.own_cpus);
>>>>>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
>>>>>> +       perf_cpu_map__put(evsel->core.cpus);
>>>>>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
>>>>>> +
>>>>>> +       /* No threads */
>>>>>> +       perf_thread_map__put(evsel->core.threads);
>>>>>> +       evsel->core.threads = perf_thread_map__new_dummy();
>>>>>> +
>>>>>> +       evlist__add(evlist, evsel);
>>>>>> +}
>>>>>> +
>>>>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
>>>>>> +{
>>>>>> +       struct evsel *evsel = evlist__dummy_event(evlist);
>>>>>> +
>>>>>> +       if (!evsel)
>>>>>> +               return NULL;
>>>>>> +
>>>>>> +       evsel->core.attr.exclude_kernel = 1;
>>>>>> +       evsel->core.attr.exclude_guest = 1;
>>>>>> +       evsel->core.attr.exclude_hv = 1;
>>>>>> +       evsel->core.attr.freq = 0;
>>>>>> +       evsel->core.attr.sample_period = 1;
>>>>>> +       evsel->no_aux_samples = true;
>>>>>> +       evsel->name = strdup("dummy:u");
>>>>>> +
>>>>>> +       if (system_wide)
>>>>>> +               evlist__add_on_all_cpus(evlist, evsel);
>>>>>> +       else
>>>>>> +               evlist__add(evlist, evsel);
>>>>>> +
>>>>>> +       return evsel;
>>>>>> +}
>>>>>> +
>>>>>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>>>>>>  {
>>>>>>         struct evsel *evsel, *n;
>>>>>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
>>>>>> index 4062f5aebfc1..1bde9ccf4e7d 100644
>>>>>> --- a/tools/perf/util/evlist.h
>>>>>> +++ b/tools/perf/util/evlist.h
>>>>>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>>>>>>  struct evsel *arch_evlist__leader(struct list_head *list);
>>>>>>
>>>>>>  int evlist__add_dummy(struct evlist *evlist);
>>>>>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
>>>>>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
>>>>>
>>>>> Sorry to be a language lawyer. What I hope to clean up with CPU maps is that:
>>>>>
>>>>> empty == dummy == any CPU
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n279
>>>>>
>>>>> Given every CPU map should be empty or contain any CPU then it seems
>>>>> they all meet the definition of empty - so something is wrong.
>>>>
>>>> Nothing is wrong.  I am not against clarifying things, but stop assuming
>>>> natural language has to mean anything exactly.  That is what computer
>>>> languages are for.
>>>>
>>>> Sometimes more abstract language is used, precisely to stop people
>>>> making assumptions about the details.
>>>>
>>>>>
>>>>> The cpu map here is explicitly opened so that it gets all online CPUs:
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/cpumap.c?h=perf/core#n174
>>>>>
>>>>> From:
>>>>> https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/cputopology.rst
>>>>> there are example topologies like:
>>>>> kernel_max: 31
>>>>>    offline: 2,4-31,32-63
>>>>>     online: 0-1,3
>>>>>   possible: 0-31
>>>>>    present: 0-31
>>>>>
>>>>> all_cpus could mean the union of offline and online CPUs, possible
>>>>> CPUs or present CPUs. You are saying that in the perf code all_cpus
>>>>> should be the same as all online cpus as only those CPUs are valid
>>>>> with perf_event_open. That's true but offline CPUs can be made online.
>>>>> If that happens here then the dummy events will have a CPU map that
>>>>> rather than being for all CPUs will be for all online CPUs at the
>>>>> point it was opened. Having online in the function name I think
>>>>> captures the time dependent nature of this - but if you think that's
>>>>> too much could we add a comment?
>>>>
>>>> If you ask me it does the exact opposite.  The function of the code
>>>> is to put the event on all CPUS without having to know the details
>>>> of: well actually perf doesn't automagically retain or restore events
>>>> across enabling or disabling CPUs so in fact we deal only in online
>>>> CPUs.
>>>
>>> But 'any CPU' (-1) could map to an offline CPU brought online. Calling
>>> this function twice could also result in this behavior. Via the
>>> topology documentation we have language to describe exactly the
>>> scenario that's happening and I'd prefer not to muddy that by making
>>> all and online synonyms.
>>
>> In this case the caller wants all CPUs, not online CPUs.  The detail
>> that we can't trace offline CPUs that become online is not relevant
>> to the caller.  Why would the caller call a function limited to online
>> CPUs when that is not what the caller wants.
> 
> Agreed, the intention is for all CPUs to be traced, so all that can be
> traced should be traced, at the time of the call to this function.
> 
> An improvement, that would change the workings of this function, but
> that would still do what was asked, would be to have functionality that
> remembers such requestgs for tracing all CPUs and when a CPU that was
> offline is brought online, gets that CPU added to whoever asked for all
> CPUs to be traced.
> 
> If this is something critical to the caller, then perhaps it should
> provide a callback for when CPUs are made online (or offline).
> 
> But then we can add that functionality when the need arises?

It should always be possible to figure out which evsels to add a newly
online CPU to.  Roughly:

per-thread evsels CPU map = {-1} => never change since the kernel
dynamically schedules per-task contexts.

If the CPU is a user-requested CPU, add it to all per-cpu evsels.

Otherwise add it to evsels marked as system_wide.

Actually adding it would be a lot more challenging.

> 
> - Arnaldo
>  
>>>>> too much could we add a comment? I'm trying to avoid a situation, like
>>>>> with the CPU map code, where all and online are interchangeable
>>>>> leading to the code being unnecessarily confusing unless you read
>>>>> every line.
>>>>
>>>> It is normal to have to read the details of code, and, in my
>>>> experience at least, normal for the code not to work exactly the
>>>> way I'd imagined.
>>>
>>> :-) The problem is that we all need to work with abstractions at some
>>> point, abstraction is pretty much the whole point of computer science.
>>> We need to fix CPU maps empty function, it is just a fundamental level
>>> of contradiction. As with the CPU map index being often mistaken for
>>> the CPU leading to bugs and crashes, I suspect remedying empty will
>>> fix existing and future bugs. With function naming the point is to be
>>> short and succinct, but also to be intention revealing for the sake of
>>> abstraction. Yes you need to read the code, but as with CPU map empty
>>> even that isn't enough and trying to infer behavior from usage can be
>>> a long and painful process.
>>
>> You seem to be insisting that the function be named for its
>> implementation (i.e. offline CPUs are not supported) not its
>> purpose (trace system wide).
>>
>> I can only suggest we go back to the original name, because the
>> function has *nothing* to do with whether or not perf supports
>> tracing per-cpu contexts on offline CPUs that become online.
>>
>>>
>>> Thanks,
>>> Ian
>>>
>>>>>
>>>>> Thanks,
>>>>> Ian
>>>>>
>>>>>> +{
>>>>>> +       return evlist__add_aux_dummy(evlist, true);
>>>>>> +}
>>>>>>
>>>>>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>>>>>>                          evsel__sb_cb_t cb, void *data);
>>>>>> --
>>>>>> 2.25.1
>>>>>>
>>>>
> 


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH V3 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params
  2022-05-06 12:25 ` [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params Adrian Hunter
  2022-05-06 20:16   ` Ian Rogers
@ 2022-05-11  7:01   ` Adrian Hunter
  1 sibling, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-11  7:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add mmap_needed to auxtrace_mmap_params.

Currently an auxtrace mmap is always attempted even if the event is not an
auxtrace event. That works because, when AUX area tracing, there is always
an auxtrace event first for every mmap. Prepare for that not being the
case, which it won't be when sideband tracking events are allowed on
all CPUs even when auxtrace is limited to selected CPUs.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---

Changes in V3: Amended mmap_needed comment

 tools/perf/util/auxtrace.c | 10 ++++++++--
 tools/perf/util/auxtrace.h | 11 +++++++++--
 tools/perf/util/evlist.c   |  5 +++--
 tools/perf/util/mmap.c     |  1 +
 4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index b11549ae39df..b446cfa66469 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -125,7 +125,7 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
 	mm->tid = mp->tid;
 	mm->cpu = mp->cpu.cpu;
 
-	if (!mp->len) {
+	if (!mp->len || !mp->mmap_needed) {
 		mm->base = NULL;
 		return 0;
 	}
@@ -168,9 +168,15 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 }
 
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu)
 {
+	mp->mmap_needed = evsel->needs_auxtrace_mmap;
+
+	if (!mp->mmap_needed)
+		return;
+
 	mp->idx = idx;
 
 	if (per_cpu) {
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index dc38b6f57232..695591b73ae1 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -344,6 +344,10 @@ struct auxtrace_mmap {
  * @idx: index of this mmap
  * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
  *       mmap) otherwise %0
+ * @mmap_needed: set to %false for non-auxtrace events. This is needed because
+ *               auxtrace mmapping is done in the same code path as non-auxtrace
+ *               mmapping but not every evsel that needs non-auxtrace mmapping
+ *               also needs auxtrace mmapping.
  * @cpu: cpu number for a per-cpu mmap otherwise %-1
  */
 struct auxtrace_mmap_params {
@@ -353,6 +357,7 @@ struct auxtrace_mmap_params {
 	int		prot;
 	int		idx;
 	pid_t		tid;
+	bool		mmap_needed;
 	struct perf_cpu	cpu;
 };
 
@@ -490,7 +495,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				unsigned int auxtrace_pages,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu);
 
 typedef int (*process_auxtrace_t)(struct perf_tool *tool,
@@ -863,7 +869,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
 				unsigned int auxtrace_pages,
 				bool auxtrace_overwrite);
 void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
-				   struct evlist *evlist, int idx,
+				   struct evlist *evlist,
+				   struct evsel *evsel, int idx,
 				   bool per_cpu);
 
 #define ITRACE_HELP ""
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 7ae56b062f44..996bdc203616 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -747,15 +747,16 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
 
 static void
 perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
-			 struct perf_evsel *_evsel __maybe_unused,
+			 struct perf_evsel *_evsel,
 			 struct perf_mmap_param *_mp,
 			 int idx)
 {
 	struct evlist *evlist = container_of(_evlist, struct evlist, core);
 	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
 	bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
+	struct evsel *evsel = container_of(_evsel, struct evsel, core);
 
-	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
+	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
 }
 
 static struct perf_mmap*
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index 50502b4a7ca4..de59c4da852b 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -62,6 +62,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
 
 void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
 					  struct evlist *evlist __maybe_unused,
+					  struct evsel *evsel __maybe_unused,
 					  int idx __maybe_unused,
 					  bool per_cpu __maybe_unused)
 {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params
  2022-05-06 20:16   ` Ian Rogers
@ 2022-05-11  7:02     ` Adrian Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-11  7:02 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On 6/05/22 23:16, Ian Rogers wrote:
> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> Add mmap_needed to auxtrace_mmap_params.
>>
>> Currently an auxtrace mmap is always attempted even if the event is not an
>> auxtrace event. That works because, when AUX area tracing, there is always
>> an auxtrace event first for every mmap. Prepare for that not being the
>> case, which it won't be when sideband tracking events are allowed on
>> all CPUs even when auxtrace is limited to selected CPUs.
> 
> Should there be a later patch to remove this option and just not do
> the auxtrace mmap when it's not necessary?

The same code path is used for non-auxtrace mmap as auxtrace mmap.
I have amended the comment to explain.

> 
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/perf/util/auxtrace.c | 10 ++++++++--
>>  tools/perf/util/auxtrace.h |  8 ++++++--
>>  tools/perf/util/evlist.c   |  5 +++--
>>  tools/perf/util/mmap.c     |  1 +
>>  4 files changed, 18 insertions(+), 6 deletions(-)
>>
>> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
>> index b11549ae39df..b446cfa66469 100644
>> --- a/tools/perf/util/auxtrace.c
>> +++ b/tools/perf/util/auxtrace.c
>> @@ -125,7 +125,7 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
>>         mm->tid = mp->tid;
>>         mm->cpu = mp->cpu.cpu;
>>
>> -       if (!mp->len) {
>> +       if (!mp->len || !mp->mmap_needed) {
>>                 mm->base = NULL;
>>                 return 0;
>>         }
>> @@ -168,9 +168,15 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>>  }
>>
>>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>> -                                  struct evlist *evlist, int idx,
>> +                                  struct evlist *evlist,
>> +                                  struct evsel *evsel, int idx,
>>                                    bool per_cpu)
>>  {
>> +       mp->mmap_needed = evsel->needs_auxtrace_mmap;
>> +
>> +       if (!mp->mmap_needed)
>> +               return;
>> +
>>         mp->idx = idx;
>>
>>         if (per_cpu) {
>> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
>> index dc38b6f57232..37feae003904 100644
>> --- a/tools/perf/util/auxtrace.h
>> +++ b/tools/perf/util/auxtrace.h
>> @@ -344,6 +344,7 @@ struct auxtrace_mmap {
>>   * @idx: index of this mmap
>>   * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
>>   *       mmap) otherwise %0
>> + * @mmap_needed: set to %false for non-auxtrace events
> 
> Could you add something like:
> (ie. we don't want the mmap but we do want the side effects of ...
> 
> Thanks,
> Ian
> 
>>   * @cpu: cpu number for a per-cpu mmap otherwise %-1
>>   */
>>  struct auxtrace_mmap_params {
>> @@ -353,6 +354,7 @@ struct auxtrace_mmap_params {
>>         int             prot;
>>         int             idx;
>>         pid_t           tid;
>> +       bool            mmap_needed;
>>         struct perf_cpu cpu;
>>  };
>>
>> @@ -490,7 +492,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>>                                 unsigned int auxtrace_pages,
>>                                 bool auxtrace_overwrite);
>>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>> -                                  struct evlist *evlist, int idx,
>> +                                  struct evlist *evlist,
>> +                                  struct evsel *evsel, int idx,
>>                                    bool per_cpu);
>>
>>  typedef int (*process_auxtrace_t)(struct perf_tool *tool,
>> @@ -863,7 +866,8 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
>>                                 unsigned int auxtrace_pages,
>>                                 bool auxtrace_overwrite);
>>  void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
>> -                                  struct evlist *evlist, int idx,
>> +                                  struct evlist *evlist,
>> +                                  struct evsel *evsel, int idx,
>>                                    bool per_cpu);
>>
>>  #define ITRACE_HELP ""
>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>> index 7ae56b062f44..996bdc203616 100644
>> --- a/tools/perf/util/evlist.c
>> +++ b/tools/perf/util/evlist.c
>> @@ -747,15 +747,16 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
>>
>>  static void
>>  perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
>> -                        struct perf_evsel *_evsel __maybe_unused,
>> +                        struct perf_evsel *_evsel,
>>                          struct perf_mmap_param *_mp,
>>                          int idx)
>>  {
>>         struct evlist *evlist = container_of(_evlist, struct evlist, core);
>>         struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
>>         bool per_cpu = !perf_cpu_map__empty(_evlist->user_requested_cpus);
>> +       struct evsel *evsel = container_of(_evsel, struct evsel, core);
>>
>> -       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu);
>> +       auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx, per_cpu);
>>  }
>>
>>  static struct perf_mmap*
>> diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
>> index 50502b4a7ca4..de59c4da852b 100644
>> --- a/tools/perf/util/mmap.c
>> +++ b/tools/perf/util/mmap.c
>> @@ -62,6 +62,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u
>>
>>  void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused,
>>                                           struct evlist *evlist __maybe_unused,
>> +                                         struct evsel *evsel __maybe_unused,
>>                                           int idx __maybe_unused,
>>                                           bool per_cpu __maybe_unused)
>>  {
>> --
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH V3 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-06 12:25 ` [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus() Adrian Hunter
  2022-05-06 13:47   ` Ian Rogers
@ 2022-05-11  7:02   ` Adrian Hunter
  2022-05-11 22:50     ` Namhyung Kim
  1 sibling, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-11  7:02 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, Ian Rogers, Alexey Bayduraev, Namhyung Kim, Leo Yan,
	linux-kernel

Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
event that sets up the system-wide maps before map propagation.

For convenience, add evlist__add_aux_dummy() so that the logic can be used
whether or not the event needs to be system-wide.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---

Changes in V3: Amended comment about all CPUs.

 tools/perf/util/evlist.c | 45 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  5 +++++
 2 files changed, 50 insertions(+)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 78c47cbafbc2..2b2900434bba 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -264,6 +264,51 @@ int evlist__add_dummy(struct evlist *evlist)
 	return 0;
 }
 
+static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
+{
+	evsel->core.system_wide = true;
+
+	/*
+	 * All CPUs.
+	 *
+	 * Note perf_event_open() does not accept CPUs that are not online, so
+	 * in fact this CPU list will include only all online CPUs.
+	 */
+	perf_cpu_map__put(evsel->core.own_cpus);
+	evsel->core.own_cpus = perf_cpu_map__new(NULL);
+	perf_cpu_map__put(evsel->core.cpus);
+	evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
+
+	/* No threads */
+	perf_thread_map__put(evsel->core.threads);
+	evsel->core.threads = perf_thread_map__new_dummy();
+
+	evlist__add(evlist, evsel);
+}
+
+struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
+{
+	struct evsel *evsel = evlist__dummy_event(evlist);
+
+	if (!evsel)
+		return NULL;
+
+	evsel->core.attr.exclude_kernel = 1;
+	evsel->core.attr.exclude_guest = 1;
+	evsel->core.attr.exclude_hv = 1;
+	evsel->core.attr.freq = 0;
+	evsel->core.attr.sample_period = 1;
+	evsel->no_aux_samples = true;
+	evsel->name = strdup("dummy:u");
+
+	if (system_wide)
+		evlist__add_on_all_cpus(evlist, evsel);
+	else
+		evlist__add(evlist, evsel);
+
+	return evsel;
+}
+
 static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
 {
 	struct evsel *evsel, *n;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 4062f5aebfc1..1bde9ccf4e7d 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
 struct evsel *arch_evlist__leader(struct list_head *list);
 
 int evlist__add_dummy(struct evlist *evlist);
+struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
+static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
+{
+	return evlist__add_aux_dummy(evlist, true);
+}
 
 int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
 			 evsel__sb_cb_t cb, void *data);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 21/23] libperf evsel: Add comments for booleans
  2022-05-06 20:51   ` Ian Rogers
@ 2022-05-11  7:03     ` Adrian Hunter
  2022-05-12  5:34       ` Ian Rogers
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-11  7:03 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On 6/05/22 23:51, Ian Rogers wrote:
> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> Add comments for 'system_wide' and 'requires_cpu' booleans
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/lib/perf/include/internal/evsel.h | 9 +++++++++
>>  1 file changed, 9 insertions(+)
>>
>> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
>> index 77fbb8b97e5c..cc8f1ba790bd 100644
>> --- a/tools/lib/perf/include/internal/evsel.h
>> +++ b/tools/lib/perf/include/internal/evsel.h
>> @@ -49,7 +49,16 @@ struct perf_evsel {
>>
>>         /* parse modifier helper */
>>         int                      nr_members;
>> +       /*
>> +        * system_wide is for events that need to be on every CPU, irrespective
>> +        * of user requested CPUs or threads. Map propagation will not override
>> +        * this events own_cpus, which will contribute to evlist all_cpus.
> 
> So this muddies my understanding of cpus and own_cpus (sigh, again
> undocumented). I believe cpus to be the set of CPUs (or any CPU, aka
> dummy) that perf_event_open happens on. all_cpus in evlist is the
> union of all the evsels cpus (ie not related to own_cpus as described
> here). Own_cpus I believe to be what's computed at parse-event time
> from sysfs. Is this a typo in the comment or quite likely my error?

A 'system_wide' event is not created by the parser, so own_cpus is set
by the code adding the event.

> 
> Thanks,
> Ian
> 
>> +        */
>>         bool                     system_wide;
>> +       /*
>> +        * Some events, for example uncore events, require a CPU.
>> +        * i.e. it cannot be the 'any CPU' value of -1.
>> +        */
>>         bool                     requires_cpu;
>>         int                      idx;
>>  };
>> --
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V3 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-11  7:02   ` [PATCH V3 " Adrian Hunter
@ 2022-05-11 22:50     ` Namhyung Kim
  2022-05-12  4:33       ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Namhyung Kim @ 2022-05-11 22:50 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel

On Wed, May 11, 2022 at 12:02 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> event that sets up the system-wide maps before map propagation.
>
> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> whether or not the event needs to be system-wide.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>
> Changes in V3: Amended comment about all CPUs.
>
>  tools/perf/util/evlist.c | 45 ++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/evlist.h |  5 +++++
>  2 files changed, 50 insertions(+)
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 78c47cbafbc2..2b2900434bba 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -264,6 +264,51 @@ int evlist__add_dummy(struct evlist *evlist)
>         return 0;
>  }
>
> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> +{
> +       evsel->core.system_wide = true;
> +
> +       /*
> +        * All CPUs.
> +        *
> +        * Note perf_event_open() does not accept CPUs that are not online, so
> +        * in fact this CPU list will include only all online CPUs.
> +        */
> +       perf_cpu_map__put(evsel->core.own_cpus);
> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> +       perf_cpu_map__put(evsel->core.cpus);
> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);

Maybe I'm missing something.. Wouldn't it be overwritten
by the user requested cpus during map propagation in
evlist__add()?

Thanks,
Namhyung


> +
> +       /* No threads */
> +       perf_thread_map__put(evsel->core.threads);
> +       evsel->core.threads = perf_thread_map__new_dummy();
> +
> +       evlist__add(evlist, evsel);
> +}
> +
> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
> +{
> +       struct evsel *evsel = evlist__dummy_event(evlist);
> +
> +       if (!evsel)
> +               return NULL;
> +
> +       evsel->core.attr.exclude_kernel = 1;
> +       evsel->core.attr.exclude_guest = 1;
> +       evsel->core.attr.exclude_hv = 1;
> +       evsel->core.attr.freq = 0;
> +       evsel->core.attr.sample_period = 1;
> +       evsel->no_aux_samples = true;
> +       evsel->name = strdup("dummy:u");
> +
> +       if (system_wide)
> +               evlist__add_on_all_cpus(evlist, evsel);
> +       else
> +               evlist__add(evlist, evsel);
> +
> +       return evsel;
> +}
> +
>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>  {
>         struct evsel *evsel, *n;
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 4062f5aebfc1..1bde9ccf4e7d 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>  struct evsel *arch_evlist__leader(struct list_head *list);
>
>  int evlist__add_dummy(struct evlist *evlist);
> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
> +{
> +       return evlist__add_aux_dummy(evlist, true);
> +}
>
>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>                          evsel__sb_cb_t cb, void *data);
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V3 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-11 22:50     ` Namhyung Kim
@ 2022-05-12  4:33       ` Adrian Hunter
  2022-05-12  5:01         ` Namhyung Kim
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-12  4:33 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel

On 12/05/22 01:50, Namhyung Kim wrote:
> On Wed, May 11, 2022 at 12:02 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
>> event that sets up the system-wide maps before map propagation.
>>
>> For convenience, add evlist__add_aux_dummy() so that the logic can be used
>> whether or not the event needs to be system-wide.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>
>> Changes in V3: Amended comment about all CPUs.
>>
>>  tools/perf/util/evlist.c | 45 ++++++++++++++++++++++++++++++++++++++++
>>  tools/perf/util/evlist.h |  5 +++++
>>  2 files changed, 50 insertions(+)
>>
>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>> index 78c47cbafbc2..2b2900434bba 100644
>> --- a/tools/perf/util/evlist.c
>> +++ b/tools/perf/util/evlist.c
>> @@ -264,6 +264,51 @@ int evlist__add_dummy(struct evlist *evlist)
>>         return 0;
>>  }
>>
>> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
>> +{
>> +       evsel->core.system_wide = true;
>> +
>> +       /*
>> +        * All CPUs.
>> +        *
>> +        * Note perf_event_open() does not accept CPUs that are not online, so
>> +        * in fact this CPU list will include only all online CPUs.
>> +        */
>> +       perf_cpu_map__put(evsel->core.own_cpus);
>> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
>> +       perf_cpu_map__put(evsel->core.cpus);
>> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> 
> Maybe I'm missing something.. Wouldn't it be overwritten
> by the user requested cpus during map propagation in
> evlist__add()?

Yes.  That gets changed in patch 22 "perf tools: Allow system-wide
events to keep their own CPUs"

> 
> Thanks,
> Namhyung
> 
> 
>> +
>> +       /* No threads */
>> +       perf_thread_map__put(evsel->core.threads);
>> +       evsel->core.threads = perf_thread_map__new_dummy();
>> +
>> +       evlist__add(evlist, evsel);
>> +}
>> +
>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
>> +{
>> +       struct evsel *evsel = evlist__dummy_event(evlist);
>> +
>> +       if (!evsel)
>> +               return NULL;
>> +
>> +       evsel->core.attr.exclude_kernel = 1;
>> +       evsel->core.attr.exclude_guest = 1;
>> +       evsel->core.attr.exclude_hv = 1;
>> +       evsel->core.attr.freq = 0;
>> +       evsel->core.attr.sample_period = 1;
>> +       evsel->no_aux_samples = true;
>> +       evsel->name = strdup("dummy:u");
>> +
>> +       if (system_wide)
>> +               evlist__add_on_all_cpus(evlist, evsel);
>> +       else
>> +               evlist__add(evlist, evsel);
>> +
>> +       return evsel;
>> +}
>> +
>>  static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
>>  {
>>         struct evsel *evsel, *n;
>> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
>> index 4062f5aebfc1..1bde9ccf4e7d 100644
>> --- a/tools/perf/util/evlist.h
>> +++ b/tools/perf/util/evlist.h
>> @@ -114,6 +114,11 @@ int arch_evlist__add_default_attrs(struct evlist *evlist);
>>  struct evsel *arch_evlist__leader(struct list_head *list);
>>
>>  int evlist__add_dummy(struct evlist *evlist);
>> +struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide);
>> +static inline struct evsel *evlist__add_dummy_on_all_cpus(struct evlist *evlist)
>> +{
>> +       return evlist__add_aux_dummy(evlist, true);
>> +}
>>
>>  int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
>>                          evsel__sb_cb_t cb, void *data);
>> --
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V3 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus()
  2022-05-12  4:33       ` Adrian Hunter
@ 2022-05-12  5:01         ` Namhyung Kim
  0 siblings, 0 replies; 70+ messages in thread
From: Namhyung Kim @ 2022-05-12  5:01 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel

On Wed, May 11, 2022 at 9:33 PM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 12/05/22 01:50, Namhyung Kim wrote:
> > On Wed, May 11, 2022 at 12:02 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> Add evlist__add_dummy_on_all_cpus() to enable creating a system-wide dummy
> >> event that sets up the system-wide maps before map propagation.
> >>
> >> For convenience, add evlist__add_aux_dummy() so that the logic can be used
> >> whether or not the event needs to be system-wide.
> >>
> >> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >> ---
> >>
> >> Changes in V3: Amended comment about all CPUs.
> >>
> >>  tools/perf/util/evlist.c | 45 ++++++++++++++++++++++++++++++++++++++++
> >>  tools/perf/util/evlist.h |  5 +++++
> >>  2 files changed, 50 insertions(+)
> >>
> >> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >> index 78c47cbafbc2..2b2900434bba 100644
> >> --- a/tools/perf/util/evlist.c
> >> +++ b/tools/perf/util/evlist.c
> >> @@ -264,6 +264,51 @@ int evlist__add_dummy(struct evlist *evlist)
> >>         return 0;
> >>  }
> >>
> >> +static void evlist__add_on_all_cpus(struct evlist *evlist, struct evsel *evsel)
> >> +{
> >> +       evsel->core.system_wide = true;
> >> +
> >> +       /*
> >> +        * All CPUs.
> >> +        *
> >> +        * Note perf_event_open() does not accept CPUs that are not online, so
> >> +        * in fact this CPU list will include only all online CPUs.
> >> +        */
> >> +       perf_cpu_map__put(evsel->core.own_cpus);
> >> +       evsel->core.own_cpus = perf_cpu_map__new(NULL);
> >> +       perf_cpu_map__put(evsel->core.cpus);
> >> +       evsel->core.cpus = perf_cpu_map__get(evsel->core.own_cpus);
> >
> > Maybe I'm missing something.. Wouldn't it be overwritten
> > by the user requested cpus during map propagation in
> > evlist__add()?
>
> Yes.  That gets changed in patch 22 "perf tools: Allow system-wide
> events to keep their own CPUs"

Oh, I see.  I'll take a look.

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-06 12:26 ` [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs Adrian Hunter
@ 2022-05-12  5:27   ` Namhyung Kim
  2022-05-12 10:34     ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Namhyung Kim @ 2022-05-12  5:27 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel

On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
> has_user_cpus. Change that so that system-wide events retain their own
> CPUs and they are added to all_cpus.
>
> Acked-by: Ian Rogers <irogers@google.com>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/lib/perf/evlist.c | 11 +++++------
>  1 file changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> index 1c801f8da44f..9a6801b53274 100644
> --- a/tools/lib/perf/evlist.c
> +++ b/tools/lib/perf/evlist.c
> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>          * We already have cpus for evsel (via PMU sysfs) so
>          * keep it, if there's no target cpu list defined.
>          */
> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
> -               perf_cpu_map__put(evsel->cpus);
> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> -       } else if (!evsel->system_wide &&
> -                  !evsel->requires_cpu &&
> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
> +       if (!evsel->own_cpus ||
> +           (!evsel->system_wide && evlist->has_user_cpus) ||
> +           (!evsel->system_wide &&
> +            !evsel->requires_cpu &&
> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {

This is getting hard to understand.  IIUC this propagation basically
sets user requested cpus to evsel unless it has its own cpus, right?

But the hybrid pmus make this complex.  Maybe we can move the
logic in evlist__fix_hybrid_cpus() here and simplify it like below

if (evsel->own_cpus) {
   if (evsel->pmu->is_hybrid)
      evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
                                      evlist->user_requested_cpus);  //?
   else
      evsel->cpus = evlist->own_cpus;  // put + get
} else {
   evsel->cpus = evlist->user_requested_cpus;  // put + get
}

Then we need to make sure evsel->pmu is set properly.

What do you think?

Thanks,
Namhyung


>                 perf_cpu_map__put(evsel->cpus);
>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>         } else if (evsel->cpus != evsel->own_cpus) {
> --
> 2.25.1
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 21/23] libperf evsel: Add comments for booleans
  2022-05-11  7:03     ` Adrian Hunter
@ 2022-05-12  5:34       ` Ian Rogers
  2022-05-12 11:40         ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Ian Rogers @ 2022-05-12  5:34 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On Wed, May 11, 2022 at 12:03 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 6/05/22 23:51, Ian Rogers wrote:
> > On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> Add comments for 'system_wide' and 'requires_cpu' booleans
> >>
> >> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >> ---
> >>  tools/lib/perf/include/internal/evsel.h | 9 +++++++++
> >>  1 file changed, 9 insertions(+)
> >>
> >> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
> >> index 77fbb8b97e5c..cc8f1ba790bd 100644
> >> --- a/tools/lib/perf/include/internal/evsel.h
> >> +++ b/tools/lib/perf/include/internal/evsel.h
> >> @@ -49,7 +49,16 @@ struct perf_evsel {
> >>
> >>         /* parse modifier helper */
> >>         int                      nr_members;
> >> +       /*
> >> +        * system_wide is for events that need to be on every CPU, irrespective
> >> +        * of user requested CPUs or threads. Map propagation will not override
> >> +        * this events own_cpus, which will contribute to evlist all_cpus.
> >
> > So this muddies my understanding of cpus and own_cpus (sigh, again
> > undocumented). I believe cpus to be the set of CPUs (or any CPU, aka
> > dummy) that perf_event_open happens on. all_cpus in evlist is the
> > union of all the evsels cpus (ie not related to own_cpus as described
> > here). Own_cpus I believe to be what's computed at parse-event time
> > from sysfs. Is this a typo in the comment or quite likely my error?
>
> A 'system_wide' event is not created by the parser, so own_cpus is set
> by the code adding the event.

I think I may be misreading the comment. Perhaps it should read:

system_wide is for events that need to be on every CPU, irrespective
of user requested CPUs or threads. Map propagation will not override
this event's own_cpus and own_cpus don't contribute to the evlist
all_cpus.

It would be nice if there were a comment on own_cpus to explain its
relationship to cpus and more broadly when it is used. Fwiw, the parse
time copy is made here:
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/parse-events.c?h=perf/core#n367

I worry that if own_cpus should be used in place of cpus then
iterators like evlist__for_each_cpu may need to handle this, and so
they'd be broken currently.

Thanks,
Ian

> >
> > Thanks,
> > Ian
> >
> >> +        */
> >>         bool                     system_wide;
> >> +       /*
> >> +        * Some events, for example uncore events, require a CPU.
> >> +        * i.e. it cannot be the 'any CPU' value of -1.
> >> +        */
> >>         bool                     requires_cpu;
> >>         int                      idx;
> >>  };
> >> --
> >> 2.25.1
> >>
>

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-12  5:27   ` Namhyung Kim
@ 2022-05-12 10:34     ` Adrian Hunter
  2022-05-12 18:53       ` Namhyung Kim
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-12 10:34 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel

On 12/05/22 08:27, Namhyung Kim wrote:
> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>> has_user_cpus. Change that so that system-wide events retain their own
>> CPUs and they are added to all_cpus.
>>
>> Acked-by: Ian Rogers <irogers@google.com>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/lib/perf/evlist.c | 11 +++++------
>>  1 file changed, 5 insertions(+), 6 deletions(-)
>>
>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>> index 1c801f8da44f..9a6801b53274 100644
>> --- a/tools/lib/perf/evlist.c
>> +++ b/tools/lib/perf/evlist.c
>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>          * We already have cpus for evsel (via PMU sysfs) so
>>          * keep it, if there's no target cpu list defined.
>>          */
>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>> -               perf_cpu_map__put(evsel->cpus);
>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>> -       } else if (!evsel->system_wide &&
>> -                  !evsel->requires_cpu &&
>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>> +       if (!evsel->own_cpus ||
>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>> +           (!evsel->system_wide &&
>> +            !evsel->requires_cpu &&
>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
> 
> This is getting hard to understand.  IIUC this propagation basically
> sets user requested cpus to evsel unless it has its own cpus, right?

I put the conditional logic altogether because that is kernel style but
it does make it practically unreadable.

If we start with the original logic:

	if (!evsel->own_cpus || evlist->has_user_cpus) {
		perf_cpu_map__put(evsel->cpus);
		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
	} else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
		perf_cpu_map__put(evsel->cpus);
		evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
	} else if (evsel->cpus != evsel->own_cpus) {
		perf_cpu_map__put(evsel->cpus);
		evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
	}

Then make it more readable, i.e. same functionality

	struct perf_cpu_map *cpus;

	if (!evsel->own_cpus || evlist->has_user_cpus)
		cpus = evlist->user_requested_cpus;
	else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

	if (evsel->cpus != cpus) {
		perf_cpu_map__put(evsel->cpus);
		evsel->cpus = perf_cpu_map__get(cpus);
	}

Then separate out the conditions, i.e. still same functionality

	if (!evsel->own_cpus)
		cpus = evlist->user_requested_cpus;
	else if (evlist->has_user_cpus)
		cpus = evlist->user_requested_cpus;
	else if (evsel->system_wide)
		cpus = evsel->own_cpus;
	else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

Then add the new requires_cpu flag:

	if (!evsel->own_cpus)
		cpus = evlist->user_requested_cpus;
	else if (evlist->has_user_cpus)
		cpus = evlist->user_requested_cpus;
	else if (evsel->system_wide)
		cpus = evsel->own_cpus;
-	else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
+	else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

Then make system_wide keep own_cpus even if has_user_cpus:

	if (!evsel->own_cpus)
		cpus = evlist->user_requested_cpus;
+	else if (evsel->system_wide)
+		cpus = evsel->own_cpus;
	else if (evlist->has_user_cpus)
		cpus = evlist->user_requested_cpus;
-	else if (evsel->system_wide)
-		cpus = evsel->own_cpus;
	else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

Which leaves:

	if (!evsel->own_cpus)
		cpus = evlist->user_requested_cpus;
	else if (evsel->system_wide)
		cpus = evsel->own_cpus;
	else if (evlist->has_user_cpus)
		cpus = evlist->user_requested_cpus;
	else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

And putting it back together:

	if (!evsel->own_cpus ||
	    (!evsel->system_wide && evlist->has_user_cpus) ||
	    (!evsel->system_wide &&
	     !evsel->requires_cpu &&
	     perf_cpu_map__empty(evlist->user_requested_cpus))) {
		cpus = evlist->user_requested_cpus;
	else
		cpus = evsel->own_cpus;

Perhaps I shouldn't put it together?

> 
> But the hybrid pmus make this complex.  Maybe we can move the
> logic in evlist__fix_hybrid_cpus() here and simplify it like below
> 
> if (evsel->own_cpus) {
>    if (evsel->pmu->is_hybrid)
>       evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>                                       evlist->user_requested_cpus);  //?
>    else
>       evsel->cpus = evlist->own_cpus;  // put + get
> } else {
>    evsel->cpus = evlist->user_requested_cpus;  // put + get
> }
> 
> Then we need to make sure evsel->pmu is set properly.
> 
> What do you think?

Hybrid handling looks complicated.  I would have to spend time
better understanding it.

So, in the context of this patch set, I don't want to look at
issues with hybrid CPUs, except that there should be no change
to how they are handled.

> 
> Thanks,
> Namhyung
> 
> 
>>                 perf_cpu_map__put(evsel->cpus);
>>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>         } else if (evsel->cpus != evsel->own_cpus) {
>> --
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 21/23] libperf evsel: Add comments for booleans
  2022-05-12  5:34       ` Ian Rogers
@ 2022-05-12 11:40         ` Adrian Hunter
  0 siblings, 0 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-12 11:40 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Alexey Bayduraev,
	Namhyung Kim, Leo Yan, linux-kernel

On 12/05/22 08:34, Ian Rogers wrote:
> On Wed, May 11, 2022 at 12:03 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 6/05/22 23:51, Ian Rogers wrote:
>>> On Fri, May 6, 2022 at 5:26 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> Add comments for 'system_wide' and 'requires_cpu' booleans
>>>>
>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>> ---
>>>>  tools/lib/perf/include/internal/evsel.h | 9 +++++++++
>>>>  1 file changed, 9 insertions(+)
>>>>
>>>> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
>>>> index 77fbb8b97e5c..cc8f1ba790bd 100644
>>>> --- a/tools/lib/perf/include/internal/evsel.h
>>>> +++ b/tools/lib/perf/include/internal/evsel.h
>>>> @@ -49,7 +49,16 @@ struct perf_evsel {
>>>>
>>>>         /* parse modifier helper */
>>>>         int                      nr_members;
>>>> +       /*
>>>> +        * system_wide is for events that need to be on every CPU, irrespective
>>>> +        * of user requested CPUs or threads. Map propagation will not override
>>>> +        * this events own_cpus, which will contribute to evlist all_cpus.
>>>
>>> So this muddies my understanding of cpus and own_cpus (sigh, again
>>> undocumented). I believe cpus to be the set of CPUs (or any CPU, aka
>>> dummy) that perf_event_open happens on. all_cpus in evlist is the
>>> union of all the evsels cpus (ie not related to own_cpus as described
>>> here). Own_cpus I believe to be what's computed at parse-event time
>>> from sysfs. Is this a typo in the comment or quite likely my error?
>>
>> A 'system_wide' event is not created by the parser, so own_cpus is set
>> by the code adding the event.
> 
> I think I may be misreading the comment. Perhaps it should read:
> 
> system_wide is for events that need to be on every CPU, irrespective
> of user requested CPUs or threads. Map propagation will not override
> this event's own_cpus and own_cpus don't contribute to the evlist
> all_cpus.

For a system_wide evsel, evsel->cpus are set to own_cpus and the
evsel->cpus contribute to all_cpus.

> 
> It would be nice if there were a comment on own_cpus to explain its
> relationship to cpus and more broadly when it is used. Fwiw, the parse
> time copy is made here:
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/parse-events.c?h=perf/core#n367
> 
> I worry that if own_cpus should be used in place of cpus then
> iterators like evlist__for_each_cpu may need to handle this, and so
> they'd be broken currently.

No, evsel->own_cpus may be used to determine evsel->cpus, but that
is where their influence stops.

> 
> Thanks,
> Ian
> 
>>>
>>> Thanks,
>>> Ian
>>>
>>>> +        */
>>>>         bool                     system_wide;
>>>> +       /*
>>>> +        * Some events, for example uncore events, require a CPU.
>>>> +        * i.e. it cannot be the 'any CPU' value of -1.
>>>> +        */
>>>>         bool                     requires_cpu;
>>>>         int                      idx;
>>>>  };
>>>> --
>>>> 2.25.1
>>>>
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-12 10:34     ` Adrian Hunter
@ 2022-05-12 18:53       ` Namhyung Kim
  2022-05-13  4:48         ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Namhyung Kim @ 2022-05-12 18:53 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian,
	Kan Liang

On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 12/05/22 08:27, Namhyung Kim wrote:
> > On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
> >> has_user_cpus. Change that so that system-wide events retain their own
> >> CPUs and they are added to all_cpus.
> >>
> >> Acked-by: Ian Rogers <irogers@google.com>
> >> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >> ---
> >>  tools/lib/perf/evlist.c | 11 +++++------
> >>  1 file changed, 5 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> >> index 1c801f8da44f..9a6801b53274 100644
> >> --- a/tools/lib/perf/evlist.c
> >> +++ b/tools/lib/perf/evlist.c
> >> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
> >>          * We already have cpus for evsel (via PMU sysfs) so
> >>          * keep it, if there's no target cpu list defined.
> >>          */
> >> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
> >> -               perf_cpu_map__put(evsel->cpus);
> >> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >> -       } else if (!evsel->system_wide &&
> >> -                  !evsel->requires_cpu &&
> >> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
> >> +       if (!evsel->own_cpus ||
> >> +           (!evsel->system_wide && evlist->has_user_cpus) ||
> >> +           (!evsel->system_wide &&
> >> +            !evsel->requires_cpu &&
> >> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
> >
> > This is getting hard to understand.  IIUC this propagation basically
> > sets user requested cpus to evsel unless it has its own cpus, right?
>
> I put the conditional logic altogether because that is kernel style but
> it does make it practically unreadable.
>
> If we start with the original logic:
>
>         if (!evsel->own_cpus || evlist->has_user_cpus) {
>                 perf_cpu_map__put(evsel->cpus);
>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>         } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>                 perf_cpu_map__put(evsel->cpus);
>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>         } else if (evsel->cpus != evsel->own_cpus) {
>                 perf_cpu_map__put(evsel->cpus);
>                 evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>         }
>
> Then make it more readable, i.e. same functionality
>
>         struct perf_cpu_map *cpus;
>
>         if (!evsel->own_cpus || evlist->has_user_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
>         if (evsel->cpus != cpus) {
>                 perf_cpu_map__put(evsel->cpus);
>                 evsel->cpus = perf_cpu_map__get(cpus);
>         }
>
> Then separate out the conditions, i.e. still same functionality
>
>         if (!evsel->own_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (evlist->has_user_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (evsel->system_wide)
>                 cpus = evsel->own_cpus;
>         else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
> Then add the new requires_cpu flag:
>
>         if (!evsel->own_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (evlist->has_user_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (evsel->system_wide)
>                 cpus = evsel->own_cpus;
> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
> Then make system_wide keep own_cpus even if has_user_cpus:
>
>         if (!evsel->own_cpus)
>                 cpus = evlist->user_requested_cpus;
> +       else if (evsel->system_wide)
> +               cpus = evsel->own_cpus;
>         else if (evlist->has_user_cpus)
>                 cpus = evlist->user_requested_cpus;
> -       else if (evsel->system_wide)
> -               cpus = evsel->own_cpus;
>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
> Which leaves:
>
>         if (!evsel->own_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (evsel->system_wide)
>                 cpus = evsel->own_cpus;
>         else if (evlist->has_user_cpus)
>                 cpus = evlist->user_requested_cpus;
>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
> And putting it back together:
>
>         if (!evsel->own_cpus ||
>             (!evsel->system_wide && evlist->has_user_cpus) ||
>             (!evsel->system_wide &&
>              !evsel->requires_cpu &&
>              perf_cpu_map__empty(evlist->user_requested_cpus))) {
>                 cpus = evlist->user_requested_cpus;
>         else
>                 cpus = evsel->own_cpus;
>
> Perhaps I shouldn't put it together?

Cool, thanks a lot for explaining it in detail.
I do not oppose your change but little worried about the
complexity.  And I think we have some issues with uncore
events already.

So do you have any idea where evsel->own_cpus
doesn't propagate to evsel->cpus?

I think evsel->system_wide and evsel->requires_cpu
can be replaced to check evsel->own_cpus instead.

Actually evlist->has_user_cpus is checked first so
uncore events' own_cpus might not be used.

In my laptop, perf stat -a -A -e imc/data_reads/
will use cpu 0 as it's listed in the pmu cpumask.
But when I use -C1,2 it'll use the both cpus and
returns the similar values each (so the sum is 2x).

I'm not sure if it's intended.  I expect it runs on
cpu 0 or one of the given cpus.  Or it runs on both
cpus and returns value in half so that the sum is
the same as the original value (from a cpu).

>
> >
> > But the hybrid pmus make this complex.  Maybe we can move the
> > logic in evlist__fix_hybrid_cpus() here and simplify it like below
> >
> > if (evsel->own_cpus) {
> >    if (evsel->pmu->is_hybrid)
> >       evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
> >                                       evlist->user_requested_cpus);  //?
> >    else
> >       evsel->cpus = evlist->own_cpus;  // put + get
> > } else {
> >    evsel->cpus = evlist->user_requested_cpus;  // put + get
> > }
> >
> > Then we need to make sure evsel->pmu is set properly.
> >
> > What do you think?
>
> Hybrid handling looks complicated.  I would have to spend time
> better understanding it.
>
> So, in the context of this patch set, I don't want to look at
> issues with hybrid CPUs, except that there should be no change
> to how they are handled.

Fair enough.  But I think we have to look at it again soon.

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-12 18:53       ` Namhyung Kim
@ 2022-05-13  4:48         ` Adrian Hunter
  2022-05-13 14:12           ` Liang, Kan
  2022-05-14 13:35           ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 70+ messages in thread
From: Adrian Hunter @ 2022-05-13  4:48 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian,
	Kan Liang

On 12/05/22 21:53, Namhyung Kim wrote:
> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 12/05/22 08:27, Namhyung Kim wrote:
>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>> CPUs and they are added to all_cpus.
>>>>
>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>> ---
>>>>  tools/lib/perf/evlist.c | 11 +++++------
>>>>  1 file changed, 5 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>> index 1c801f8da44f..9a6801b53274 100644
>>>> --- a/tools/lib/perf/evlist.c
>>>> +++ b/tools/lib/perf/evlist.c
>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>          * We already have cpus for evsel (via PMU sysfs) so
>>>>          * keep it, if there's no target cpu list defined.
>>>>          */
>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>> -               perf_cpu_map__put(evsel->cpus);
>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>> -       } else if (!evsel->system_wide &&
>>>> -                  !evsel->requires_cpu &&
>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>> +       if (!evsel->own_cpus ||
>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>> +           (!evsel->system_wide &&
>>>> +            !evsel->requires_cpu &&
>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>
>>> This is getting hard to understand.  IIUC this propagation basically
>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>
>> I put the conditional logic altogether because that is kernel style but
>> it does make it practically unreadable.
>>
>> If we start with the original logic:
>>
>>         if (!evsel->own_cpus || evlist->has_user_cpus) {
>>                 perf_cpu_map__put(evsel->cpus);
>>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>         } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>                 perf_cpu_map__put(evsel->cpus);
>>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>         } else if (evsel->cpus != evsel->own_cpus) {
>>                 perf_cpu_map__put(evsel->cpus);
>>                 evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>         }
>>
>> Then make it more readable, i.e. same functionality
>>
>>         struct perf_cpu_map *cpus;
>>
>>         if (!evsel->own_cpus || evlist->has_user_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>>         if (evsel->cpus != cpus) {
>>                 perf_cpu_map__put(evsel->cpus);
>>                 evsel->cpus = perf_cpu_map__get(cpus);
>>         }
>>
>> Then separate out the conditions, i.e. still same functionality
>>
>>         if (!evsel->own_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (evlist->has_user_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (evsel->system_wide)
>>                 cpus = evsel->own_cpus;
>>         else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>> Then add the new requires_cpu flag:
>>
>>         if (!evsel->own_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (evlist->has_user_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (evsel->system_wide)
>>                 cpus = evsel->own_cpus;
>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>> Then make system_wide keep own_cpus even if has_user_cpus:
>>
>>         if (!evsel->own_cpus)
>>                 cpus = evlist->user_requested_cpus;
>> +       else if (evsel->system_wide)
>> +               cpus = evsel->own_cpus;
>>         else if (evlist->has_user_cpus)
>>                 cpus = evlist->user_requested_cpus;
>> -       else if (evsel->system_wide)
>> -               cpus = evsel->own_cpus;
>>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>> Which leaves:
>>
>>         if (!evsel->own_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (evsel->system_wide)
>>                 cpus = evsel->own_cpus;
>>         else if (evlist->has_user_cpus)
>>                 cpus = evlist->user_requested_cpus;
>>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>> And putting it back together:
>>
>>         if (!evsel->own_cpus ||
>>             (!evsel->system_wide && evlist->has_user_cpus) ||
>>             (!evsel->system_wide &&
>>              !evsel->requires_cpu &&
>>              perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>                 cpus = evlist->user_requested_cpus;
>>         else
>>                 cpus = evsel->own_cpus;
>>
>> Perhaps I shouldn't put it together?
> 
> Cool, thanks a lot for explaining it in detail.
> I do not oppose your change but little worried about the
> complexity.  And I think we have some issues with uncore
> events already.

Yes it is a bit complicated because we are handling
many different use cases.

> 
> So do you have any idea where evsel->own_cpus
> doesn't propagate to evsel->cpus?

We let the user's list of CPUs override it i.e. the
evlist->has_user_cpus case.  Essentially we are expecting
the user to know what they are doing.

> 
> I think evsel->system_wide and evsel->requires_cpu
> can be replaced to check evsel->own_cpus instead.

Not at the moment because we let the user override
own_cpus.

> 
> Actually evlist->has_user_cpus is checked first so
> uncore events' own_cpus might not be used.

Yes

> 
> In my laptop, perf stat -a -A -e imc/data_reads/
> will use cpu 0 as it's listed in the pmu cpumask.
> But when I use -C1,2 it'll use the both cpus and
> returns the similar values each (so the sum is 2x).

We expect the user to understand the uncore PMU they
are using.  AFAICT an uncore PMU cpu mask with only
CPU 0 typically means a single PMU that counts events
that could be indrectly caused by any CPU.  When the
cpu mask has more than one CPU, it means a PMU for
each of a group of CPU's (e.g. a core or socket)

So in the example you gave above, there is only 1 PMU
and reading from any CPU will give it's value.

A user providing a list of CPUs for uncore events
is useful only in certain cases.  For example when
each core has an uncore PMU and you only want to get
values from one core.

> 
> I'm not sure if it's intended.  I expect it runs on
> cpu 0 or one of the given cpus.  Or it runs on both
> cpus and returns value in half so that the sum is
> the same as the original value (from a cpu).

I don't know if there is anything wrong with the way
we are handling uncore PMUs, except that I don't know
if it is documented anywhere.

> 
>>
>>>
>>> But the hybrid pmus make this complex.  Maybe we can move the
>>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
>>>
>>> if (evsel->own_cpus) {
>>>    if (evsel->pmu->is_hybrid)
>>>       evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>>>                                       evlist->user_requested_cpus);  //?
>>>    else
>>>       evsel->cpus = evlist->own_cpus;  // put + get
>>> } else {
>>>    evsel->cpus = evlist->user_requested_cpus;  // put + get
>>> }
>>>
>>> Then we need to make sure evsel->pmu is set properly.
>>>
>>> What do you think?
>>
>> Hybrid handling looks complicated.  I would have to spend time
>> better understanding it.
>>
>> So, in the context of this patch set, I don't want to look at
>> issues with hybrid CPUs, except that there should be no change
>> to how they are handled.
> 
> Fair enough.  But I think we have to look at it again soon.
> 
> Thanks,
> Namhyung


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13  4:48         ` Adrian Hunter
@ 2022-05-13 14:12           ` Liang, Kan
  2022-05-13 15:21             ` Adrian Hunter
  2022-05-14 13:35           ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 70+ messages in thread
From: Liang, Kan @ 2022-05-13 14:12 UTC (permalink / raw)
  To: Adrian Hunter, Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian



On 5/13/2022 12:48 AM, Adrian Hunter wrote:
> On 12/05/22 21:53, Namhyung Kim wrote:
>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>
>>> On 12/05/22 08:27, Namhyung Kim wrote:
>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>
>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>>> CPUs and they are added to all_cpus.
>>>>>
>>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>> ---
>>>>>   tools/lib/perf/evlist.c | 11 +++++------
>>>>>   1 file changed, 5 insertions(+), 6 deletions(-)
>>>>>
>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>>> index 1c801f8da44f..9a6801b53274 100644
>>>>> --- a/tools/lib/perf/evlist.c
>>>>> +++ b/tools/lib/perf/evlist.c
>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>>           * We already have cpus for evsel (via PMU sysfs) so
>>>>>           * keep it, if there's no target cpu list defined.
>>>>>           */
>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>> -               perf_cpu_map__put(evsel->cpus);
>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>> -       } else if (!evsel->system_wide &&
>>>>> -                  !evsel->requires_cpu &&
>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>> +       if (!evsel->own_cpus ||
>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>> +           (!evsel->system_wide &&
>>>>> +            !evsel->requires_cpu &&
>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>
>>>> This is getting hard to understand.  IIUC this propagation basically
>>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>>
>>> I put the conditional logic altogether because that is kernel style but
>>> it does make it practically unreadable.
>>>
>>> If we start with the original logic:
>>>
>>>          if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>                  perf_cpu_map__put(evsel->cpus);
>>>                  evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>          } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>                  perf_cpu_map__put(evsel->cpus);
>>>                  evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>          } else if (evsel->cpus != evsel->own_cpus) {
>>>                  perf_cpu_map__put(evsel->cpus);
>>>                  evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>>          }
>>>
>>> Then make it more readable, i.e. same functionality
>>>
>>>          struct perf_cpu_map *cpus;
>>>
>>>          if (!evsel->own_cpus || evlist->has_user_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>>          if (evsel->cpus != cpus) {
>>>                  perf_cpu_map__put(evsel->cpus);
>>>                  evsel->cpus = perf_cpu_map__get(cpus);
>>>          }
>>>
>>> Then separate out the conditions, i.e. still same functionality
>>>
>>>          if (!evsel->own_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (evlist->has_user_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (evsel->system_wide)
>>>                  cpus = evsel->own_cpus;
>>>          else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>> Then add the new requires_cpu flag:
>>>
>>>          if (!evsel->own_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (evlist->has_user_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (evsel->system_wide)
>>>                  cpus = evsel->own_cpus;
>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>> Then make system_wide keep own_cpus even if has_user_cpus:
>>>
>>>          if (!evsel->own_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>> +       else if (evsel->system_wide)
>>> +               cpus = evsel->own_cpus;
>>>          else if (evlist->has_user_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>> -       else if (evsel->system_wide)
>>> -               cpus = evsel->own_cpus;
>>>          else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>> Which leaves:
>>>
>>>          if (!evsel->own_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (evsel->system_wide)
>>>                  cpus = evsel->own_cpus;
>>>          else if (evlist->has_user_cpus)
>>>                  cpus = evlist->user_requested_cpus;
>>>          else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>> And putting it back together:
>>>
>>>          if (!evsel->own_cpus ||
>>>              (!evsel->system_wide && evlist->has_user_cpus) ||
>>>              (!evsel->system_wide &&
>>>               !evsel->requires_cpu &&
>>>               perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>                  cpus = evlist->user_requested_cpus;
>>>          else
>>>                  cpus = evsel->own_cpus;
>>>
>>> Perhaps I shouldn't put it together?
>>
>> Cool, thanks a lot for explaining it in detail.
>> I do not oppose your change but little worried about the
>> complexity.  And I think we have some issues with uncore
>> events already.
> 
> Yes it is a bit complicated because we are handling
> many different use cases.
> 
>>
>> So do you have any idea where evsel->own_cpus
>> doesn't propagate to evsel->cpus?
> 
> We let the user's list of CPUs override it i.e. the
> evlist->has_user_cpus case.  Essentially we are expecting
> the user to know what they are doing.
> 
>>
>> I think evsel->system_wide and evsel->requires_cpu
>> can be replaced to check evsel->own_cpus instead.
> 
> Not at the moment because we let the user override
> own_cpus.

Do we check whether the user's input is valid (match the PMU's cpumask) 
before the override?

I think we know the PMU name. The cpumask of the PMU can be found in the 
sysfs. So we should have enough information for a sanity check.


> 
>>
>> Actually evlist->has_user_cpus is checked first so
>> uncore events' own_cpus might not be used.
> 
> Yes
> 
>>
>> In my laptop, perf stat -a -A -e imc/data_reads/
>> will use cpu 0 as it's listed in the pmu cpumask.
>> But when I use -C1,2 it'll use the both cpus and
>> returns the similar values each (so the sum is 2x).
> 
> We expect the user to understand the uncore PMU they
> are using.  AFAICT an uncore PMU cpu mask with only
> CPU 0 typically means a single PMU that counts events
> that could be indrectly caused by any CPU.  When the
> cpu mask has more than one CPU, it means a PMU for
> each of a group of CPU's (e.g. a core or socket)
> 
> So in the example you gave above, there is only 1 PMU
> and reading from any CPU will give it's value.
> 
> A user providing a list of CPUs for uncore events
> is useful only in certain cases.  For example when
> each core has an uncore PMU and you only want to get
> values from one core.
>
>>
>> I'm not sure if it's intended.  I expect it runs on
>> cpu 0 or one of the given cpus.  Or it runs on both
>> cpus and returns value in half so that the sum is
>> the same as the original value (from a cpu).

It runs on CPU0. The kernel will correct the CPU when initializing the 
event. The uncore is per-die (For the most current platforms, die is the 
same as socket.). Usually, it runs on the first CPU of a die.
For the -C 1,2 uncore/event/ case, the current tool creates two events. 
One for each CPU. The kernel will find the die ID of the input CPU 
first, then correct it to the first CPU of the die, which is 0.
So from the kernel's perspective, the perf command turns to -C0 
uncore/event/ -C0 uncore/event/. That's why you see similar values each. 
(They should not be exactly the same. That's because they are not in a 
group.)


> 
> I don't know if there is anything wrong with the way
> we are handling uncore PMUs, except that I don't know
> if it is documented anywhere.

Right, we are lacking of the document for the cpumask. I guess I can 
update it in the 
Documentation/ABI/testing/sysfs-bus-event_source-devices-uncore. But 
it's only for the developer.

At the meantime, I think it may be better to show an error/warning if 
the user inputs are not matched with the cpumask of the requested PMU. 
That's for the end users.

> 
>>
>>>
>>>>
>>>> But the hybrid pmus make this complex.  Maybe we can move the
>>>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
>>>>
>>>> if (evsel->own_cpus) {
>>>>     if (evsel->pmu->is_hybrid)
>>>>        evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>>>>                                        evlist->user_requested_cpus);  //?
>>>>     else
>>>>        evsel->cpus = evlist->own_cpus;  // put + get
>>>> } else {
>>>>     evsel->cpus = evlist->user_requested_cpus;  // put + get
>>>> }
>>>>
>>>> Then we need to make sure evsel->pmu is set properly.
>>>>
>>>> What do you think?
>>>
>>> Hybrid handling looks complicated.  I would have to spend time
>>> better understanding it.
>>>
>>> So, in the context of this patch set, I don't want to look at
>>> issues with hybrid CPUs, except that there should be no change
>>> to how they are handled.
>>

I think we should at least run perf test on a hybrid machine. We already 
have some backlog to handle. It's better not to bring more regression issue.

Thanks,Kan




^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13 14:12           ` Liang, Kan
@ 2022-05-13 15:21             ` Adrian Hunter
  2022-05-13 15:46               ` Liang, Kan
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-13 15:21 UTC (permalink / raw)
  To: Liang, Kan, Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian

On 13/05/22 17:12, Liang, Kan wrote:
> 
> 
> On 5/13/2022 12:48 AM, Adrian Hunter wrote:
>> On 12/05/22 21:53, Namhyung Kim wrote:
>>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>
>>>> On 12/05/22 08:27, Namhyung Kim wrote:
>>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>
>>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>>>> CPUs and they are added to all_cpus.
>>>>>>
>>>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>>> ---
>>>>>>   tools/lib/perf/evlist.c | 11 +++++------
>>>>>>   1 file changed, 5 insertions(+), 6 deletions(-)
>>>>>>
>>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>>>> index 1c801f8da44f..9a6801b53274 100644
>>>>>> --- a/tools/lib/perf/evlist.c
>>>>>> +++ b/tools/lib/perf/evlist.c
>>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>>>           * We already have cpus for evsel (via PMU sysfs) so
>>>>>>           * keep it, if there's no target cpu list defined.
>>>>>>           */
>>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>> -               perf_cpu_map__put(evsel->cpus);
>>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>> -       } else if (!evsel->system_wide &&
>>>>>> -                  !evsel->requires_cpu &&
>>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>> +       if (!evsel->own_cpus ||
>>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>> +           (!evsel->system_wide &&
>>>>>> +            !evsel->requires_cpu &&
>>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>
>>>>> This is getting hard to understand.  IIUC this propagation basically
>>>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>>>
>>>> I put the conditional logic altogether because that is kernel style but
>>>> it does make it practically unreadable.
>>>>
>>>> If we start with the original logic:
>>>>
>>>>          if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>                  perf_cpu_map__put(evsel->cpus);
>>>>                  evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>          } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>                  perf_cpu_map__put(evsel->cpus);
>>>>                  evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>          } else if (evsel->cpus != evsel->own_cpus) {
>>>>                  perf_cpu_map__put(evsel->cpus);
>>>>                  evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>>>          }
>>>>
>>>> Then make it more readable, i.e. same functionality
>>>>
>>>>          struct perf_cpu_map *cpus;
>>>>
>>>>          if (!evsel->own_cpus || evlist->has_user_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>>          if (evsel->cpus != cpus) {
>>>>                  perf_cpu_map__put(evsel->cpus);
>>>>                  evsel->cpus = perf_cpu_map__get(cpus);
>>>>          }
>>>>
>>>> Then separate out the conditions, i.e. still same functionality
>>>>
>>>>          if (!evsel->own_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (evlist->has_user_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (evsel->system_wide)
>>>>                  cpus = evsel->own_cpus;
>>>>          else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>> Then add the new requires_cpu flag:
>>>>
>>>>          if (!evsel->own_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (evlist->has_user_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (evsel->system_wide)
>>>>                  cpus = evsel->own_cpus;
>>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>> Then make system_wide keep own_cpus even if has_user_cpus:
>>>>
>>>>          if (!evsel->own_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>> +       else if (evsel->system_wide)
>>>> +               cpus = evsel->own_cpus;
>>>>          else if (evlist->has_user_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>> -       else if (evsel->system_wide)
>>>> -               cpus = evsel->own_cpus;
>>>>          else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>> Which leaves:
>>>>
>>>>          if (!evsel->own_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (evsel->system_wide)
>>>>                  cpus = evsel->own_cpus;
>>>>          else if (evlist->has_user_cpus)
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>> And putting it back together:
>>>>
>>>>          if (!evsel->own_cpus ||
>>>>              (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>              (!evsel->system_wide &&
>>>>               !evsel->requires_cpu &&
>>>>               perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>                  cpus = evlist->user_requested_cpus;
>>>>          else
>>>>                  cpus = evsel->own_cpus;
>>>>
>>>> Perhaps I shouldn't put it together?
>>>
>>> Cool, thanks a lot for explaining it in detail.
>>> I do not oppose your change but little worried about the
>>> complexity.  And I think we have some issues with uncore
>>> events already.
>>
>> Yes it is a bit complicated because we are handling
>> many different use cases.
>>
>>>
>>> So do you have any idea where evsel->own_cpus
>>> doesn't propagate to evsel->cpus?
>>
>> We let the user's list of CPUs override it i.e. the
>> evlist->has_user_cpus case.  Essentially we are expecting
>> the user to know what they are doing.
>>
>>>
>>> I think evsel->system_wide and evsel->requires_cpu
>>> can be replaced to check evsel->own_cpus instead.
>>
>> Not at the moment because we let the user override
>> own_cpus.
> 
> Do we check whether the user's input is valid (match the PMU's cpumask) before the override?
> 
> I think we know the PMU name. The cpumask of the PMU can be found in the sysfs. So we should have enough information for a sanity check.

For the uncore PMU case, I am not sure what sanity is :-)

I don't know about the hybrid case.  I suspect it doesn't
work because it would need to intersect own_cpus with
user_requested_cpus if has_user_cpus, wouldn't it?

> 
> 
>>
>>>
>>> Actually evlist->has_user_cpus is checked first so
>>> uncore events' own_cpus might not be used.
>>
>> Yes
>>
>>>
>>> In my laptop, perf stat -a -A -e imc/data_reads/
>>> will use cpu 0 as it's listed in the pmu cpumask.
>>> But when I use -C1,2 it'll use the both cpus and
>>> returns the similar values each (so the sum is 2x).
>>
>> We expect the user to understand the uncore PMU they
>> are using.  AFAICT an uncore PMU cpu mask with only
>> CPU 0 typically means a single PMU that counts events
>> that could be indrectly caused by any CPU.  When the
>> cpu mask has more than one CPU, it means a PMU for
>> each of a group of CPU's (e.g. a core or socket)
>>
>> So in the example you gave above, there is only 1 PMU
>> and reading from any CPU will give it's value.
>>
>> A user providing a list of CPUs for uncore events
>> is useful only in certain cases.  For example when
>> each core has an uncore PMU and you only want to get
>> values from one core.
>>
>>>
>>> I'm not sure if it's intended.  I expect it runs on
>>> cpu 0 or one of the given cpus.  Or it runs on both
>>> cpus and returns value in half so that the sum is
>>> the same as the original value (from a cpu).
> 
> It runs on CPU0. The kernel will correct the CPU when initializing the event. The uncore is per-die (For the most current platforms, die is the same as socket.). Usually, it runs on the first CPU of a die.
> For the -C 1,2 uncore/event/ case, the current tool creates two events. One for each CPU. The kernel will find the die ID of the input CPU first, then correct it to the first CPU of the die, which is 0.
> So from the kernel's perspective, the perf command turns to -C0 uncore/event/ -C0 uncore/event/. That's why you see similar values each. (They should not be exactly the same. That's because they are not in a group.)
> 
> 
>>
>> I don't know if there is anything wrong with the way
>> we are handling uncore PMUs, except that I don't know
>> if it is documented anywhere.
> 
> Right, we are lacking of the document for the cpumask. I guess I can update it in the Documentation/ABI/testing/sysfs-bus-event_source-devices-uncore. But it's only for the developer.
> 
> At the meantime, I think it may be better to show an error/warning if the user inputs are not matched with the cpumask of the requested PMU. That's for the end users.
> 
>>
>>>
>>>>
>>>>>
>>>>> But the hybrid pmus make this complex.  Maybe we can move the
>>>>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
>>>>>
>>>>> if (evsel->own_cpus) {
>>>>>     if (evsel->pmu->is_hybrid)
>>>>>        evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>>>>>                                        evlist->user_requested_cpus);  //?
>>>>>     else
>>>>>        evsel->cpus = evlist->own_cpus;  // put + get
>>>>> } else {
>>>>>     evsel->cpus = evlist->user_requested_cpus;  // put + get
>>>>> }
>>>>>
>>>>> Then we need to make sure evsel->pmu is set properly.
>>>>>
>>>>> What do you think?
>>>>
>>>> Hybrid handling looks complicated.  I would have to spend time
>>>> better understanding it.
>>>>
>>>> So, in the context of this patch set, I don't want to look at
>>>> issues with hybrid CPUs, except that there should be no change
>>>> to how they are handled.
>>>
> 
> I think we should at least run perf test on a hybrid machine. We already have some backlog to handle. It's better not to bring more regression issue.
> 
> Thanks,Kan
> 
> 
> 


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13 15:21             ` Adrian Hunter
@ 2022-05-13 15:46               ` Liang, Kan
  2022-05-13 16:11                 ` Adrian Hunter
  0 siblings, 1 reply; 70+ messages in thread
From: Liang, Kan @ 2022-05-13 15:46 UTC (permalink / raw)
  To: Adrian Hunter, Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian



On 5/13/2022 11:21 AM, Adrian Hunter wrote:
> On 13/05/22 17:12, Liang, Kan wrote:
>>
>>
>> On 5/13/2022 12:48 AM, Adrian Hunter wrote:
>>> On 12/05/22 21:53, Namhyung Kim wrote:
>>>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>
>>>>> On 12/05/22 08:27, Namhyung Kim wrote:
>>>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>>
>>>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>>>>> CPUs and they are added to all_cpus.
>>>>>>>
>>>>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>>>> ---
>>>>>>>    tools/lib/perf/evlist.c | 11 +++++------
>>>>>>>    1 file changed, 5 insertions(+), 6 deletions(-)
>>>>>>>
>>>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>>>>> index 1c801f8da44f..9a6801b53274 100644
>>>>>>> --- a/tools/lib/perf/evlist.c
>>>>>>> +++ b/tools/lib/perf/evlist.c
>>>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>>>>            * We already have cpus for evsel (via PMU sysfs) so
>>>>>>>            * keep it, if there's no target cpu list defined.
>>>>>>>            */
>>>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>>> -               perf_cpu_map__put(evsel->cpus);
>>>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>> -       } else if (!evsel->system_wide &&
>>>>>>> -                  !evsel->requires_cpu &&
>>>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>>> +       if (!evsel->own_cpus ||
>>>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>>> +           (!evsel->system_wide &&
>>>>>>> +            !evsel->requires_cpu &&
>>>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>>
>>>>>> This is getting hard to understand.  IIUC this propagation basically
>>>>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>>>>
>>>>> I put the conditional logic altogether because that is kernel style but
>>>>> it does make it practically unreadable.
>>>>>
>>>>> If we start with the original logic:
>>>>>
>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>           } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>           } else if (evsel->cpus != evsel->own_cpus) {
>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>                   evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>>>>           }
>>>>>
>>>>> Then make it more readable, i.e. same functionality
>>>>>
>>>>>           struct perf_cpu_map *cpus;
>>>>>
>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>>           if (evsel->cpus != cpus) {
>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>                   evsel->cpus = perf_cpu_map__get(cpus);
>>>>>           }
>>>>>
>>>>> Then separate out the conditions, i.e. still same functionality
>>>>>
>>>>>           if (!evsel->own_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (evlist->has_user_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (evsel->system_wide)
>>>>>                   cpus = evsel->own_cpus;
>>>>>           else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>> Then add the new requires_cpu flag:
>>>>>
>>>>>           if (!evsel->own_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (evlist->has_user_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (evsel->system_wide)
>>>>>                   cpus = evsel->own_cpus;
>>>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>> Then make system_wide keep own_cpus even if has_user_cpus:
>>>>>
>>>>>           if (!evsel->own_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>> +       else if (evsel->system_wide)
>>>>> +               cpus = evsel->own_cpus;
>>>>>           else if (evlist->has_user_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>> -       else if (evsel->system_wide)
>>>>> -               cpus = evsel->own_cpus;
>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>> Which leaves:
>>>>>
>>>>>           if (!evsel->own_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (evsel->system_wide)
>>>>>                   cpus = evsel->own_cpus;
>>>>>           else if (evlist->has_user_cpus)
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>> And putting it back together:
>>>>>
>>>>>           if (!evsel->own_cpus ||
>>>>>               (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>               (!evsel->system_wide &&
>>>>>                !evsel->requires_cpu &&
>>>>>                perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>           else
>>>>>                   cpus = evsel->own_cpus;
>>>>>
>>>>> Perhaps I shouldn't put it together?
>>>>
>>>> Cool, thanks a lot for explaining it in detail.
>>>> I do not oppose your change but little worried about the
>>>> complexity.  And I think we have some issues with uncore
>>>> events already.
>>>
>>> Yes it is a bit complicated because we are handling
>>> many different use cases.
>>>
>>>>
>>>> So do you have any idea where evsel->own_cpus
>>>> doesn't propagate to evsel->cpus?
>>>
>>> We let the user's list of CPUs override it i.e. the
>>> evlist->has_user_cpus case.  Essentially we are expecting
>>> the user to know what they are doing.
>>>
>>>>
>>>> I think evsel->system_wide and evsel->requires_cpu
>>>> can be replaced to check evsel->own_cpus instead.
>>>
>>> Not at the moment because we let the user override
>>> own_cpus.
>>
>> Do we check whether the user's input is valid (match the PMU's cpumask) before the override?
>>
>> I think we know the PMU name. The cpumask of the PMU can be found in the sysfs. So we should have enough information for a sanity check.
> 
> For the uncore PMU case, I am not sure what sanity is :-)
> 

For a non-core PMU, e.g., uncore, cstate, power and etc. The cpumask is 
under the /sys/devices/<PMU>/cpumask. It shows the cpumask which kernel 
supports. If a end user request a different CPU other that the cpumask, 
I think it's better throw a waning. It should mitigate the confusion 
which Namhyung mentioned (uncore -C1,2).

> I don't know about the hybrid case.  I suspect it doesn't
> work because it would need to intersect own_cpus with
> user_requested_cpus if has_user_cpus, wouldn't it?

For the hybrid, the cpumask is named as "cpus" under the sysfs. The name 
is the same for both X86 and Arm.
The current kernel will filter out the CPU which is not in the cpumask.
For the tool, I think we can throw a warning as well if the user 
requests the unsupported CPU.

Actually, there is already a patch to check and print a warning for the 
hybrid group. See commit 660e533e87ff ("perf stat: Warn group events 
from different hybrid PMU"), but it's X86 specific.

Maybe we can introduce a generic way by checking the "cpus" of the core 
PMU for both X86 and Arm. Then the above patch may be dropped.

Thanks,
Kan

> 
>>
>>
>>>
>>>>
>>>> Actually evlist->has_user_cpus is checked first so
>>>> uncore events' own_cpus might not be used.
>>>
>>> Yes
>>>
>>>>
>>>> In my laptop, perf stat -a -A -e imc/data_reads/
>>>> will use cpu 0 as it's listed in the pmu cpumask.
>>>> But when I use -C1,2 it'll use the both cpus and
>>>> returns the similar values each (so the sum is 2x).
>>>
>>> We expect the user to understand the uncore PMU they
>>> are using.  AFAICT an uncore PMU cpu mask with only
>>> CPU 0 typically means a single PMU that counts events
>>> that could be indrectly caused by any CPU.  When the
>>> cpu mask has more than one CPU, it means a PMU for
>>> each of a group of CPU's (e.g. a core or socket)
>>>
>>> So in the example you gave above, there is only 1 PMU
>>> and reading from any CPU will give it's value.
>>>
>>> A user providing a list of CPUs for uncore events
>>> is useful only in certain cases.  For example when
>>> each core has an uncore PMU and you only want to get
>>> values from one core.
>>>
>>>>
>>>> I'm not sure if it's intended.  I expect it runs on
>>>> cpu 0 or one of the given cpus.  Or it runs on both
>>>> cpus and returns value in half so that the sum is
>>>> the same as the original value (from a cpu).
>>
>> It runs on CPU0. The kernel will correct the CPU when initializing the event. The uncore is per-die (For the most current platforms, die is the same as socket.). Usually, it runs on the first CPU of a die.
>> For the -C 1,2 uncore/event/ case, the current tool creates two events. One for each CPU. The kernel will find the die ID of the input CPU first, then correct it to the first CPU of the die, which is 0.
>> So from the kernel's perspective, the perf command turns to -C0 uncore/event/ -C0 uncore/event/. That's why you see similar values each. (They should not be exactly the same. That's because they are not in a group.)
>>
>>
>>>
>>> I don't know if there is anything wrong with the way
>>> we are handling uncore PMUs, except that I don't know
>>> if it is documented anywhere.
>>
>> Right, we are lacking of the document for the cpumask. I guess I can update it in the Documentation/ABI/testing/sysfs-bus-event_source-devices-uncore. But it's only for the developer.
>>
>> At the meantime, I think it may be better to show an error/warning if the user inputs are not matched with the cpumask of the requested PMU. That's for the end users.
>>
>>>
>>>>
>>>>>
>>>>>>
>>>>>> But the hybrid pmus make this complex.  Maybe we can move the
>>>>>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
>>>>>>
>>>>>> if (evsel->own_cpus) {
>>>>>>      if (evsel->pmu->is_hybrid)
>>>>>>         evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>>>>>>                                         evlist->user_requested_cpus);  //?
>>>>>>      else
>>>>>>         evsel->cpus = evlist->own_cpus;  // put + get
>>>>>> } else {
>>>>>>      evsel->cpus = evlist->user_requested_cpus;  // put + get
>>>>>> }
>>>>>>
>>>>>> Then we need to make sure evsel->pmu is set properly.
>>>>>>
>>>>>> What do you think?
>>>>>
>>>>> Hybrid handling looks complicated.  I would have to spend time
>>>>> better understanding it.
>>>>>
>>>>> So, in the context of this patch set, I don't want to look at
>>>>> issues with hybrid CPUs, except that there should be no change
>>>>> to how they are handled.
>>>>
>>
>> I think we should at least run perf test on a hybrid machine. We already have some backlog to handle. It's better not to bring more regression issue.
>>
>> Thanks,Kan
>>
>>
>>
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13 15:46               ` Liang, Kan
@ 2022-05-13 16:11                 ` Adrian Hunter
  2022-05-13 16:42                   ` Namhyung Kim
  0 siblings, 1 reply; 70+ messages in thread
From: Adrian Hunter @ 2022-05-13 16:11 UTC (permalink / raw)
  To: Liang, Kan
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian,
	Namhyung Kim

On 13/05/22 18:46, Liang, Kan wrote:
> 
> 
> On 5/13/2022 11:21 AM, Adrian Hunter wrote:
>> On 13/05/22 17:12, Liang, Kan wrote:
>>>
>>>
>>> On 5/13/2022 12:48 AM, Adrian Hunter wrote:
>>>> On 12/05/22 21:53, Namhyung Kim wrote:
>>>>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>
>>>>>> On 12/05/22 08:27, Namhyung Kim wrote:
>>>>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>>>
>>>>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>>>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>>>>>> CPUs and they are added to all_cpus.
>>>>>>>>
>>>>>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>>>>> ---
>>>>>>>>    tools/lib/perf/evlist.c | 11 +++++------
>>>>>>>>    1 file changed, 5 insertions(+), 6 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>>>>>> index 1c801f8da44f..9a6801b53274 100644
>>>>>>>> --- a/tools/lib/perf/evlist.c
>>>>>>>> +++ b/tools/lib/perf/evlist.c
>>>>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>>>>>            * We already have cpus for evsel (via PMU sysfs) so
>>>>>>>>            * keep it, if there's no target cpu list defined.
>>>>>>>>            */
>>>>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>>>> -               perf_cpu_map__put(evsel->cpus);
>>>>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>>> -       } else if (!evsel->system_wide &&
>>>>>>>> -                  !evsel->requires_cpu &&
>>>>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>>>> +       if (!evsel->own_cpus ||
>>>>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>>>> +           (!evsel->system_wide &&
>>>>>>>> +            !evsel->requires_cpu &&
>>>>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>>>
>>>>>>> This is getting hard to understand.  IIUC this propagation basically
>>>>>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>>>>>
>>>>>> I put the conditional logic altogether because that is kernel style but
>>>>>> it does make it practically unreadable.
>>>>>>
>>>>>> If we start with the original logic:
>>>>>>
>>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>           } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>           } else if (evsel->cpus != evsel->own_cpus) {
>>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>>                   evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>>>>>           }
>>>>>>
>>>>>> Then make it more readable, i.e. same functionality
>>>>>>
>>>>>>           struct perf_cpu_map *cpus;
>>>>>>
>>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>>           if (evsel->cpus != cpus) {
>>>>>>                   perf_cpu_map__put(evsel->cpus);
>>>>>>                   evsel->cpus = perf_cpu_map__get(cpus);
>>>>>>           }
>>>>>>
>>>>>> Then separate out the conditions, i.e. still same functionality
>>>>>>
>>>>>>           if (!evsel->own_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (evlist->has_user_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (evsel->system_wide)
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>           else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>> Then add the new requires_cpu flag:
>>>>>>
>>>>>>           if (!evsel->own_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (evlist->has_user_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (evsel->system_wide)
>>>>>>                   cpus = evsel->own_cpus;
>>>>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>> Then make system_wide keep own_cpus even if has_user_cpus:
>>>>>>
>>>>>>           if (!evsel->own_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>> +       else if (evsel->system_wide)
>>>>>> +               cpus = evsel->own_cpus;
>>>>>>           else if (evlist->has_user_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>> -       else if (evsel->system_wide)
>>>>>> -               cpus = evsel->own_cpus;
>>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>> Which leaves:
>>>>>>
>>>>>>           if (!evsel->own_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (evsel->system_wide)
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>           else if (evlist->has_user_cpus)
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>> And putting it back together:
>>>>>>
>>>>>>           if (!evsel->own_cpus ||
>>>>>>               (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>>               (!evsel->system_wide &&
>>>>>>                !evsel->requires_cpu &&
>>>>>>                perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>>                   cpus = evlist->user_requested_cpus;
>>>>>>           else
>>>>>>                   cpus = evsel->own_cpus;
>>>>>>
>>>>>> Perhaps I shouldn't put it together?
>>>>>
>>>>> Cool, thanks a lot for explaining it in detail.
>>>>> I do not oppose your change but little worried about the
>>>>> complexity.  And I think we have some issues with uncore
>>>>> events already.
>>>>
>>>> Yes it is a bit complicated because we are handling
>>>> many different use cases.
>>>>
>>>>>
>>>>> So do you have any idea where evsel->own_cpus
>>>>> doesn't propagate to evsel->cpus?
>>>>
>>>> We let the user's list of CPUs override it i.e. the
>>>> evlist->has_user_cpus case.  Essentially we are expecting
>>>> the user to know what they are doing.
>>>>
>>>>>
>>>>> I think evsel->system_wide and evsel->requires_cpu
>>>>> can be replaced to check evsel->own_cpus instead.
>>>>
>>>> Not at the moment because we let the user override
>>>> own_cpus.
>>>
>>> Do we check whether the user's input is valid (match the PMU's cpumask) before the override?
>>>
>>> I think we know the PMU name. The cpumask of the PMU can be found in the sysfs. So we should have enough information for a sanity check.
>>
>> For the uncore PMU case, I am not sure what sanity is :-)
>>
> 
> For a non-core PMU, e.g., uncore, cstate, power and etc. The cpumask is under the /sys/devices/<PMU>/cpumask. It shows the cpumask which kernel supports. If a end user request a different CPU other that the cpumask, I think it's better throw a waning. It should mitigate the confusion which Namhyung mentioned (uncore -C1,2).

So you couldn't get uncore events unless you are also coincidentally wanting to trace CPU 0.

I guess really the requrement is not to perf_event_open() an uncore PMU more than once? 
To figure that out we'd need to be able map CPUs to uncore PMUs?

> 
>> I don't know about the hybrid case.  I suspect it doesn't
>> work because it would need to intersect own_cpus with
>> user_requested_cpus if has_user_cpus, wouldn't it?
> 
> For the hybrid, the cpumask is named as "cpus" under the sysfs. The name is the same for both X86 and Arm.
> The current kernel will filter out the CPU which is not in the cpumask.
> For the tool, I think we can throw a warning as well if the user requests the unsupported CPU.

Ok, I was assuming we were using atom and core PMUs at the same time, so if the user
asks for some of each that should be fine.

> 
> Actually, there is already a patch to check and print a warning for the hybrid group. See commit 660e533e87ff ("perf stat: Warn group events from different hybrid PMU"), but it's X86 specific.
> 
> Maybe we can introduce a generic way by checking the "cpus" of the core PMU for both X86 and Arm. Then the above patch may be dropped.
> 
> Thanks,
> Kan
> 
>>
>>>
>>>
>>>>
>>>>>
>>>>> Actually evlist->has_user_cpus is checked first so
>>>>> uncore events' own_cpus might not be used.
>>>>
>>>> Yes
>>>>
>>>>>
>>>>> In my laptop, perf stat -a -A -e imc/data_reads/
>>>>> will use cpu 0 as it's listed in the pmu cpumask.
>>>>> But when I use -C1,2 it'll use the both cpus and
>>>>> returns the similar values each (so the sum is 2x).
>>>>
>>>> We expect the user to understand the uncore PMU they
>>>> are using.  AFAICT an uncore PMU cpu mask with only
>>>> CPU 0 typically means a single PMU that counts events
>>>> that could be indrectly caused by any CPU.  When the
>>>> cpu mask has more than one CPU, it means a PMU for
>>>> each of a group of CPU's (e.g. a core or socket)
>>>>
>>>> So in the example you gave above, there is only 1 PMU
>>>> and reading from any CPU will give it's value.
>>>>
>>>> A user providing a list of CPUs for uncore events
>>>> is useful only in certain cases.  For example when
>>>> each core has an uncore PMU and you only want to get
>>>> values from one core.
>>>>
>>>>>
>>>>> I'm not sure if it's intended.  I expect it runs on
>>>>> cpu 0 or one of the given cpus.  Or it runs on both
>>>>> cpus and returns value in half so that the sum is
>>>>> the same as the original value (from a cpu).
>>>
>>> It runs on CPU0. The kernel will correct the CPU when initializing the event. The uncore is per-die (For the most current platforms, die is the same as socket.). Usually, it runs on the first CPU of a die.
>>> For the -C 1,2 uncore/event/ case, the current tool creates two events. One for each CPU. The kernel will find the die ID of the input CPU first, then correct it to the first CPU of the die, which is 0.
>>> So from the kernel's perspective, the perf command turns to -C0 uncore/event/ -C0 uncore/event/. That's why you see similar values each. (They should not be exactly the same. That's because they are not in a group.)
>>>
>>>
>>>>
>>>> I don't know if there is anything wrong with the way
>>>> we are handling uncore PMUs, except that I don't know
>>>> if it is documented anywhere.
>>>
>>> Right, we are lacking of the document for the cpumask. I guess I can update it in the Documentation/ABI/testing/sysfs-bus-event_source-devices-uncore. But it's only for the developer.
>>>
>>> At the meantime, I think it may be better to show an error/warning if the user inputs are not matched with the cpumask of the requested PMU. That's for the end users.
>>>
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>> But the hybrid pmus make this complex.  Maybe we can move the
>>>>>>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
>>>>>>>
>>>>>>> if (evsel->own_cpus) {
>>>>>>>      if (evsel->pmu->is_hybrid)
>>>>>>>         evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
>>>>>>>                                         evlist->user_requested_cpus);  //?
>>>>>>>      else
>>>>>>>         evsel->cpus = evlist->own_cpus;  // put + get
>>>>>>> } else {
>>>>>>>      evsel->cpus = evlist->user_requested_cpus;  // put + get
>>>>>>> }
>>>>>>>
>>>>>>> Then we need to make sure evsel->pmu is set properly.
>>>>>>>
>>>>>>> What do you think?
>>>>>>
>>>>>> Hybrid handling looks complicated.  I would have to spend time
>>>>>> better understanding it.
>>>>>>
>>>>>> So, in the context of this patch set, I don't want to look at
>>>>>> issues with hybrid CPUs, except that there should be no change
>>>>>> to how they are handled.
>>>>>
>>>
>>> I think we should at least run perf test on a hybrid machine. We already have some backlog to handle. It's better not to bring more regression issue.
>>>
>>> Thanks,Kan
>>>
>>>
>>>
>>


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13 16:11                 ` Adrian Hunter
@ 2022-05-13 16:42                   ` Namhyung Kim
  2022-05-13 17:32                     ` Liang, Kan
  0 siblings, 1 reply; 70+ messages in thread
From: Namhyung Kim @ 2022-05-13 16:42 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Liang, Kan, Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian

On Fri, May 13, 2022 at 9:11 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> On 13/05/22 18:46, Liang, Kan wrote:
> >
> >
> > On 5/13/2022 11:21 AM, Adrian Hunter wrote:
> >> On 13/05/22 17:12, Liang, Kan wrote:
> >>>
> >>>
> >>> On 5/13/2022 12:48 AM, Adrian Hunter wrote:
> >>>> On 12/05/22 21:53, Namhyung Kim wrote:
> >>>>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>>>
> >>>>>> On 12/05/22 08:27, Namhyung Kim wrote:
> >>>>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>>>>>
> >>>>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
> >>>>>>>> has_user_cpus. Change that so that system-wide events retain their own
> >>>>>>>> CPUs and they are added to all_cpus.
> >>>>>>>>
> >>>>>>>> Acked-by: Ian Rogers <irogers@google.com>
> >>>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >>>>>>>> ---
> >>>>>>>>    tools/lib/perf/evlist.c | 11 +++++------
> >>>>>>>>    1 file changed, 5 insertions(+), 6 deletions(-)
> >>>>>>>>
> >>>>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> >>>>>>>> index 1c801f8da44f..9a6801b53274 100644
> >>>>>>>> --- a/tools/lib/perf/evlist.c
> >>>>>>>> +++ b/tools/lib/perf/evlist.c
> >>>>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
> >>>>>>>>            * We already have cpus for evsel (via PMU sysfs) so
> >>>>>>>>            * keep it, if there's no target cpu list defined.
> >>>>>>>>            */
> >>>>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
> >>>>>>>> -               perf_cpu_map__put(evsel->cpus);
> >>>>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>>>>>>> -       } else if (!evsel->system_wide &&
> >>>>>>>> -                  !evsel->requires_cpu &&
> >>>>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
> >>>>>>>> +       if (!evsel->own_cpus ||
> >>>>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
> >>>>>>>> +           (!evsel->system_wide &&
> >>>>>>>> +            !evsel->requires_cpu &&
> >>>>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
> >>>>>>>
> >>>>>>> This is getting hard to understand.  IIUC this propagation basically
> >>>>>>> sets user requested cpus to evsel unless it has its own cpus, right?
> >>>>>>
> >>>>>> I put the conditional logic altogether because that is kernel style but
> >>>>>> it does make it practically unreadable.
> >>>>>>
> >>>>>> If we start with the original logic:
> >>>>>>
> >>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus) {
> >>>>>>                   perf_cpu_map__put(evsel->cpus);
> >>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>>>>>           } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
> >>>>>>                   perf_cpu_map__put(evsel->cpus);
> >>>>>>                   evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>>>>>           } else if (evsel->cpus != evsel->own_cpus) {
> >>>>>>                   perf_cpu_map__put(evsel->cpus);
> >>>>>>                   evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
> >>>>>>           }
> >>>>>>
> >>>>>> Then make it more readable, i.e. same functionality
> >>>>>>
> >>>>>>           struct perf_cpu_map *cpus;
> >>>>>>
> >>>>>>           if (!evsel->own_cpus || evlist->has_user_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>>           if (evsel->cpus != cpus) {
> >>>>>>                   perf_cpu_map__put(evsel->cpus);
> >>>>>>                   evsel->cpus = perf_cpu_map__get(cpus);
> >>>>>>           }
> >>>>>>
> >>>>>> Then separate out the conditions, i.e. still same functionality
> >>>>>>
> >>>>>>           if (!evsel->own_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (evlist->has_user_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (evsel->system_wide)
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>           else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>> Then add the new requires_cpu flag:
> >>>>>>
> >>>>>>           if (!evsel->own_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (evlist->has_user_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (evsel->system_wide)
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>>>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>> Then make system_wide keep own_cpus even if has_user_cpus:
> >>>>>>
> >>>>>>           if (!evsel->own_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>> +       else if (evsel->system_wide)
> >>>>>> +               cpus = evsel->own_cpus;
> >>>>>>           else if (evlist->has_user_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>> -       else if (evsel->system_wide)
> >>>>>> -               cpus = evsel->own_cpus;
> >>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>> Which leaves:
> >>>>>>
> >>>>>>           if (!evsel->own_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (evsel->system_wide)
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>           else if (evlist->has_user_cpus)
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>> And putting it back together:
> >>>>>>
> >>>>>>           if (!evsel->own_cpus ||
> >>>>>>               (!evsel->system_wide && evlist->has_user_cpus) ||
> >>>>>>               (!evsel->system_wide &&
> >>>>>>                !evsel->requires_cpu &&
> >>>>>>                perf_cpu_map__empty(evlist->user_requested_cpus))) {
> >>>>>>                   cpus = evlist->user_requested_cpus;
> >>>>>>           else
> >>>>>>                   cpus = evsel->own_cpus;
> >>>>>>
> >>>>>> Perhaps I shouldn't put it together?
> >>>>>
> >>>>> Cool, thanks a lot for explaining it in detail.
> >>>>> I do not oppose your change but little worried about the
> >>>>> complexity.  And I think we have some issues with uncore
> >>>>> events already.
> >>>>
> >>>> Yes it is a bit complicated because we are handling
> >>>> many different use cases.
> >>>>
> >>>>>
> >>>>> So do you have any idea where evsel->own_cpus
> >>>>> doesn't propagate to evsel->cpus?
> >>>>
> >>>> We let the user's list of CPUs override it i.e. the
> >>>> evlist->has_user_cpus case.  Essentially we are expecting
> >>>> the user to know what they are doing.
> >>>>
> >>>>>
> >>>>> I think evsel->system_wide and evsel->requires_cpu
> >>>>> can be replaced to check evsel->own_cpus instead.
> >>>>
> >>>> Not at the moment because we let the user override
> >>>> own_cpus.
> >>>
> >>> Do we check whether the user's input is valid (match the PMU's cpumask) before the override?
> >>>
> >>> I think we know the PMU name. The cpumask of the PMU can be found in the sysfs. So we should have enough information for a sanity check.
> >>
> >> For the uncore PMU case, I am not sure what sanity is :-)
> >>
> >
> > For a non-core PMU, e.g., uncore, cstate, power and etc. The cpumask is under the /sys/devices/<PMU>/cpumask. It shows the cpumask which kernel supports. If a end user request a different CPU other that the cpumask, I think it's better throw a waning. It should mitigate the confusion which Namhyung mentioned (uncore -C1,2).
>
> So you couldn't get uncore events unless you are also coincidentally wanting to trace CPU 0.
>
> I guess really the requrement is not to perf_event_open() an uncore PMU more than once?
> To figure that out we'd need to be able map CPUs to uncore PMUs?

We might just use evsel->own_cpus for uncore events and
if the user-given cpu list contains other cpus it can show an
warning.

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13 16:42                   ` Namhyung Kim
@ 2022-05-13 17:32                     ` Liang, Kan
  0 siblings, 0 replies; 70+ messages in thread
From: Liang, Kan @ 2022-05-13 17:32 UTC (permalink / raw)
  To: Namhyung Kim, Adrian Hunter
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers,
	Alexey Bayduraev, Leo Yan, linux-kernel, Stephane Eranian



On 5/13/2022 12:42 PM, Namhyung Kim wrote:
> On Fri, May 13, 2022 at 9:11 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> On 13/05/22 18:46, Liang, Kan wrote:
>>>
>>>
>>> On 5/13/2022 11:21 AM, Adrian Hunter wrote:
>>>> On 13/05/22 17:12, Liang, Kan wrote:
>>>>>
>>>>>
>>>>> On 5/13/2022 12:48 AM, Adrian Hunter wrote:
>>>>>> On 12/05/22 21:53, Namhyung Kim wrote:
>>>>>>> On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>>>
>>>>>>>> On 12/05/22 08:27, Namhyung Kim wrote:
>>>>>>>>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>>>>>>>>
>>>>>>>>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
>>>>>>>>>> has_user_cpus. Change that so that system-wide events retain their own
>>>>>>>>>> CPUs and they are added to all_cpus.
>>>>>>>>>>
>>>>>>>>>> Acked-by: Ian Rogers <irogers@google.com>
>>>>>>>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>>>>>>>> ---
>>>>>>>>>>     tools/lib/perf/evlist.c | 11 +++++------
>>>>>>>>>>     1 file changed, 5 insertions(+), 6 deletions(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
>>>>>>>>>> index 1c801f8da44f..9a6801b53274 100644
>>>>>>>>>> --- a/tools/lib/perf/evlist.c
>>>>>>>>>> +++ b/tools/lib/perf/evlist.c
>>>>>>>>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
>>>>>>>>>>             * We already have cpus for evsel (via PMU sysfs) so
>>>>>>>>>>             * keep it, if there's no target cpu list defined.
>>>>>>>>>>             */
>>>>>>>>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>>>>>> -               perf_cpu_map__put(evsel->cpus);
>>>>>>>>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>>>>> -       } else if (!evsel->system_wide &&
>>>>>>>>>> -                  !evsel->requires_cpu &&
>>>>>>>>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>>>>>> +       if (!evsel->own_cpus ||
>>>>>>>>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>>>>>> +           (!evsel->system_wide &&
>>>>>>>>>> +            !evsel->requires_cpu &&
>>>>>>>>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>>>>>
>>>>>>>>> This is getting hard to understand.  IIUC this propagation basically
>>>>>>>>> sets user requested cpus to evsel unless it has its own cpus, right?
>>>>>>>>
>>>>>>>> I put the conditional logic altogether because that is kernel style but
>>>>>>>> it does make it practically unreadable.
>>>>>>>>
>>>>>>>> If we start with the original logic:
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus || evlist->has_user_cpus) {
>>>>>>>>                    perf_cpu_map__put(evsel->cpus);
>>>>>>>>                    evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>>>            } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
>>>>>>>>                    perf_cpu_map__put(evsel->cpus);
>>>>>>>>                    evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
>>>>>>>>            } else if (evsel->cpus != evsel->own_cpus) {
>>>>>>>>                    perf_cpu_map__put(evsel->cpus);
>>>>>>>>                    evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
>>>>>>>>            }
>>>>>>>>
>>>>>>>> Then make it more readable, i.e. same functionality
>>>>>>>>
>>>>>>>>            struct perf_cpu_map *cpus;
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus || evlist->has_user_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>>            if (evsel->cpus != cpus) {
>>>>>>>>                    perf_cpu_map__put(evsel->cpus);
>>>>>>>>                    evsel->cpus = perf_cpu_map__get(cpus);
>>>>>>>>            }
>>>>>>>>
>>>>>>>> Then separate out the conditions, i.e. still same functionality
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (evlist->has_user_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (evsel->system_wide)
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>            else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>> Then add the new requires_cpu flag:
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (evlist->has_user_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (evsel->system_wide)
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>>> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>> Then make system_wide keep own_cpus even if has_user_cpus:
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>> +       else if (evsel->system_wide)
>>>>>>>> +               cpus = evsel->own_cpus;
>>>>>>>>            else if (evlist->has_user_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>> -       else if (evsel->system_wide)
>>>>>>>> -               cpus = evsel->own_cpus;
>>>>>>>>            else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>> Which leaves:
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (evsel->system_wide)
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>            else if (evlist->has_user_cpus)
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>> And putting it back together:
>>>>>>>>
>>>>>>>>            if (!evsel->own_cpus ||
>>>>>>>>                (!evsel->system_wide && evlist->has_user_cpus) ||
>>>>>>>>                (!evsel->system_wide &&
>>>>>>>>                 !evsel->requires_cpu &&
>>>>>>>>                 perf_cpu_map__empty(evlist->user_requested_cpus))) {
>>>>>>>>                    cpus = evlist->user_requested_cpus;
>>>>>>>>            else
>>>>>>>>                    cpus = evsel->own_cpus;
>>>>>>>>
>>>>>>>> Perhaps I shouldn't put it together?
>>>>>>>
>>>>>>> Cool, thanks a lot for explaining it in detail.
>>>>>>> I do not oppose your change but little worried about the
>>>>>>> complexity.  And I think we have some issues with uncore
>>>>>>> events already.
>>>>>>
>>>>>> Yes it is a bit complicated because we are handling
>>>>>> many different use cases.
>>>>>>
>>>>>>>
>>>>>>> So do you have any idea where evsel->own_cpus
>>>>>>> doesn't propagate to evsel->cpus?
>>>>>>
>>>>>> We let the user's list of CPUs override it i.e. the
>>>>>> evlist->has_user_cpus case.  Essentially we are expecting
>>>>>> the user to know what they are doing.
>>>>>>
>>>>>>>
>>>>>>> I think evsel->system_wide and evsel->requires_cpu
>>>>>>> can be replaced to check evsel->own_cpus instead.
>>>>>>
>>>>>> Not at the moment because we let the user override
>>>>>> own_cpus.
>>>>>
>>>>> Do we check whether the user's input is valid (match the PMU's cpumask) before the override?
>>>>>
>>>>> I think we know the PMU name. The cpumask of the PMU can be found in the sysfs. So we should have enough information for a sanity check.
>>>>
>>>> For the uncore PMU case, I am not sure what sanity is :-)
>>>>
>>>
>>> For a non-core PMU, e.g., uncore, cstate, power and etc. The cpumask is under the /sys/devices/<PMU>/cpumask. It shows the cpumask which kernel supports. If a end user request a different CPU other that the cpumask, I think it's better throw a waning. It should mitigate the confusion which Namhyung mentioned (uncore -C1,2).
>>
>> So you couldn't get uncore events unless you are also coincidentally wanting to trace CPU 0.
>>
>> I guess really the requrement is not to perf_event_open() an uncore PMU more than once?
>> To figure that out we'd need to be able map CPUs to uncore PMUs?
> 
> We might just use evsel->own_cpus for uncore events and
> if the user-given cpu list contains other cpus it can show an
> warning.
>

Yes, it sounds reasonable.


Thanks,
Kan

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-13  4:48         ` Adrian Hunter
  2022-05-13 14:12           ` Liang, Kan
@ 2022-05-14 13:35           ` Arnaldo Carvalho de Melo
  2022-05-17 23:31             ` Namhyung Kim
  1 sibling, 1 reply; 70+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-05-14 13:35 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Namhyung Kim, Jiri Olsa, Ian Rogers, Alexey Bayduraev, Leo Yan,
	linux-kernel, Stephane Eranian, Kan Liang

Em Fri, May 13, 2022 at 07:48:40AM +0300, Adrian Hunter escreveu:
> On 12/05/22 21:53, Namhyung Kim wrote:
> > On Thu, May 12, 2022 at 3:35 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>
> >> On 12/05/22 08:27, Namhyung Kim wrote:
> >>> On Fri, May 6, 2022 at 5:27 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
> >>>>
> >>>> Currently, user_requested_cpus supplants system-wide CPUs when the evlist
> >>>> has_user_cpus. Change that so that system-wide events retain their own
> >>>> CPUs and they are added to all_cpus.
> >>>>
> >>>> Acked-by: Ian Rogers <irogers@google.com>
> >>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >>>> ---
> >>>>  tools/lib/perf/evlist.c | 11 +++++------
> >>>>  1 file changed, 5 insertions(+), 6 deletions(-)
> >>>>
> >>>> diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
> >>>> index 1c801f8da44f..9a6801b53274 100644
> >>>> --- a/tools/lib/perf/evlist.c
> >>>> +++ b/tools/lib/perf/evlist.c
> >>>> @@ -40,12 +40,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
> >>>>          * We already have cpus for evsel (via PMU sysfs) so
> >>>>          * keep it, if there's no target cpu list defined.
> >>>>          */
> >>>> -       if (!evsel->own_cpus || evlist->has_user_cpus) {
> >>>> -               perf_cpu_map__put(evsel->cpus);
> >>>> -               evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>>> -       } else if (!evsel->system_wide &&
> >>>> -                  !evsel->requires_cpu &&
> >>>> -                  perf_cpu_map__empty(evlist->user_requested_cpus)) {
> >>>> +       if (!evsel->own_cpus ||
> >>>> +           (!evsel->system_wide && evlist->has_user_cpus) ||
> >>>> +           (!evsel->system_wide &&
> >>>> +            !evsel->requires_cpu &&
> >>>> +            perf_cpu_map__empty(evlist->user_requested_cpus))) {
> >>>
> >>> This is getting hard to understand.  IIUC this propagation basically
> >>> sets user requested cpus to evsel unless it has its own cpus, right?
> >>
> >> I put the conditional logic altogether because that is kernel style but
> >> it does make it practically unreadable.
> >>
> >> If we start with the original logic:
> >>
> >>         if (!evsel->own_cpus || evlist->has_user_cpus) {
> >>                 perf_cpu_map__put(evsel->cpus);
> >>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>         } else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus)) {
> >>                 perf_cpu_map__put(evsel->cpus);
> >>                 evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
> >>         } else if (evsel->cpus != evsel->own_cpus) {
> >>                 perf_cpu_map__put(evsel->cpus);
> >>                 evsel->cpus = perf_cpu_map__get(evsel->own_cpus);
> >>         }
> >>
> >> Then make it more readable, i.e. same functionality
> >>
> >>         struct perf_cpu_map *cpus;
> >>
> >>         if (!evsel->own_cpus || evlist->has_user_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (!evsel->system_wide && perf_cpu_map__empty(evlist->user_requested_cpus))
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >>         if (evsel->cpus != cpus) {
> >>                 perf_cpu_map__put(evsel->cpus);
> >>                 evsel->cpus = perf_cpu_map__get(cpus);
> >>         }
> >>
> >> Then separate out the conditions, i.e. still same functionality
> >>
> >>         if (!evsel->own_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (evlist->has_user_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (evsel->system_wide)
> >>                 cpus = evsel->own_cpus;
> >>         else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >> Then add the new requires_cpu flag:
> >>
> >>         if (!evsel->own_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (evlist->has_user_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (evsel->system_wide)
> >>                 cpus = evsel->own_cpus;
> >> -       else if (perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >> +       else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >> Then make system_wide keep own_cpus even if has_user_cpus:
> >>
> >>         if (!evsel->own_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >> +       else if (evsel->system_wide)
> >> +               cpus = evsel->own_cpus;
> >>         else if (evlist->has_user_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >> -       else if (evsel->system_wide)
> >> -               cpus = evsel->own_cpus;
> >>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >> Which leaves:
> >>
> >>         if (!evsel->own_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (evsel->system_wide)
> >>                 cpus = evsel->own_cpus;
> >>         else if (evlist->has_user_cpus)
> >>                 cpus = evlist->user_requested_cpus;
> >>         else if (!evsel->requres_cpu && perf_cpu_map__empty(evlist->user_requested_cpus)) /* per-thread */
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >> And putting it back together:
> >>
> >>         if (!evsel->own_cpus ||
> >>             (!evsel->system_wide && evlist->has_user_cpus) ||
> >>             (!evsel->system_wide &&
> >>              !evsel->requires_cpu &&
> >>              perf_cpu_map__empty(evlist->user_requested_cpus))) {
> >>                 cpus = evlist->user_requested_cpus;
> >>         else
> >>                 cpus = evsel->own_cpus;
> >>
> >> Perhaps I shouldn't put it together?
> > 
> > Cool, thanks a lot for explaining it in detail.
> > I do not oppose your change but little worried about the
> > complexity.  And I think we have some issues with uncore
> > events already.
> 
> Yes it is a bit complicated because we are handling
> many different use cases.
> 
> > 
> > So do you have any idea where evsel->own_cpus
> > doesn't propagate to evsel->cpus?
> 
> We let the user's list of CPUs override it i.e. the
> evlist->has_user_cpus case.  Essentially we are expecting
> the user to know what they are doing.
> 
> > 
> > I think evsel->system_wide and evsel->requires_cpu
> > can be replaced to check evsel->own_cpus instead.
> 
> Not at the moment because we let the user override
> own_cpus.
> 
> > 
> > Actually evlist->has_user_cpus is checked first so
> > uncore events' own_cpus might not be used.
> 
> Yes
> 
> > 
> > In my laptop, perf stat -a -A -e imc/data_reads/
> > will use cpu 0 as it's listed in the pmu cpumask.
> > But when I use -C1,2 it'll use the both cpus and
> > returns the similar values each (so the sum is 2x).
> 
> We expect the user to understand the uncore PMU they
> are using.  AFAICT an uncore PMU cpu mask with only
> CPU 0 typically means a single PMU that counts events
> that could be indrectly caused by any CPU.  When the
> cpu mask has more than one CPU, it means a PMU for
> each of a group of CPU's (e.g. a core or socket)
> 
> So in the example you gave above, there is only 1 PMU
> and reading from any CPU will give it's value.
> 
> A user providing a list of CPUs for uncore events
> is useful only in certain cases.  For example when
> each core has an uncore PMU and you only want to get
> values from one core.
> 
> > 
> > I'm not sure if it's intended.  I expect it runs on
> > cpu 0 or one of the given cpus.  Or it runs on both
> > cpus and returns value in half so that the sum is
> > the same as the original value (from a cpu).
> 
> I don't know if there is anything wrong with the way
> we are handling uncore PMUs, except that I don't know
> if it is documented anywhere.

Good thing about this conversation is that it will result in
documentation :-)

Thank you guys for having it and detailing it so nicely.

- Arnaldo
 
> > 
> >>
> >>>
> >>> But the hybrid pmus make this complex.  Maybe we can move the
> >>> logic in evlist__fix_hybrid_cpus() here and simplify it like below
> >>>
> >>> if (evsel->own_cpus) {
> >>>    if (evsel->pmu->is_hybrid)
> >>>       evsel->cpus = fixup_hybrid_cpus(evsel>own_cpus,
> >>>                                       evlist->user_requested_cpus);  //?
> >>>    else
> >>>       evsel->cpus = evlist->own_cpus;  // put + get
> >>> } else {
> >>>    evsel->cpus = evlist->user_requested_cpus;  // put + get
> >>> }
> >>>
> >>> Then we need to make sure evsel->pmu is set properly.
> >>>
> >>> What do you think?
> >>
> >> Hybrid handling looks complicated.  I would have to spend time
> >> better understanding it.
> >>
> >> So, in the context of this patch set, I don't want to look at
> >> issues with hybrid CPUs, except that there should be no change
> >> to how they are handled.
> > 
> > Fair enough.  But I think we have to look at it again soon.
> > 
> > Thanks,
> > Namhyung

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs
  2022-05-14 13:35           ` Arnaldo Carvalho de Melo
@ 2022-05-17 23:31             ` Namhyung Kim
  0 siblings, 0 replies; 70+ messages in thread
From: Namhyung Kim @ 2022-05-17 23:31 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Adrian Hunter, Jiri Olsa, Ian Rogers, Alexey Bayduraev, Leo Yan,
	linux-kernel, Stephane Eranian, Kan Liang

On Sat, May 14, 2022 at 6:35 AM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> Em Fri, May 13, 2022 at 07:48:40AM +0300, Adrian Hunter escreveu:
> > On 12/05/22 21:53, Namhyung Kim wrote:
> > > I'm not sure if it's intended.  I expect it runs on
> > > cpu 0 or one of the given cpus.  Or it runs on both
> > > cpus and returns value in half so that the sum is
> > > the same as the original value (from a cpu).
> >
> > I don't know if there is anything wrong with the way
> > we are handling uncore PMUs, except that I don't know
> > if it is documented anywhere.
>
> Good thing about this conversation is that it will result in
> documentation :-)
>
> Thank you guys for having it and detailing it so nicely.

To move things forward,

Acked-by: Namhyung Kim <namhyung@kernel.org>

for the patchset.  I'll try to cleanup the cpu map propagation
with hybrid events later.

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2022-05-17 23:31 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-06 12:25 [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 01/23] perf intel-pt: Add a test for system-wide side band Adrian Hunter
2022-05-10 17:18   ` Arnaldo Carvalho de Melo
2022-05-10 17:21     ` Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 02/23] libperf evsel: Add perf_evsel__enable_thread() Adrian Hunter
2022-05-06 17:06   ` Ian Rogers
2022-05-10 17:19   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 03/23] perf evlist: Use libperf functions in evlist__enable_event_idx() Adrian Hunter
2022-05-10 17:23   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 04/23] perf auxtrace: Move evlist__enable_event_idx() to auxtrace.c Adrian Hunter
2022-05-10 17:24   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 05/23] perf auxtrace: Do not mix up mmap idx Adrian Hunter
2022-05-10 17:25   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 06/23] libperf evlist: Remove ->idx() per_cpu parameter Adrian Hunter
2022-05-10 17:26   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 07/23] libperf evlist: Move ->idx() into mmap_per_evsel() Adrian Hunter
2022-05-10 17:26   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 08/23] libperf evlist: Add evsel as a parameter to ->idx() Adrian Hunter
2022-05-10 17:26   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 09/23] perf auxtrace: Record whether an auxtrace mmap is needed Adrian Hunter
2022-05-10 17:27   ` Arnaldo Carvalho de Melo
2022-05-06 12:25 ` [PATCH V2 10/23] perf auxtrace: Add mmap_needed to auxtrace_mmap_params Adrian Hunter
2022-05-06 20:16   ` Ian Rogers
2022-05-11  7:02     ` Adrian Hunter
2022-05-11  7:01   ` [PATCH V3 " Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 11/23] perf auxtrace: Remove auxtrace_mmap_params__set_idx() per_cpu parameter Adrian Hunter
2022-05-06 20:19   ` Ian Rogers
2022-05-06 12:25 ` [PATCH V2 12/23] perf evlist: Factor out evlist__dummy_event() Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 13/23] perf evlist: Add evlist__add_dummy_on_all_cpus() Adrian Hunter
2022-05-06 13:47   ` Ian Rogers
2022-05-06 15:07     ` Adrian Hunter
2022-05-06 15:35       ` Ian Rogers
2022-05-10 14:55         ` Adrian Hunter
2022-05-10 16:19           ` Ian Rogers
2022-05-10 16:24           ` Arnaldo Carvalho de Melo
2022-05-10 17:32             ` Adrian Hunter
2022-05-11  7:02   ` [PATCH V3 " Adrian Hunter
2022-05-11 22:50     ` Namhyung Kim
2022-05-12  4:33       ` Adrian Hunter
2022-05-12  5:01         ` Namhyung Kim
2022-05-06 12:25 ` [PATCH V2 14/23] perf record: Use evlist__add_dummy_on_all_cpus() in record__config_text_poke() Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 15/23] perf intel-pt: Use evlist__add_dummy_on_all_cpus() for switch tracking Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 16/23] perf intel-pt: Track sideband system-wide when needed Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 17/23] perf tools: Allow all_cpus to be a superset of user_requested_cpus Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 18/23] libperf evlist: Allow mixing per-thread and per-cpu mmaps Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 19/23] libperf evlist: Check nr_mmaps is correct Adrian Hunter
2022-05-06 20:20   ` Ian Rogers
2022-05-06 12:25 ` [PATCH V2 20/23] perf stat: Add requires_cpu flag for uncore Adrian Hunter
2022-05-06 12:25 ` [PATCH V2 21/23] libperf evsel: Add comments for booleans Adrian Hunter
2022-05-06 20:51   ` Ian Rogers
2022-05-11  7:03     ` Adrian Hunter
2022-05-12  5:34       ` Ian Rogers
2022-05-12 11:40         ` Adrian Hunter
2022-05-06 12:26 ` [PATCH V2 22/23] perf tools: Allow system-wide events to keep their own CPUs Adrian Hunter
2022-05-12  5:27   ` Namhyung Kim
2022-05-12 10:34     ` Adrian Hunter
2022-05-12 18:53       ` Namhyung Kim
2022-05-13  4:48         ` Adrian Hunter
2022-05-13 14:12           ` Liang, Kan
2022-05-13 15:21             ` Adrian Hunter
2022-05-13 15:46               ` Liang, Kan
2022-05-13 16:11                 ` Adrian Hunter
2022-05-13 16:42                   ` Namhyung Kim
2022-05-13 17:32                     ` Liang, Kan
2022-05-14 13:35           ` Arnaldo Carvalho de Melo
2022-05-17 23:31             ` Namhyung Kim
2022-05-06 12:26 ` [PATCH V2 23/23] perf tools: Allow system-wide events to keep their own threads Adrian Hunter
2022-05-08 15:08 ` [PATCH V2 00/23] perf intel-pt: Better support for perf record --cpu Leo Yan
2022-05-09  5:44   ` Adrian Hunter
2022-05-09  8:46     ` Leo Yan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).