linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1 00/15] Addition of session API to python module
@ 2025-10-29  5:33 Ian Rogers
  2025-10-29  5:33 ` [RFC PATCH v1 01/15] perf arch arm: Sort includes and add missed explicit dependencies Ian Rogers
                   ` (14 more replies)
  0 siblings, 15 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:33 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

The perf script command uses a session with process_events to call
through to the python process_events function. The event is turned
into a python dictionary, whether the entries are used or not, adding
overhead. To avoid the overhead, add a session API abstraction and
pass callbacks that can be used to perform the existing perf script
functions. The implementation is incomplete in this RFC.

In this series the mem-phys-addr.py command is ported from perf script
to using the session API. The performance before and after is:

Before:
```
$ perf mem record -a sleep 1
$ time perf script tools/perf/scripts/python/mem-phys-addr.py
Event: cpu_core/mem-loads-aux/
Memory type                                    count  percentage
 ---------------------------------------  ----------  ----------
0-fff : Reserved                                3217       100.0

real    0m3.754s
user    0m0.023s
sys     0m0.018s
```

After:
```
$ PYTHONPATH=/tmp/perf/python time python3 tools/perf/python/mem-phys-addr.py
Event: evsel(cpu_core/mem-loads-aux/)
Memory type                                    count  percentage
 ---------------------------------------  ----------  ----------
0-fff : Reserved                                3217       100.0

real    0m0.106s
user    0m0.021s
sys     0m0.020s
```

So a roughly 35x speedup, but it maybe that some of that is one time
start-up overhead of libpython which wouldn't be present for larger
perf.data files.

Before porting all the script commands and adding things like
callchain support to the python module, I wanted to get feedback. One
thing that particularly simplifies the series is adding reference
counts to evsel and evlist to avoid copying/cloning evsels created by
the session API when loading a perf.data file.

The approach of moving away from libpython and scripts was most
recently discussed as a topic in:
https://lore.kernel.org/lkml/CAP-5=fWDqE8SYfOLZkg_0=4Ayx6E7O+h7uUp4NDeCFkiN4b7-w@mail.gmail.com/

When creating the python wrapper some house keeping was done around
includes and perf_data's encapsulation.

The perf script callbacks differ from those in perf_tool, for example,
stat is the perf_tool callback is for a stat event while the scripting
ops combine things and have a stat callback associated with
stat_round. Should the session API match the tool or the script API?
The former feels better for long term, while the latter could simplify
porting perf scripts.

Ian Rogers (15):
  perf arch arm: Sort includes and add missed explicit dependencies
  perf arch x86: Sort includes and add missed explicit dependencies
  perf tests: Sort includes and add missed explicit dependencies
  perf script: Sort includes and add missed explicit dependencies
  perf util: Sort includes and add missed explicit dependencies
  perf python: Add add missed explicit dependencies
  perf evsel/evlist: Avoid unnecessary #includes
  perf maps: Move getting debug_file to verbose path
  perf data: Clean up use_stdio and structures
  perf python: Add wrapper for perf_data file abstraction
  perf python: Add python session abstraction wrapping perf's session
  perf evlist: Add reference count
  perf evsel: Add reference count
  perf python: Add access to evsel and phys_addr in event
  perf mem-phys-addr.py: Port to standalone application from perf script

 tools/perf/arch/arm/util/cs-etm.c           |  22 +-
 tools/perf/arch/x86/tests/hybrid.c          |   2 +-
 tools/perf/arch/x86/tests/topdown.c         |   2 +-
 tools/perf/arch/x86/util/intel-bts.c        |  14 +-
 tools/perf/arch/x86/util/intel-pt.c         |  31 +-
 tools/perf/arch/x86/util/iostat.c           |   2 +-
 tools/perf/bench/evlist-open-close.c        |  18 +-
 tools/perf/builtin-ftrace.c                 |   8 +-
 tools/perf/builtin-inject.c                 |   7 +-
 tools/perf/builtin-kvm.c                    |   4 +-
 tools/perf/builtin-lock.c                   |   2 +-
 tools/perf/builtin-record.c                 |  14 +-
 tools/perf/builtin-script.c                 | 109 ++--
 tools/perf/builtin-stat.c                   |   8 +-
 tools/perf/builtin-top.c                    |  52 +-
 tools/perf/builtin-trace.c                  |  38 +-
 tools/perf/python/mem-phys-addr.py          | 117 ++++
 tools/perf/tests/backward-ring-buffer.c     |  18 +-
 tools/perf/tests/code-reading.c             |   4 +-
 tools/perf/tests/event-times.c              |   4 +-
 tools/perf/tests/event_update.c             |   2 +-
 tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
 tools/perf/tests/evsel-tp-sched.c           |   4 +-
 tools/perf/tests/expand-cgroup.c            |   8 +-
 tools/perf/tests/hists_cumulate.c           |   2 +-
 tools/perf/tests/hists_filter.c             |   2 +-
 tools/perf/tests/hists_link.c               |   2 +-
 tools/perf/tests/hists_output.c             |   2 +-
 tools/perf/tests/hwmon_pmu.c                |  14 +-
 tools/perf/tests/keep-tracking.c            |   2 +-
 tools/perf/tests/mmap-basic.c               |  31 +-
 tools/perf/tests/openat-syscall-all-cpus.c  |   6 +-
 tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
 tools/perf/tests/openat-syscall.c           |   6 +-
 tools/perf/tests/parse-events.c             |   4 +-
 tools/perf/tests/parse-metric.c             |   4 +-
 tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
 tools/perf/tests/perf-record.c              |  18 +-
 tools/perf/tests/perf-time-to-tsc.c         |   2 +-
 tools/perf/tests/pfm.c                      |   4 +-
 tools/perf/tests/pmu-events.c               |   6 +-
 tools/perf/tests/pmu.c                      |   2 +-
 tools/perf/tests/sw-clock.c                 |  14 +-
 tools/perf/tests/switch-tracking.c          |   2 +-
 tools/perf/tests/task-exit.c                |  14 +-
 tools/perf/tests/tool_pmu.c                 |   2 +-
 tools/perf/tests/topology.c                 |   5 +-
 tools/perf/util/bpf_counter_cgroup.c        |   2 +-
 tools/perf/util/bpf_off_cpu.c               |  28 +-
 tools/perf/util/bpf_trace_augment.c         |   7 +-
 tools/perf/util/cgroup.c                    |   6 +-
 tools/perf/util/data-convert-bt.c           |   2 +-
 tools/perf/util/data.c                      |  81 ++-
 tools/perf/util/data.h                      |  52 +-
 tools/perf/util/evlist.c                    | 100 ++--
 tools/perf/util/evlist.h                    |  23 +-
 tools/perf/util/evsel.c                     | 103 ++--
 tools/perf/util/evsel.h                     |  30 +-
 tools/perf/util/expr.c                      |   2 +-
 tools/perf/util/header.c                    |  12 +-
 tools/perf/util/map.h                       |   6 +-
 tools/perf/util/maps.c                      |   9 +-
 tools/perf/util/metricgroup.c               |   6 +-
 tools/perf/util/parse-events.c              |   4 +-
 tools/perf/util/parse-events.y              |   2 +-
 tools/perf/util/perf_api_probe.c            |  19 +-
 tools/perf/util/pfm.c                       |   2 +-
 tools/perf/util/print-events.c              |   2 +-
 tools/perf/util/print_insn.h                |   5 +-
 tools/perf/util/python.c                    | 584 +++++++++++++++-----
 tools/perf/util/record.c                    |   2 +-
 tools/perf/util/s390-sample-raw.c           |  15 +-
 tools/perf/util/session.c                   |   4 +-
 tools/perf/util/sideband_evlist.c           |  16 +-
 tools/perf/util/stat-shadow.c               |   1 +
 tools/perf/util/stat.c                      |  15 +-
 76 files changed, 1152 insertions(+), 650 deletions(-)
 create mode 100644 tools/perf/python/mem-phys-addr.py

-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 01/15] perf arch arm: Sort includes and add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
@ 2025-10-29  5:33 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 02/15] perf arch x86: " Ian Rogers
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:33 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/arm/util/cs-etm.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index ea891d12f8f4..a0086ca8385b 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -3,10 +3,14 @@
  * Copyright(C) 2015 Linaro Limited. All rights reserved.
  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
  */
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
 
 #include <api/fs/fs.h>
-#include <linux/bits.h>
+#include <internal/lib.h> // page_size
 #include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/compiler.h>
 #include <linux/coresight-pmu.h>
 #include <linux/kernel.h>
@@ -15,24 +19,20 @@
 #include <linux/types.h>
 #include <linux/zalloc.h>
 
-#include "cs-etm.h"
-#include "../../../util/debug.h"
-#include "../../../util/record.h"
 #include "../../../util/auxtrace.h"
 #include "../../../util/cpumap.h"
+#include "../../../util/cs-etm.h"
+#include "../../../util/debug.h"
 #include "../../../util/event.h"
 #include "../../../util/evlist.h"
 #include "../../../util/evsel.h"
-#include "../../../util/perf_api_probe.h"
 #include "../../../util/evsel_config.h"
+#include "../../../util/perf_api_probe.h"
+#include "../../../util/pmu.h"
 #include "../../../util/pmus.h"
-#include "../../../util/cs-etm.h"
-#include <internal/lib.h> // page_size
+#include "../../../util/record.h"
 #include "../../../util/session.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
+#include "cs-etm.h"
 
 struct cs_etm_recording {
 	struct auxtrace_record	itr;
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 02/15] perf arch x86: Sort includes and add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
  2025-10-29  5:33 ` [RFC PATCH v1 01/15] perf arch arm: Sort includes and add missed explicit dependencies Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 03/15] perf tests: " Ian Rogers
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/x86/util/intel-bts.c | 14 +++++++------
 tools/perf/arch/x86/util/intel-pt.c  | 31 ++++++++++++++--------------
 2 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 85c8186300c8..c778d3407bea 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -5,25 +5,27 @@
  */
 
 #include <errno.h>
+
+#include <internal/lib.h> // page_size
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
 #include <linux/zalloc.h>
 
+#include "../../../util/auxtrace.h"
 #include "../../../util/cpumap.h"
+#include "../../../util/debug.h"
 #include "../../../util/event.h"
-#include "../../../util/evsel.h"
 #include "../../../util/evlist.h"
+#include "../../../util/evsel.h"
+#include "../../../util/intel-bts.h"
 #include "../../../util/mmap.h"
-#include "../../../util/session.h"
+#include "../../../util/pmu.h"
 #include "../../../util/pmus.h"
-#include "../../../util/debug.h"
 #include "../../../util/record.h"
+#include "../../../util/session.h"
 #include "../../../util/tsc.h"
-#include "../../../util/auxtrace.h"
-#include "../../../util/intel-bts.h"
-#include <internal/lib.h> // page_size
 
 #define KiB(x) ((x) * 1024)
 #define MiB(x) ((x) * 1024 * 1024)
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 2d7c0dec86b0..9ca197cc396e 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -3,37 +3,38 @@
  * intel_pt.c: Intel Processor Trace support
  * Copyright (c) 2013-2015, Intel Corporation.
  */
-
+#include <cpuid.h>
 #include <errno.h>
 #include <stdbool.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
+
+#include <api/fs/fs.h>
+#include <internal/lib.h> // page_size
 #include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
 #include <linux/log2.h>
+#include <linux/types.h>
 #include <linux/zalloc.h>
-#include <linux/err.h>
-#include <cpuid.h>
+#include <subcmd/parse-options.h>
 
-#include "../../../util/session.h"
+#include "../../../util/auxtrace.h"
+#include "../../../util/config.h"
+#include "../../../util/cpumap.h"
+#include "../../../util/debug.h"
 #include "../../../util/event.h"
 #include "../../../util/evlist.h"
 #include "../../../util/evsel.h"
 #include "../../../util/evsel_config.h"
-#include "../../../util/config.h"
-#include "../../../util/cpumap.h"
+#include "../../../util/intel-pt.h"
 #include "../../../util/mmap.h"
-#include <subcmd/parse-options.h>
 #include "../../../util/parse-events.h"
-#include "../../../util/pmus.h"
-#include "../../../util/debug.h"
-#include "../../../util/auxtrace.h"
 #include "../../../util/perf_api_probe.h"
+#include "../../../util/pmu.h"
+#include "../../../util/pmus.h"
 #include "../../../util/record.h"
+#include "../../../util/session.h"
 #include "../../../util/target.h"
 #include "../../../util/tsc.h"
-#include <internal/lib.h> // page_size
-#include "../../../util/intel-pt.h"
-#include <api/fs/fs.h>
 
 #define KiB(x) ((x) * 1024)
 #define MiB(x) ((x) * 1024 * 1024)
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 03/15] perf tests: Sort includes and add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
  2025-10-29  5:33 ` [RFC PATCH v1 01/15] perf arch arm: Sort includes and add missed explicit dependencies Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 02/15] perf arch x86: " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 04/15] perf script: " Ian Rogers
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing #includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/tests/hwmon_pmu.c  | 12 +++++++-----
 tools/perf/tests/mmap-basic.c | 13 ++++++++-----
 2 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
index 151f02701c8c..97ea036ebae6 100644
--- a/tools/perf/tests/hwmon_pmu.c
+++ b/tools/perf/tests/hwmon_pmu.c
@@ -1,14 +1,16 @@
 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
-#include "debug.h"
-#include "evlist.h"
-#include "hwmon_pmu.h"
-#include "parse-events.h"
-#include "tests.h"
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include "debug.h"
+#include "evlist.h"
+#include "hwmon_pmu.h"
+#include "parse-events.h"
+#include "pmus.h"
+#include "tests.h"
+
 
 static const struct test_event {
 	const char *name;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 3c89d3001887..a622bb8d4cc8 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -5,21 +5,24 @@
 #include <stdlib.h>
 #include <perf/cpumap.h>
 
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <perf/evlist.h>
+#include <perf/mmap.h>
+
 #include "cpumap.h"
 #include "debug.h"
 #include "event.h"
 #include "evlist.h"
 #include "evsel.h"
+#include "pmu.h"
+#include "pmus.h"
 #include "thread_map.h"
 #include "tests.h"
 #include "util/affinity.h"
 #include "util/mmap.h"
 #include "util/sample.h"
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <perf/evlist.h>
-#include <perf/mmap.h>
 
 /*
  * This test will generate random numbers of calls to some getpid syscalls,
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 04/15] perf script: Sort includes and add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (2 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 03/15] perf tests: " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 05/15] perf util: " Ian Rogers
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing #include of pmu.h found while cleaning the evsel/evlist
header files. Sort the remaining header files for consistency with the
rest of the code. Doing this exposed a missing forward declaration of
addr_location in print_insn.h, add this and sort the forward
declarations.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-script.c  | 109 ++++++++++++++++++-----------------
 tools/perf/util/print_insn.h |   5 +-
 2 files changed, 59 insertions(+), 55 deletions(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8124fcb51da9..6c3d98b51ee7 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1,74 +1,77 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "builtin.h"
 
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <linux/bitmap.h>
+#include <linux/compiler.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/time64.h>
+#include <linux/unaligned.h>
+#include <linux/zalloc.h>
+#include <perf/evlist.h>
+#include <subcmd/exec-cmd.h>
+#include <subcmd/pager.h>
+#include <subcmd/parse-options.h>
+
+#include "archinsn.h"
+#include "asm/bug.h"
+#include "perf.h"
+#include "print_binary.h"
+#include "print_insn.h"
+#include "ui/ui.h"
+#include "util/annotate.h"
+#include "util/auxtrace.h"
+#include "util/cgroup.h"
+#include "util/color.h"
 #include "util/counts.h"
+#include "util/cpumap.h"
+#include "util/data.h"
 #include "util/debug.h"
+#include "util/dlfilter.h"
 #include "util/dso.h"
-#include <subcmd/exec-cmd.h>
-#include "util/header.h"
-#include <subcmd/parse-options.h>
-#include "util/perf_regs.h"
-#include "util/session.h"
-#include "util/tool.h"
-#include "util/map.h"
-#include "util/srcline.h"
-#include "util/symbol.h"
-#include "util/thread.h"
-#include "util/trace-event.h"
+#include "util/dump-insn.h"
 #include "util/env.h"
+#include "util/event.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/evsel_fprintf.h"
 #include "util/evswitch.h"
+#include "util/header.h"
+#include "util/map.h"
+#include "util/mem-events.h"
+#include "util/mem-info.h"
+#include "util/path.h"
+#include "util/perf_regs.h"
+#include "util/pmu.h"
+#include "util/record.h"
+#include "util/session.h"
 #include "util/sort.h"
-#include "util/data.h"
-#include "util/auxtrace.h"
-#include "util/cpumap.h"
-#include "util/thread_map.h"
+#include "util/srcline.h"
 #include "util/stat.h"
-#include "util/color.h"
 #include "util/string2.h"
+#include "util/symbol.h"
 #include "util/thread-stack.h"
+#include "util/thread.h"
+#include "util/thread_map.h"
 #include "util/time-utils.h"
-#include "util/path.h"
-#include "util/event.h"
-#include "util/mem-info.h"
-#include "ui/ui.h"
-#include "print_binary.h"
-#include "print_insn.h"
-#include "archinsn.h"
-#include <linux/bitmap.h>
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/stringify.h>
-#include <linux/time64.h>
-#include <linux/zalloc.h>
-#include <linux/unaligned.h>
-#include <sys/utsname.h>
-#include "asm/bug.h"
-#include "util/mem-events.h"
-#include "util/dump-insn.h"
-#include <dirent.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <subcmd/pager.h>
-#include <perf/evlist.h>
-#include <linux/err.h>
-#include "util/dlfilter.h"
-#include "util/record.h"
+#include "util/tool.h"
+#include "util/trace-event.h"
 #include "util/util.h"
-#include "util/cgroup.h"
-#include "util/annotate.h"
-#include "perf.h"
 
-#include <linux/ctype.h>
 #ifdef HAVE_LIBTRACEEVENT
 #include <event-parse.h>
 #endif
diff --git a/tools/perf/util/print_insn.h b/tools/perf/util/print_insn.h
index 07d11af3fc1c..a54f7e858e49 100644
--- a/tools/perf/util/print_insn.h
+++ b/tools/perf/util/print_insn.h
@@ -5,10 +5,11 @@
 #include <stddef.h>
 #include <stdio.h>
 
-struct perf_sample;
-struct thread;
+struct addr_location;
 struct machine;
 struct perf_insn;
+struct perf_sample;
+struct thread;
 
 #define PRINT_INSN_IMM_HEX		(1<<0)
 
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 05/15] perf util: Sort includes and add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (3 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 04/15] perf script: " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 06/15] perf python: Add " Ian Rogers
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing includes found while cleaning the evsel/evlist header
files. Sort the remaining header files for consistency with the rest
of the code.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/bpf_off_cpu.c       | 28 ++++++-----
 tools/perf/util/bpf_trace_augment.c |  7 +--
 tools/perf/util/evlist.c            | 78 ++++++++++++++---------------
 tools/perf/util/evsel.c             | 77 ++++++++++++++--------------
 tools/perf/util/map.h               |  6 +--
 tools/perf/util/perf_api_probe.c    | 17 ++++---
 tools/perf/util/s390-sample-raw.c   | 15 +++---
 tools/perf/util/stat-shadow.c       |  1 +
 tools/perf/util/stat.c              | 15 +++---
 9 files changed, 127 insertions(+), 117 deletions(-)

diff --git a/tools/perf/util/bpf_off_cpu.c b/tools/perf/util/bpf_off_cpu.c
index 88e0660c4bff..707ab14aa4ca 100644
--- a/tools/perf/util/bpf_off_cpu.c
+++ b/tools/perf/util/bpf_off_cpu.c
@@ -1,22 +1,24 @@
 // SPDX-License-Identifier: GPL-2.0
-#include "util/bpf_counter.h"
-#include "util/debug.h"
-#include "util/evsel.h"
-#include "util/evlist.h"
-#include "util/off_cpu.h"
-#include "util/perf-hooks.h"
-#include "util/record.h"
-#include "util/session.h"
-#include "util/target.h"
-#include "util/cpumap.h"
-#include "util/thread_map.h"
-#include "util/cgroup.h"
-#include "util/strlist.h"
 #include <bpf/bpf.h>
 #include <bpf/btf.h>
 #include <internal/xyarray.h>
 #include <linux/time64.h>
 
+#include "bpf_counter.h"
+#include "cgroup.h"
+#include "cpumap.h"
+#include "debug.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "off_cpu.h"
+#include "parse-events.h"
+#include "perf-hooks.h"
+#include "record.h"
+#include "session.h"
+#include "strlist.h"
+#include "target.h"
+#include "thread_map.h"
+
 #include "bpf_skel/off_cpu.skel.h"
 
 #define MAX_STACKS  32
diff --git a/tools/perf/util/bpf_trace_augment.c b/tools/perf/util/bpf_trace_augment.c
index 56ed17534caa..c2d502c1c358 100644
--- a/tools/perf/util/bpf_trace_augment.c
+++ b/tools/perf/util/bpf_trace_augment.c
@@ -1,9 +1,10 @@
 #include <bpf/libbpf.h>
 #include <internal/xyarray.h>
 
-#include "util/debug.h"
-#include "util/evlist.h"
-#include "util/trace_augment.h"
+#include "debug.h"
+#include "evlist.h"
+#include "parse-events.h"
+#include "trace_augment.h"
 
 #include "bpf_skel/augmented_raw_syscalls.skel.h"
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index e8217efdda53..d99a3f12606f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -5,66 +5,66 @@
  * Parts came from builtin-{top,stat,record}.c, see those files for further
  * copyright notes.
  */
-#include <api/fs/fs.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <poll.h>
-#include "cpumap.h"
-#include "util/mmap.h"
-#include "thread_map.h"
-#include "target.h"
-#include "evlist.h"
-#include "evsel.h"
-#include "record.h"
-#include "debug.h"
-#include "units.h"
-#include "bpf_counter.h"
-#include <internal/lib.h> // page_size
-#include "affinity.h"
-#include "../perf.h"
-#include "asm/bug.h"
-#include "bpf-event.h"
-#include "util/event.h"
-#include "util/string2.h"
-#include "util/perf_api_probe.h"
-#include "util/evsel_fprintf.h"
-#include "util/pmu.h"
-#include "util/sample.h"
-#include "util/bpf-filter.h"
-#include "util/stat.h"
-#include "util/util.h"
-#include "util/env.h"
-#include "util/intel-tpebs.h"
-#include "util/metricgroup.h"
-#include "util/strbuf.h"
-#include <signal.h>
-#include <unistd.h>
 #include <sched.h>
+#include <signal.h>
 #include <stdlib.h>
-
-#include "parse-events.h"
-#include <subcmd/parse-options.h>
-
-#include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/timerfd.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
+#include <api/fs/fs.h>
+#include <internal/lib.h> // page_size
+#include <internal/xyarray.h>
 #include <linux/bitops.h>
+#include <linux/err.h>
 #include <linux/hash.h>
 #include <linux/log2.h>
-#include <linux/err.h>
 #include <linux/string.h>
 #include <linux/time64.h>
 #include <linux/zalloc.h>
+#include <perf/cpumap.h>
 #include <perf/evlist.h>
 #include <perf/evsel.h>
-#include <perf/cpumap.h>
 #include <perf/mmap.h>
+#include <subcmd/parse-options.h>
+
+#include "../perf.h"
+#include "affinity.h"
+#include "asm/bug.h"
+#include "bpf-event.h"
+#include "bpf_counter.h"
+#include "cpumap.h"
+#include "debug.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "parse-events.h"
+#include "record.h"
+#include "target.h"
+#include "thread_map.h"
+#include "units.h"
+#include "bpf-filter.h"
+#include "env.h"
+#include "event.h"
+#include "evsel_fprintf.h"
+#include "intel-tpebs.h"
+#include "metricgroup.h"
+#include "mmap.h"
+#include "perf_api_probe.h"
+#include "pmu.h"
+#include "pmus.h"
+#include "sample.h"
+#include "stat.h"
+#include "strbuf.h"
+#include "string2.h"
+#include "util.h"
 
-#include <internal/xyarray.h>
 
 #ifdef LACKS_SIGQUEUE_PROTOTYPE
 int sigqueue(pid_t pid, int sig, const union sigval value);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ad11cbfcbff1..6769cd27b6e4 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -12,66 +12,67 @@
 #define __SANE_USERSPACE_TYPES__
 
 #include <byteswap.h>
+#include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
-#include <linux/bitops.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
 #include <api/fs/fs.h>
 #include <api/fs/tracing_path.h>
-#include <linux/hw_breakpoint.h>
-#include <linux/perf_event.h>
+#include <internal/lib.h>
+#include <internal/threadmap.h>
+#include <internal/xyarray.h>
+#include <linux/bitops.h>
 #include <linux/compiler.h>
+#include <linux/ctype.h>
 #include <linux/err.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
 #include <linux/zalloc.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <stdlib.h>
+#include <perf/cpumap.h>
 #include <perf/evsel.h>
+
+#include "../perf-sys.h"
 #include "asm/bug.h"
+#include "bpf-filter.h"
 #include "bpf_counter.h"
 #include "callchain.h"
 #include "cgroup.h"
 #include "counts.h"
+#include "debug.h"
+#include "drm_pmu.h"
+#include "env.h"
 #include "event.h"
-#include "evsel.h"
-#include "time-utils.h"
-#include "util/env.h"
-#include "util/evsel_config.h"
-#include "util/evsel_fprintf.h"
 #include "evlist.h"
-#include <perf/cpumap.h>
-#include "thread_map.h"
-#include "target.h"
+#include "evsel.h"
+#include "evsel_config.h"
+#include "evsel_fprintf.h"
+#include "hashmap.h"
+#include "hist.h"
+#include "hwmon_pmu.h"
+#include "intel-tpebs.h"
+#include "memswap.h"
+#include "off_cpu.h"
+#include "parse-branch-options.h"
 #include "perf_regs.h"
+#include "pmu.h"
+#include "pmus.h"
 #include "record.h"
-#include "debug.h"
-#include "trace-event.h"
+#include "rlimit.h"
 #include "session.h"
 #include "stat.h"
 #include "string2.h"
-#include "memswap.h"
-#include "util.h"
-#include "util/hashmap.h"
-#include "off_cpu.h"
-#include "pmu.h"
-#include "pmus.h"
-#include "drm_pmu.h"
-#include "hwmon_pmu.h"
+#include "target.h"
+#include "thread_map.h"
+#include "time-utils.h"
 #include "tool_pmu.h"
 #include "tp_pmu.h"
-#include "rlimit.h"
-#include "../perf-sys.h"
-#include "util/parse-branch-options.h"
-#include "util/bpf-filter.h"
-#include "util/hist.h"
-#include <internal/xyarray.h>
-#include <internal/lib.h>
-#include <internal/threadmap.h>
-#include "util/intel-tpebs.h"
-
-#include <linux/ctype.h>
+#include "trace-event.h"
+#include "util.h"
 
 #ifdef HAVE_LIBTRACEEVENT
 #include <event-parse.h>
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 979b3e11b9bc..7cd5188fe628 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -2,13 +2,11 @@
 #ifndef __PERF_MAP_H
 #define __PERF_MAP_H
 
-#include <linux/refcount.h>
-#include <linux/compiler.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdbool.h>
+
+#include <linux/refcount.h>
 #include <linux/types.h>
 #include <internal/rc_check.h>
 
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index 6ecf38314f01..3345145a9307 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -1,13 +1,16 @@
 /* SPDX-License-Identifier: GPL-2.0 */
+#include <errno.h>
 
-#include "perf-sys.h"
-#include "util/cloexec.h"
-#include "util/evlist.h"
-#include "util/evsel.h"
-#include "util/parse-events.h"
-#include "util/perf_api_probe.h"
 #include <perf/cpumap.h>
-#include <errno.h>
+
+#include "cloexec.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "parse-events.h"
+#include "perf-sys.h"
+#include "perf_api_probe.h"
+#include "pmu.h"
+#include "pmus.h"
 
 typedef void (*setup_probe_fn_t)(struct evsel *evsel);
 
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index 335217bb532b..a2d6a1f93cce 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -12,21 +12,22 @@
  * sample was taken from.
  */
 
-#include <unistd.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <string.h>
-#include <inttypes.h>
+#include <unistd.h>
 
-#include <sys/stat.h>
-#include <linux/compiler.h>
 #include <asm/byteorder.h>
+#include <linux/compiler.h>
+#include <sys/stat.h>
 
+#include "color.h"
 #include "debug.h"
-#include "session.h"
 #include "evlist.h"
-#include "color.h"
-#include "sample-raw.h"
+#include "pmus.h"
 #include "s390-cpumcf-kernel.h"
+#include "sample-raw.h"
+#include "session.h"
 #include "util/pmu.h"
 #include "util/sample.h"
 
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index abaf6b579bfc..3588b469de9d 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -6,6 +6,7 @@
 #include "color.h"
 #include "debug.h"
 #include "pmu.h"
+#include "pmus.h"
 #include "rblist.h"
 #include "evlist.h"
 #include "expr.h"
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 101ed6c497bc..c1c44c417c93 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -1,21 +1,24 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <errno.h>
-#include <linux/err.h>
 #include <inttypes.h>
 #include <math.h>
 #include <string.h>
+
+#include <linux/err.h>
+#include <linux/zalloc.h>
+
 #include "counts.h"
 #include "cpumap.h"
 #include "debug.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "hashmap.h"
 #include "header.h"
-#include "stat.h"
+#include "pmu.h"
 #include "session.h"
+#include "stat.h"
 #include "target.h"
-#include "evlist.h"
-#include "evsel.h"
 #include "thread_map.h"
-#include "util/hashmap.h"
-#include <linux/zalloc.h>
 
 void update_stats(struct stats *stats, u64 val)
 {
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 06/15] perf python: Add add missed explicit dependencies
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (4 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 05/15] perf util: " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 07/15] perf evsel/evlist: Avoid unnecessary #includes Ian Rogers
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Fix missing #include of pmus.h found while cleaning the evsel/evlist
header files.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/python.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index fa5e4270d182..0366142184d8 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -15,6 +15,7 @@
 #include "evsel.h"
 #include "event.h"
 #include "expr.h"
+#include "pmus.h"
 #include "print_binary.h"
 #include "record.h"
 #include "strbuf.h"
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 07/15] perf evsel/evlist: Avoid unnecessary #includes
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (5 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 06/15] perf python: Add " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 08/15] perf maps: Move getting debug_file to verbose path Ian Rogers
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Use forward declarations and remove unnecessary #includes in evsel.h
and evlist.h. Sort the forward declaration.s

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/evlist.h | 16 +++++++++-------
 tools/perf/util/evsel.h  | 19 ++++++++++---------
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 5e71e3dc6042..61acbb10d9a5 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,28 +2,30 @@
 #ifndef __PERF_EVLIST_H
 #define __PERF_EVLIST_H 1
 
+#include <pthread.h>
+#include <signal.h>
+#include <unistd.h>
+
 #include <linux/compiler.h>
 #include <linux/kernel.h>
-#include <linux/refcount.h>
 #include <linux/list.h>
+#include <linux/refcount.h>
 #include <api/fd/array.h>
 #include <internal/evlist.h>
-#include <internal/evsel.h>
 #include <perf/evlist.h>
+
 #include "events_stats.h"
 #include "evsel.h"
 #include "rblist.h"
-#include <pthread.h>
-#include <signal.h>
-#include <unistd.h>
 
-struct pollfd;
-struct thread_map;
+struct evsel;
 struct perf_cpu_map;
 struct perf_stat_config;
+struct pollfd;
 struct record_opts;
 struct strbuf;
 struct target;
+struct thread_map;
 
 /*
  * State machine of bkw_mmap_state:
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index f8de0f9a719b..f4540920604e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -2,28 +2,29 @@
 #ifndef __PERF_EVSEL_H
 #define __PERF_EVSEL_H 1
 
-#include <linux/list.h>
 #include <stdbool.h>
 #include <sys/types.h>
+
+#include <internal/evsel.h>
+#include <linux/list.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
-#include <internal/evsel.h>
 #include <perf/evsel.h>
+
 #include "symbol_conf.h"
-#include "pmus.h"
-#include "pmu.h"
 
+struct bperf_follower_bpf;
+struct bperf_leader_bpf;
+struct bpf_counter_ops;
 struct bpf_object;
 struct cgroup;
+struct hashmap;
 struct perf_counts;
+struct perf_pmu;
 struct perf_stat_config;
 struct perf_stat_evsel;
-union perf_event;
-struct bpf_counter_ops;
 struct target;
-struct hashmap;
-struct bperf_leader_bpf;
-struct bperf_follower_bpf;
+union perf_event;
 
 typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
 
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 08/15] perf maps: Move getting debug_file to verbose path
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (6 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 07/15] perf evsel/evlist: Avoid unnecessary #includes Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 09/15] perf data: Clean up use_stdio and structures Ian Rogers
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Getting debug_file can trigger warnings if not set. Avoid getting
these warnings by pushing the use under the controlling if.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/maps.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index 779f6230130a..44cfd63f10dc 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -811,7 +811,6 @@ static int __maps__insert_sorted(struct maps *maps, unsigned int first_after_ind
 static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
 {
 	int err = 0;
-	FILE *fp = debug_file();
 	unsigned int i, ni = INT_MAX; // Some gcc complain, but depends on maps_by_name...
 
 	if (!maps__maps_by_address_sorted(maps))
@@ -839,8 +838,8 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
 				dso__name(map__dso(new)));
 		} else if (verbose >= 2) {
 			pr_debug("overlapping maps:\n");
-			map__fprintf(new, fp);
-			map__fprintf(pos, fp);
+			map__fprintf(new, debug_file());
+			map__fprintf(pos, debug_file());
 		}
 
 		if (maps_by_name)
@@ -861,7 +860,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
 			map__set_end(before, map__start(new));
 
 			if (verbose >= 2 && !use_browser)
-				map__fprintf(before, fp);
+				map__fprintf(before, debug_file());
 		}
 		if (map__end(new) < map__end(pos)) {
 			/* The new map isn't as long as the existing map. */
@@ -879,7 +878,7 @@ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
 			       map__map_ip(after, map__end(new)));
 
 			if (verbose >= 2 && !use_browser)
-				map__fprintf(after, fp);
+				map__fprintf(after, debug_file());
 		}
 		/*
 		 * If adding one entry, for `before` or `after`, we can replace
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 09/15] perf data: Clean up use_stdio and structures
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (7 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 08/15] perf maps: Move getting debug_file to verbose path Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 10/15] perf python: Add wrapper for perf_data file abstraction Ian Rogers
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

use_stdio was associated with struct perf_data and not perf_data_file
meaning there was implicit use of fd rather than fptr that may not be
safe. For example, in perf_data_file__write. Reorganize perf_data_file
to better abstract use_stdio, add kernel-doc and more consistently use
perf_data__ accessors so that use_stdio is better respected.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-inject.c |  7 ++--
 tools/perf/builtin-record.c | 10 +++--
 tools/perf/tests/topology.c |  3 +-
 tools/perf/util/data.c      | 81 ++++++++++++++++++++++++-------------
 tools/perf/util/data.h      | 52 ++++++++++++++++++++----
 tools/perf/util/session.c   |  2 +-
 6 files changed, 109 insertions(+), 46 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index a114b3fa1bea..bc2725dcdc8c 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -269,9 +269,8 @@ static s64 perf_event__repipe_auxtrace(struct perf_session *session,
 	inject->have_auxtrace = true;
 
 	if (!inject->output.is_pipe) {
-		off_t offset;
+		off_t offset = perf_data__seek(&inject->output, 0, SEEK_CUR);
 
-		offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
 		if (offset == -1)
 			return -errno;
 		ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
@@ -2364,12 +2363,12 @@ int cmd_inject(int argc, const char **argv)
 		.output = {
 			.path = "-",
 			.mode = PERF_DATA_MODE_WRITE,
-			.use_stdio = true,
+			.file.use_stdio = true,
 		},
 	};
 	struct perf_data data = {
 		.mode = PERF_DATA_MODE_READ,
-		.use_stdio = true,
+		.file.use_stdio = true,
 	};
 	int ret;
 	const char *known_build_ids = NULL;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index cb52aea9607d..3d8cf4090a92 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -453,7 +453,7 @@ static int record__aio_pushfn(struct mmap *map, void *to, void *buf, size_t size
 static int record__aio_push(struct record *rec, struct mmap *map, off_t *off)
 {
 	int ret, idx;
-	int trace_fd = rec->session->data->file.fd;
+	int trace_fd = perf_data__fd(rec->session->data);
 	struct record_aio aio = { .rec = rec, .size = 0 };
 
 	/*
@@ -1676,7 +1676,7 @@ static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist,
 	int rc = 0;
 	int nr_mmaps;
 	struct mmap **maps;
-	int trace_fd = rec->data.file.fd;
+	int trace_fd = perf_data__fd(&rec->data);
 	off_t off = 0;
 
 	if (!evlist)
@@ -1885,8 +1885,10 @@ record__finish_output(struct record *rec)
 	rec->session->header.data_size += rec->bytes_written;
 	data->file.size = lseek(perf_data__fd(data), 0, SEEK_CUR);
 	if (record__threads_enabled(rec)) {
-		for (i = 0; i < data->dir.nr; i++)
-			data->dir.files[i].size = lseek(data->dir.files[i].fd, 0, SEEK_CUR);
+		for (i = 0; i < data->dir.nr; i++) {
+			data->dir.files[i].size =
+				perf_data_file__seek(&data->dir.files[i], 0, SEEK_CUR);
+		}
 	}
 
 	/* Buildid scanning disabled or build ID in kernel and synthesized map events. */
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index ec01150d208d..af4618c3124a 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -52,7 +52,8 @@ static int session_write_header(char *path)
 	session->header.data_size += DATA_SIZE;
 
 	TEST_ASSERT_VAL("failed to write header",
-			!perf_session__write_header(session, session->evlist, data.file.fd, true));
+			!perf_session__write_header(session, session->evlist,
+						    perf_data__fd(&data), true));
 
 	evlist__delete(session->evlist);
 	perf_session__delete(session);
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 164eb45a0b36..0dcd4b8c51ce 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -20,18 +20,30 @@
 #include "rlimit.h"
 #include <internal/lib.h>
 
-static void close_dir(struct perf_data_file *files, int nr)
+static void perf_data_file__close(struct perf_data_file *file)
 {
-	while (--nr >= 0) {
-		close(files[nr].fd);
-		zfree(&files[nr].path);
+	if (file->use_stdio) {
+		fclose(file->fptr);
+		file->fptr = NULL;
+	} else {
+		close(file->fd);
+		file->fd = -1;
 	}
+	zfree(&file->path);
+}
+
+static void close_dir(struct perf_data_file *files, int nr)
+{
+	while (--nr >= 0)
+		perf_data_file__close(&files[nr]);
+
 	free(files);
 }
 
 void perf_data__close_dir(struct perf_data *data)
 {
 	close_dir(data->dir.files, data->dir.nr);
+	data->dir.files = NULL;
 }
 
 int perf_data__create_dir(struct perf_data *data, int nr)
@@ -174,7 +186,7 @@ static bool check_pipe(struct perf_data *data)
 	}
 
 	if (is_pipe) {
-		if (data->use_stdio) {
+		if (data->file.use_stdio) {
 			const char *mode;
 
 			mode = perf_data__is_read(data) ? "r" : "w";
@@ -182,7 +194,7 @@ static bool check_pipe(struct perf_data *data)
 
 			if (data->file.fptr == NULL) {
 				data->file.fd = fd;
-				data->use_stdio = false;
+				data->file.use_stdio = false;
 			}
 
 		/*
@@ -353,7 +365,7 @@ int perf_data__open(struct perf_data *data)
 		return 0;
 
 	/* currently it allows stdio for pipe only */
-	data->use_stdio = false;
+	data->file.use_stdio = false;
 
 	if (!data->path)
 		data->path = "perf.data";
@@ -373,41 +385,55 @@ void perf_data__close(struct perf_data *data)
 	if (perf_data__is_dir(data))
 		perf_data__close_dir(data);
 
-	zfree(&data->file.path);
-
-	if (data->use_stdio)
-		fclose(data->file.fptr);
-	else
-		close(data->file.fd);
+	perf_data_file__close(&data->file);
 }
 
-ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size)
+static ssize_t perf_data_file__read(struct perf_data_file *file, void *buf, size_t size)
 {
-	if (data->use_stdio) {
-		if (fread(buf, size, 1, data->file.fptr) == 1)
+	if (file->use_stdio) {
+		if (fread(buf, size, 1, file->fptr) == 1)
 			return size;
-		return feof(data->file.fptr) ? 0 : -1;
+		return feof(file->fptr) ? 0 : -1;
 	}
-	return readn(data->file.fd, buf, size);
+	return readn(file->fd, buf, size);
+}
+
+ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size)
+{
+	return perf_data_file__read(&data->file, buf, size);
 }
 
 ssize_t perf_data_file__write(struct perf_data_file *file,
 			      void *buf, size_t size)
 {
+	if (file->use_stdio) {
+		if (fwrite(buf, size, /*nmemb=*/1, file->fptr) == 1)
+			return size;
+		return -1;
+	}
 	return writen(file->fd, buf, size);
 }
 
 ssize_t perf_data__write(struct perf_data *data,
 			 void *buf, size_t size)
 {
-	if (data->use_stdio) {
-		if (fwrite(buf, size, 1, data->file.fptr) == 1)
-			return size;
-		return -1;
-	}
 	return perf_data_file__write(&data->file, buf, size);
 }
 
+off_t perf_data_file__seek(struct perf_data_file *file, off_t offset, int whence)
+{
+	if (file->use_stdio)
+		return fseek(file->fptr, offset, whence);
+
+	return lseek(file->fd, offset, whence);
+}
+
+off_t perf_data__seek(struct perf_data *data, off_t offset, int whence)
+{
+	assert(!data->is_pipe);
+	return perf_data_file__seek(&data->file, offset, whence);
+}
+
 int perf_data__switch(struct perf_data *data,
 		      const char *postfix,
 		      size_t pos, bool at_exit,
@@ -429,19 +455,18 @@ int perf_data__switch(struct perf_data *data,
 		pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
 
 	if (!at_exit) {
-		close(data->file.fd);
+		perf_data_file__close(&data->file);
 		ret = perf_data__open(data);
 		if (ret < 0)
 			goto out;
 
-		if (lseek(data->file.fd, pos, SEEK_SET) == (off_t)-1) {
+		if (perf_data__seek(data, pos, SEEK_SET) == (off_t)-1) {
 			ret = -errno;
-			pr_debug("Failed to lseek to %zu: %s",
-				 pos, strerror(errno));
+			pr_debug("Failed to seek to %zu: %s", pos, strerror(errno));
 			goto out;
 		}
 	}
-	ret = data->file.fd;
+	ret = perf_data__fd(data);
 out:
 	return ret;
 }
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 1438e32e0451..71f06df7abdb 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -17,32 +17,70 @@ enum perf_dir_version {
 	PERF_DIR_VERSION	= 1,
 };
 
+/**
+ * struct perf_data_file: A wrapper around a file used for perf.data reading or writing. Generally part
+ * of struct perf_data.
+ */
 struct perf_data_file {
+	/**
+	 * @path: Path of file. Generally a copy of perf_data.path but for a
+	 * directory it is the file within the directory.
+	 */
 	char		*path;
 	union {
+		/** @fd: File descriptor for read/writes. Valid if use_stdio is false. */
 		int	 fd;
+		/**
+		 * @fptr: Stdio FILE. Valid if use_stdio is true, currently just
+		 * pipes in perf inject.
+		 */
 		FILE	*fptr;
 	};
+	/** @size: Size of file when opened. */
 	unsigned long	 size;
+	/** @use_stdio: Use buffered stdio operations. */
+	bool		 use_stdio;
 };
 
+/**
+ * struct perf_data: A wrapper around a file used for perf.data reading or writing.
+ */
 struct perf_data {
+	/** @path: Path to open and of the file. NULL implies 'perf.data' will be used. */
 	const char		*path;
+	/** @file: Underlying file to be used. */
 	struct perf_data_file	 file;
+	/** @is_pipe: Underlying file is a pipe. */
 	bool			 is_pipe;
+	/** @is_dir: Underlying file is a directory. */
 	bool			 is_dir;
+	/** @force: Ignore opening a file creating created by a different user. */
 	bool			 force;
-	bool			 use_stdio;
+	/** @in_place_update: A file opened for reading but will be written to. */
 	bool			 in_place_update;
+	/** @mode: Read or write mode. */
 	enum perf_data_mode	 mode;
 
 	struct {
+		/** @version: perf_dir_version. */
 		u64			 version;
+		/** @files: perf data files for the directory. */
 		struct perf_data_file	*files;
+		/** @nr: Number of perf data files for the directory. */
 		int			 nr;
 	} dir;
 };
 
+static inline int perf_data_file__fd(struct perf_data_file *file)
+{
+	return file->use_stdio ? fileno(file->fptr) : file->fd;
+}
+
+ssize_t perf_data_file__write(struct perf_data_file *file,
+			      void *buf, size_t size);
+off_t perf_data_file__seek(struct perf_data_file *file, off_t offset, int whence);
+
+
 static inline bool perf_data__is_read(struct perf_data *data)
 {
 	return data->mode == PERF_DATA_MODE_READ;
@@ -70,10 +108,7 @@ static inline bool perf_data__is_single_file(struct perf_data *data)
 
 static inline int perf_data__fd(struct perf_data *data)
 {
-	if (data->use_stdio)
-		return fileno(data->file.fptr);
-
-	return data->file.fd;
+	return perf_data_file__fd(&data->file);
 }
 
 int perf_data__open(struct perf_data *data);
@@ -81,8 +116,7 @@ void perf_data__close(struct perf_data *data);
 ssize_t perf_data__read(struct perf_data *data, void *buf, size_t size);
 ssize_t perf_data__write(struct perf_data *data,
 			 void *buf, size_t size);
-ssize_t perf_data_file__write(struct perf_data_file *file,
-			      void *buf, size_t size);
+off_t perf_data__seek(struct perf_data *data, off_t offset, int whence);
 /*
  * If at_exit is set, only rename current perf.data to
  * perf.data.<postfix>, continue write on original data.
@@ -99,8 +133,10 @@ int perf_data__open_dir(struct perf_data *data);
 void perf_data__close_dir(struct perf_data *data);
 unsigned long perf_data__size(struct perf_data *data);
 int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz);
-bool has_kcore_dir(const char *path);
 char *perf_data__kallsyms_name(struct perf_data *data);
 char *perf_data__guest_kallsyms_name(struct perf_data *data, pid_t machine_pid);
+
+bool has_kcore_dir(const char *path);
 bool is_perf_data(const char *path);
+
 #endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 09af486c83e4..081e68c72c30 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -2358,7 +2358,7 @@ static int __perf_session__process_dir_events(struct perf_session *session)
 		if (!data->dir.files[i].size)
 			continue;
 		rd[readers] = (struct reader) {
-			.fd		 = data->dir.files[i].fd,
+			.fd		 = perf_data_file__fd(&data->dir.files[i]),
 			.path		 = data->dir.files[i].path,
 			.data_size	 = data->dir.files[i].size,
 			.data_offset	 = 0,
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 10/15] perf python: Add wrapper for perf_data file abstraction
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (8 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 09/15] perf data: Clean up use_stdio and structures Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 11/15] perf python: Add python session abstraction wrapping perf's session Ian Rogers
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

The perf_data struct is needed for session supported.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/python.c | 62 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 0366142184d8..f96c1f6dca56 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -11,6 +11,7 @@
 #include <perf/mmap.h>
 #include "callchain.h"
 #include "counts.h"
+#include "data.h"
 #include "evlist.h"
 #include "evsel.h"
 #include "event.h"
@@ -2163,6 +2164,61 @@ static PyObject *pyrf__metrics(PyObject *self, PyObject *args)
 	return list;
 }
 
+struct pyrf_data {
+	PyObject_HEAD
+
+	struct perf_data data;
+};
+
+static int pyrf_data__init(struct pyrf_data *pdata, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "path", "fd", NULL };
+	char *path = NULL;
+	int fd = -1;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &path, &fd))
+		return -1;
+
+	pdata->data.path = strdup(path);
+	pdata->data.mode = PERF_DATA_MODE_READ;
+	pdata->data.file.fd = fd;
+	return perf_data__open(&pdata->data) < 0 ? -1 : 0;
+}
+
+static void pyrf_data__delete(struct pyrf_data *pdata)
+{
+	perf_data__close(&pdata->data);
+	free((char *)pdata->data.path);
+	Py_TYPE(pdata)->tp_free((PyObject *)pdata);
+}
+
+static PyObject *pyrf_data__str(PyObject *self)
+{
+	const struct pyrf_data *pdata = (const struct pyrf_data *)self;
+
+	return PyUnicode_FromString(pdata->data.path);
+}
+
+static const char pyrf_data__doc[] = PyDoc_STR("perf data file object.");
+
+static PyTypeObject pyrf_data__type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
+	.tp_name	= "perf.data",
+	.tp_basicsize	= sizeof(struct pyrf_data),
+	.tp_dealloc	= (destructor)pyrf_data__delete,
+	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+	.tp_doc		= pyrf_data__doc,
+	.tp_init	= (initproc)pyrf_data__init,
+	.tp_repr	= pyrf_data__str,
+	.tp_str		= pyrf_data__str,
+};
+
+static int pyrf_data__setup_types(void)
+{
+	pyrf_data__type.tp_new = PyType_GenericNew;
+	return PyType_Ready(&pyrf_data__type);
+}
+
 static PyMethodDef perf__methods[] = {
 	{
 		.ml_name  = "metrics",
@@ -2225,7 +2281,8 @@ PyMODINIT_FUNC PyInit_perf(void)
 	    pyrf_cpu_map__setup_types() < 0 ||
 	    pyrf_pmu_iterator__setup_types() < 0 ||
 	    pyrf_pmu__setup_types() < 0 ||
-	    pyrf_counts_values__setup_types() < 0)
+	    pyrf_counts_values__setup_types() < 0 ||
+	    pyrf_data__setup_types() < 0)
 		return module;
 
 	/* The page_size is placed in util object. */
@@ -2273,6 +2330,9 @@ PyMODINIT_FUNC PyInit_perf(void)
 	Py_INCREF(&pyrf_counts_values__type);
 	PyModule_AddObject(module, "counts_values", (PyObject *)&pyrf_counts_values__type);
 
+	Py_INCREF(&pyrf_data__type);
+	PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type);
+
 	dict = PyModule_GetDict(module);
 	if (dict == NULL)
 		goto error;
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 11/15] perf python: Add python session abstraction wrapping perf's session
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (9 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 10/15] perf python: Add wrapper for perf_data file abstraction Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 12/15] perf evlist: Add reference count Ian Rogers
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Sessions are necessary to be able to use perf.data files within a
tool. Add a wrapper python type that incorporates the tool. Allow a
sample callback to be passed when creating the session. When
process_events is run this callback will be called, if supplied, for
sample events.

An example use looks like:
```
$ perf record -e cycles,instructions -a sleep 3
$ PYTHONPATH=..../perf/python python3
Python 3.13.7 (main, Aug 20 2025, 22:17:40) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import perf
>>> count=0
... def handle_sample(x):
...   global count
...   if count < 3:
...     print(dir(x))
...   count = count + 1
... perf.session(perf.data("perf.data"),sample=handle_sample).process_events()
...
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'sample_addr', 'sample_cpu', 'sample_id', 'sample_ip', 'sample_period', 'sample_pid', 'sample_stream_id', 'sample_tid', 'sample_time', 'type']
```

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/python.c | 114 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 113 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index f96c1f6dca56..dfc6e9299af9 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -19,8 +19,10 @@
 #include "pmus.h"
 #include "print_binary.h"
 #include "record.h"
+#include "session.h"
 #include "strbuf.h"
 #include "thread_map.h"
+#include "tool.h"
 #include "tp_pmu.h"
 #include "trace-event.h"
 #include "metricgroup.h"
@@ -2219,6 +2221,112 @@ static int pyrf_data__setup_types(void)
 	return PyType_Ready(&pyrf_data__type);
 }
 
+struct pyrf_session {
+	PyObject_HEAD
+
+	struct perf_session *session;
+	struct perf_tool tool;
+	struct pyrf_data *pdata;
+	PyObject *sample;
+	PyObject *stat;
+};
+
+static int pyrf_session_tool__sample(const struct perf_tool *tool,
+				     union perf_event *event,
+				     struct perf_sample *sample,
+				     struct evsel *evsel,
+				     struct machine *machine __maybe_unused)
+{
+	struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool);
+	PyObject *pyevent = pyrf_event__new(event);
+	struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
+
+	if (pyevent == NULL)
+		return -ENOMEM;
+
+	pevent->evsel = evsel;
+	memcpy(&pevent->sample, sample, sizeof(struct perf_sample));
+
+	PyObject_CallFunction(psession->sample, "O", pyevent);
+	Py_DECREF(pyevent);
+	return 0;
+}
+
+static int pyrf_session__init(struct pyrf_session *psession, PyObject *args, PyObject *kwargs)
+{
+	struct pyrf_data *pdata;
+	PyObject *sample = NULL;
+	static char *kwlist[] = { "data", "sample", NULL };
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, &pdata, &sample))
+		return -1;
+
+	Py_INCREF(pdata);
+	psession->pdata = pdata;
+	perf_tool__init(&psession->tool, /*ordered_events=*/true);
+
+	#define ADD_TOOL(name) \
+	if (name) {					\
+		if (!PyCallable_Check(name)) {\
+			PyErr_SetString(PyExc_TypeError, #name " must be callable"); \
+			return -1;\
+		}\
+		psession->tool.name = pyrf_session_tool__##name;	\
+		Py_INCREF(name); \
+		psession->name = name; \
+	}
+
+	ADD_TOOL(sample);
+	#undef ADD_TOOL
+
+	psession->session = perf_session__new(&pdata->data, &psession->tool);
+	return psession->session ? 0 : -1;
+}
+
+static void pyrf_session__delete(struct pyrf_session *psession)
+{
+	Py_XDECREF(psession->pdata);
+	Py_XDECREF(psession->sample);
+	perf_session__delete(psession->session);
+	Py_TYPE(psession)->tp_free((PyObject *)psession);
+}
+
+static PyObject *pyrf_session__process_events(struct pyrf_session *psession)
+{
+	perf_session__process_events(psession->session);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef pyrf_session__methods[] = {
+	{
+		.ml_name  = "process_events",
+		.ml_meth  = (PyCFunction)pyrf_session__process_events,
+		.ml_flags = METH_NOARGS,
+		.ml_doc	  = PyDoc_STR("Iterate and process events.")
+	},
+	{ .ml_name = NULL, }
+};
+
+static const char pyrf_session__doc[] = PyDoc_STR("perf session object.");
+
+static PyTypeObject pyrf_session__type = {
+	PyVarObject_HEAD_INIT(NULL, 0)
+	.tp_name	= "perf.session",
+	.tp_basicsize	= sizeof(struct pyrf_session),
+	.tp_dealloc	= (destructor)pyrf_session__delete,
+	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+	.tp_methods	= pyrf_session__methods,
+	.tp_doc		= pyrf_session__doc,
+	.tp_init	= (initproc)pyrf_session__init,
+};
+
+static int pyrf_session__setup_types(void)
+{
+	pyrf_session__type.tp_new = PyType_GenericNew;
+	return PyType_Ready(&pyrf_session__type);
+}
+
 static PyMethodDef perf__methods[] = {
 	{
 		.ml_name  = "metrics",
@@ -2282,7 +2390,8 @@ PyMODINIT_FUNC PyInit_perf(void)
 	    pyrf_pmu_iterator__setup_types() < 0 ||
 	    pyrf_pmu__setup_types() < 0 ||
 	    pyrf_counts_values__setup_types() < 0 ||
-	    pyrf_data__setup_types() < 0)
+	    pyrf_data__setup_types() < 0 ||
+	    pyrf_session__setup_types() < 0)
 		return module;
 
 	/* The page_size is placed in util object. */
@@ -2333,6 +2442,9 @@ PyMODINIT_FUNC PyInit_perf(void)
 	Py_INCREF(&pyrf_data__type);
 	PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type);
 
+	Py_INCREF(&pyrf_data__type);
+	PyModule_AddObject(module, "session", (PyObject *)&pyrf_session__type);
+
 	dict = PyModule_GetDict(module);
 	if (dict == NULL)
 		goto error;
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (10 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 11/15] perf python: Add python session abstraction wrapping perf's session Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29 16:22   ` Arnaldo Carvalho de Melo
  2025-10-29  5:34 ` [RFC PATCH v1 13/15] perf evsel: " Ian Rogers
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

This a no-op for most of the perf tool. The reference count is set to
1 at allocation, the put will see the 1, decrement it and perform the
delete. The purpose for adding the reference count is for the python
code. Prior to this change the python code would clone evlists, but
this has issues if events are opened, etc. This change adds a
reference count for the evlists and a later change will add it to
evsels. The combination is needed for the python code to operate
correctly (not hit asserts in the evsel clone), but the changes are
broken apart for the sake of smaller patches.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/x86/tests/hybrid.c          |   2 +-
 tools/perf/arch/x86/tests/topdown.c         |   2 +-
 tools/perf/arch/x86/util/iostat.c           |   2 +-
 tools/perf/bench/evlist-open-close.c        |  18 +-
 tools/perf/builtin-ftrace.c                 |   8 +-
 tools/perf/builtin-kvm.c                    |   4 +-
 tools/perf/builtin-lock.c                   |   2 +-
 tools/perf/builtin-record.c                 |   4 +-
 tools/perf/builtin-stat.c                   |   8 +-
 tools/perf/builtin-top.c                    |  52 +++---
 tools/perf/builtin-trace.c                  |  26 +--
 tools/perf/tests/backward-ring-buffer.c     |  18 +-
 tools/perf/tests/code-reading.c             |   4 +-
 tools/perf/tests/event-times.c              |   4 +-
 tools/perf/tests/event_update.c             |   2 +-
 tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
 tools/perf/tests/expand-cgroup.c            |   8 +-
 tools/perf/tests/hists_cumulate.c           |   2 +-
 tools/perf/tests/hists_filter.c             |   2 +-
 tools/perf/tests/hists_link.c               |   2 +-
 tools/perf/tests/hists_output.c             |   2 +-
 tools/perf/tests/hwmon_pmu.c                |   2 +-
 tools/perf/tests/keep-tracking.c            |   2 +-
 tools/perf/tests/mmap-basic.c               |  18 +-
 tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
 tools/perf/tests/parse-events.c             |   4 +-
 tools/perf/tests/parse-metric.c             |   4 +-
 tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
 tools/perf/tests/perf-record.c              |  18 +-
 tools/perf/tests/perf-time-to-tsc.c         |   2 +-
 tools/perf/tests/pfm.c                      |   4 +-
 tools/perf/tests/pmu-events.c               |   6 +-
 tools/perf/tests/pmu.c                      |   2 +-
 tools/perf/tests/sw-clock.c                 |  14 +-
 tools/perf/tests/switch-tracking.c          |   2 +-
 tools/perf/tests/task-exit.c                |  14 +-
 tools/perf/tests/tool_pmu.c                 |   2 +-
 tools/perf/tests/topology.c                 |   2 +-
 tools/perf/util/cgroup.c                    |   4 +-
 tools/perf/util/data-convert-bt.c           |   2 +-
 tools/perf/util/evlist.c                    |  20 ++-
 tools/perf/util/evlist.h                    |   7 +-
 tools/perf/util/expr.c                      |   2 +-
 tools/perf/util/header.c                    |  12 +-
 tools/perf/util/metricgroup.c               |   6 +-
 tools/perf/util/parse-events.c              |   4 +-
 tools/perf/util/perf_api_probe.c            |   2 +-
 tools/perf/util/python.c                    | 176 +++++++-------------
 tools/perf/util/record.c                    |   2 +-
 tools/perf/util/session.c                   |   2 +-
 tools/perf/util/sideband_evlist.c           |  16 +-
 51 files changed, 252 insertions(+), 299 deletions(-)

diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
index e221ea104174..dfb0ffc0d030 100644
--- a/tools/perf/arch/x86/tests/hybrid.c
+++ b/tools/perf/arch/x86/tests/hybrid.c
@@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
 		ret = e->check(evlist);
 	}
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 
 	return ret;
 }
diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
index 1eba3b4594ef..b31aef4ef28b 100644
--- a/tools/perf/arch/x86/tests/topdown.c
+++ b/tools/perf/arch/x86/tests/topdown.c
@@ -55,7 +55,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
 			*ret = TEST_FAIL;
 		}
 	}
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return 0;
 }
 
diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
index 7442a2cd87ed..e0417552b0cb 100644
--- a/tools/perf/arch/x86/util/iostat.c
+++ b/tools/perf/arch/x86/util/iostat.c
@@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
 	if (evlist->core.nr_entries > 0) {
 		pr_warning("The -e and -M options are not supported."
 			   "All chosen events/metrics will be dropped\n");
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		evlist = evlist__new();
 		if (!evlist)
 			return -ENOMEM;
diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
index bfaf50e4e519..a802fb005ee3 100644
--- a/tools/perf/bench/evlist-open-close.c
+++ b/tools/perf/bench/evlist-open-close.c
@@ -75,7 +75,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
 		parse_events_error__exit(&err);
 		pr_err("Run 'perf list' for a list of valid events\n");
 		ret = 1;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 	parse_events_error__exit(&err);
 	if (uid_str) {
@@ -84,24 +84,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
 		if (uid == UINT_MAX) {
 			pr_err("Invalid User: %s", uid_str);
 			ret = -EINVAL;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 		ret = parse_uid_filter(evlist, uid);
 		if (ret)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 	ret = evlist__create_maps(evlist, &opts.target);
 	if (ret < 0) {
 		pr_err("Not enough memory to create thread/cpu maps\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__config(evlist, &opts, NULL);
 
 	return evlist;
 
-out_delete_evlist:
-	evlist__delete(evlist);
+out_put_evlist:
+	evlist__put(evlist);
 	return NULL;
 }
 
@@ -150,7 +150,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
 		evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
 	printf("  Number of iterations:\t%d\n", iterations);
 
-	evlist__delete(evlist);
+	evlist__put(evlist);
 
 	for (i = 0; i < iterations; i++) {
 		pr_debug("Started iteration %d\n", i);
@@ -161,7 +161,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
 		gettimeofday(&start, NULL);
 		err = bench__do_evlist_open_close(evlist);
 		if (err) {
-			evlist__delete(evlist);
+			evlist__put(evlist);
 			return err;
 		}
 
@@ -170,7 +170,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
 		runtime_us = timeval2usec(&diff);
 		update_stats(&time_stats, runtime_us);
 
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
 	}
 
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index 6b6eec65f93f..4a2fe05e9786 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -1993,20 +1993,20 @@ int cmd_ftrace(int argc, const char **argv)
 
 	ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
 	if (ret < 0)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if (argc) {
 		ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
 					       argv, false,
 					       ftrace__workload_exec_failed_signal);
 		if (ret < 0)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 
 	ret = cmd_func(&ftrace);
 
-out_delete_evlist:
-	evlist__delete(ftrace.evlist);
+out_put_evlist:
+	evlist__put(ftrace.evlist);
 
 out_delete_filters:
 	delete_filter_func(&ftrace.filters);
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index f0f285763f19..b07cbe051e33 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1806,7 +1806,7 @@ static struct evlist *kvm_live_event_list(void)
 
 out:
 	if (err) {
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		evlist = NULL;
 	}
 
@@ -1937,7 +1937,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
 out:
 	perf_session__delete(kvm->session);
 	kvm->session = NULL;
-	evlist__delete(kvm->evlist);
+	evlist__put(kvm->evlist);
 
 	return err;
 }
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 078634461df2..2a57767f03a9 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -2143,7 +2143,7 @@ static int __cmd_contention(int argc, const char **argv)
 
 out_delete:
 	lock_filter_finish();
-	evlist__delete(con.evlist);
+	evlist__put(con.evlist);
 	lock_contention_finish(&con);
 	perf_session__delete(session);
 	perf_env__exit(&host_env);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3d8cf4090a92..738dbae80eac 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -4349,7 +4349,7 @@ int cmd_record(int argc, const char **argv)
 			goto out;
 
 		evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
-		evlist__delete(def_evlist);
+		evlist__put(def_evlist);
 	}
 
 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
@@ -4460,7 +4460,7 @@ int cmd_record(int argc, const char **argv)
 	auxtrace_record__free(rec->itr);
 out_opts:
 	evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
-	evlist__delete(rec->evlist);
+	evlist__put(rec->evlist);
 	return err;
 }
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 886727ae8529..282926c6abd4 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2067,7 +2067,7 @@ static int add_default_events(void)
 			metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
 							&evlist->metric_events,
 							&metric_evlist->metric_events);
-			evlist__delete(metric_evlist);
+			evlist__put(metric_evlist);
 		}
 	}
 
@@ -2142,7 +2142,7 @@ static int add_default_events(void)
 	metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
 					&evsel_list->metric_events,
 					&evlist->metric_events);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
@@ -2373,7 +2373,7 @@ static int __cmd_report(int argc, const char **argv)
 
 	perf_stat.session  = session;
 	stat_config.output = stderr;
-	evlist__delete(evsel_list);
+	evlist__put(evsel_list);
 	evsel_list         = session->evlist;
 
 	ret = perf_session__process_events(session);
@@ -3042,7 +3042,7 @@ int cmd_stat(int argc, const char **argv)
 	if (smi_cost && smi_reset)
 		sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
 
-	evlist__delete(evsel_list);
+	evlist__put(evsel_list);
 
 	evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 710604c4f6f6..45d5dae54dcd 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1641,14 +1641,14 @@ int cmd_top(int argc, const char **argv)
 	perf_env__init(&host_env);
 	status = perf_config(perf_top_config, &top);
 	if (status)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	/*
 	 * Since the per arch annotation init routine may need the cpuid, read
 	 * it here, since we are not getting this from the perf.data header.
 	 */
 	status = perf_env__set_cmdline(&host_env, argc, argv);
 	if (status)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	status = perf_env__read_cpuid(&host_env);
 	if (status) {
@@ -1669,44 +1669,44 @@ int cmd_top(int argc, const char **argv)
 		annotate_opts.disassembler_style = strdup(disassembler_style);
 		if (!annotate_opts.disassembler_style) {
 			status = -ENOMEM;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 	if (objdump_path) {
 		annotate_opts.objdump_path = strdup(objdump_path);
 		if (!annotate_opts.objdump_path) {
 			status = -ENOMEM;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 	if (addr2line_path) {
 		symbol_conf.addr2line_path = strdup(addr2line_path);
 		if (!symbol_conf.addr2line_path) {
 			status = -ENOMEM;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 
 	status = symbol__validate_sym_arguments();
 	if (status)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if (annotate_check_args() < 0)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if (!top.evlist->core.nr_entries) {
 		struct evlist *def_evlist = evlist__new_default();
 
 		if (!def_evlist)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 
 		evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
-		evlist__delete(def_evlist);
+		evlist__put(def_evlist);
 	}
 
 	status = evswitch__init(&top.evswitch, top.evlist, stderr);
 	if (status)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if (symbol_conf.report_hierarchy) {
 		/* disable incompatible options */
@@ -1717,18 +1717,18 @@ int cmd_top(int argc, const char **argv)
 			pr_err("Error: --hierarchy and --fields options cannot be used together\n");
 			parse_options_usage(top_usage, options, "fields", 0);
 			parse_options_usage(NULL, options, "hierarchy", 0);
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 
 	if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
 		pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	if (nr_cgroups > 0 && opts->record_cgroup) {
 		pr_err("--cgroup and --all-cgroups cannot be used together\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	if (branch_call_mode) {
@@ -1752,7 +1752,7 @@ int cmd_top(int argc, const char **argv)
 		status = perf_env__read_core_pmu_caps(&host_env);
 		if (status) {
 			pr_err("PMU capability data is not available\n");
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 
@@ -1775,7 +1775,7 @@ int cmd_top(int argc, const char **argv)
 	if (IS_ERR(top.session)) {
 		status = PTR_ERR(top.session);
 		top.session = NULL;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 	top.evlist->session = top.session;
 
@@ -1785,7 +1785,7 @@ int cmd_top(int argc, const char **argv)
 		if (field_order)
 			parse_options_usage(sort_order ? NULL : top_usage,
 					    options, "fields", 0);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	status = target__validate(target);
@@ -1800,11 +1800,11 @@ int cmd_top(int argc, const char **argv)
 		if (uid == UINT_MAX) {
 			ui__error("Invalid User: %s", top.uid_str);
 			status = -EINVAL;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 		status = parse_uid_filter(top.evlist, uid);
 		if (status)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 
 	if (target__none(target))
@@ -1814,7 +1814,7 @@ int cmd_top(int argc, const char **argv)
 		ui__error("Couldn't create thread/CPU maps: %s\n",
 			  errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
 		status = -errno;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	if (top.delay_secs < 1)
@@ -1822,7 +1822,7 @@ int cmd_top(int argc, const char **argv)
 
 	if (record_opts__config(opts)) {
 		status = -EINVAL;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	top.sym_evsel = evlist__first(top.evlist);
@@ -1837,14 +1837,14 @@ int cmd_top(int argc, const char **argv)
 
 	status = symbol__annotation_init();
 	if (status < 0)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	annotation_config__init();
 
 	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 	status = symbol__init(NULL);
 	if (status < 0)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	sort__setup_elide(stdout);
 
@@ -1864,13 +1864,13 @@ int cmd_top(int argc, const char **argv)
 		if (top.sb_evlist == NULL) {
 			pr_err("Couldn't create side band evlist.\n.");
 			status = -EINVAL;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
 			pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
 			status = -EINVAL;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 #endif
@@ -1885,8 +1885,8 @@ int cmd_top(int argc, const char **argv)
 	if (!opts->no_bpf_event)
 		evlist__stop_sb_thread(top.sb_evlist);
 
-out_delete_evlist:
-	evlist__delete(top.evlist);
+out_put_evlist:
+	evlist__put(top.evlist);
 	perf_session__delete(top.session);
 	annotation_options__exit();
 	perf_env__exit(&host_env);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index a743bda294bd..c056df42a78f 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -4364,7 +4364,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
 	if (trace->summary_bpf) {
 		if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 
 		if (trace->summary_only)
 			goto create_maps;
@@ -4432,19 +4432,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 	err = evlist__create_maps(evlist, &trace->opts.target);
 	if (err < 0) {
 		fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	err = trace__symbols_init(trace, argc, argv, evlist);
 	if (err < 0) {
 		fprintf(trace->output, "Problems initializing symbol libraries!\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
 		trace->syscall_stats = alloc_syscall_stats();
 		if (IS_ERR(trace->syscall_stats))
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 
 	evlist__config(evlist, &trace->opts, &callchain_param);
@@ -4453,7 +4453,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 		err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
 		if (err < 0) {
 			fprintf(trace->output, "Couldn't run the workload!\n");
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 		workload_pid = evlist->workload.pid;
 	}
@@ -4501,7 +4501,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
 	err = trace__expand_filters(trace, &evsel);
 	if (err)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
 	if (err < 0)
 		goto out_error_apply_filters;
@@ -4618,12 +4618,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 		}
 	}
 
-out_delete_evlist:
+out_put_evlist:
 	trace_cleanup_bpf_summary();
 	delete_syscall_stats(trace->syscall_stats);
 	trace__symbols__exit(trace);
 	evlist__free_syscall_tp_fields(evlist);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	cgroup__put(trace->cgroup);
 	trace->evlist = NULL;
 	trace->live = false;
@@ -4648,22 +4648,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 
 out_error:
 	fprintf(trace->output, "%s\n", errbuf);
-	goto out_delete_evlist;
+	goto out_put_evlist;
 
 out_error_apply_filters:
 	fprintf(trace->output,
 		"Failed to set filter \"%s\" on event %s with %d (%s)\n",
 		evsel->filter, evsel__name(evsel), errno,
 		str_error_r(errno, errbuf, sizeof(errbuf)));
-	goto out_delete_evlist;
+	goto out_put_evlist;
 }
 out_error_mem:
 	fprintf(trace->output, "Not enough memory to run!\n");
-	goto out_delete_evlist;
+	goto out_put_evlist;
 
 out_errno:
 	fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
-	goto out_delete_evlist;
+	goto out_put_evlist;
 }
 
 static int trace__replay(struct trace *trace)
@@ -5331,7 +5331,7 @@ static void trace__exit(struct trace *trace)
 		zfree(&trace->syscalls.table);
 	}
 	zfree(&trace->perfconfig_events);
-	evlist__delete(trace->evlist);
+	evlist__put(trace->evlist);
 	trace->evlist = NULL;
 	ordered_events__free(&trace->oe.data);
 #ifdef HAVE_LIBBPF_SUPPORT
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
index c5e7999f2817..2b49b002d749 100644
--- a/tools/perf/tests/backward-ring-buffer.c
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
 	err = evlist__create_maps(evlist, &opts.target);
 	if (err < 0) {
 		pr_debug("Not enough memory to create thread/cpu maps\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	parse_events_error__init(&parse_error);
@@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
 	if (err) {
 		pr_debug("Failed to parse tracepoint event, try use root\n");
 		ret = TEST_SKIP;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__config(evlist, &opts, NULL);
@@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
 	if (err < 0) {
 		pr_debug("perf_evlist__open: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	ret = TEST_FAIL;
 	err = do_test(evlist, opts.mmap_pages, &sample_count,
 		      &comm_count);
 	if (err != TEST_OK)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
 		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
 		       sample_count, comm_count);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__close(evlist);
@@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
 	if (err < 0) {
 		pr_debug("perf_evlist__open: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	err = do_test(evlist, 1, &sample_count, &comm_count);
 	if (err != TEST_OK)
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	ret = TEST_OK;
-out_delete_evlist:
-	evlist__delete(evlist);
+out_put_evlist:
+	evlist__put(evlist);
 	return ret;
 }
 
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 5927d1ea20e2..8da8951154d8 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -806,7 +806,7 @@ static int do_test_code_reading(bool try_kcore)
 			}
 
 			perf_evlist__set_maps(&evlist->core, NULL, NULL);
-			evlist__delete(evlist);
+			evlist__put(evlist);
 			evlist = NULL;
 			continue;
 		}
@@ -843,7 +843,7 @@ static int do_test_code_reading(bool try_kcore)
 out_put:
 	thread__put(thread);
 out_err:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
 	machine__delete(machine);
diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
index ae3b98bb42cf..94ab54ecd3f9 100644
--- a/tools/perf/tests/event-times.c
+++ b/tools/perf/tests/event-times.c
@@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
 	err = attach(evlist);
 	if (err == TEST_SKIP) {
 		pr_debug("  SKIP  : not enough rights\n");
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		return err;
 	}
 
@@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
 		 count.ena, count.run);
 
 out_err:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return !err ? TEST_OK : TEST_FAIL;
 }
 
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
index cb9e6de2e033..8de66dac52b0 100644
--- a/tools/perf/tests/event_update.c
+++ b/tools/perf/tests/event_update.c
@@ -115,7 +115,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
 	TEST_ASSERT_VAL("failed to synthesize attr update cpus",
 			!perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
 
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return 0;
 }
 
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 1922cac13a24..6a220634c52f 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
 				if (err) {
 					pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
 						name);
-					evlist__delete(evlist);
+					evlist__put(evlist);
 					continue;
 				}
 				evlist__for_each_entry(evlist, evsel) {
@@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
 						ret = TEST_FAIL;
 					}
 				}
-				evlist__delete(evlist);
+				evlist__put(evlist);
 			}
 		}
 	}
@@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
 		if (err) {
 			pr_debug("failed to parse event '%s', err %d\n",
 				 names[i], err);
-			evlist__delete(evlist);
+			evlist__put(evlist);
 			ret = TEST_FAIL;
 			continue;
 		}
@@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
 				ret = TEST_FAIL;
 			}
 		}
-		evlist__delete(evlist);
+		evlist__put(evlist);
 	}
 	return ret;
 }
diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
index c7b32a220ca1..9060b085e3de 100644
--- a/tools/perf/tests/expand-cgroup.c
+++ b/tools/perf/tests/expand-cgroup.c
@@ -104,7 +104,7 @@ static int expand_default_events(void)
 	TEST_ASSERT_VAL("failed to get evlist", evlist);
 
 	ret = test_expand_events(evlist);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
@@ -131,7 +131,7 @@ static int expand_group_events(void)
 	ret = test_expand_events(evlist);
 out:
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
@@ -162,7 +162,7 @@ static int expand_libpfm_events(void)
 
 	ret = test_expand_events(evlist);
 out:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
@@ -186,7 +186,7 @@ static int expand_metric_events(void)
 	ret = test_expand_events(evlist);
 
 out:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 3eb9ef8d7ec6..8f7cce7b5085 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
 
 out:
 	/* tear down everything */
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	machines__exit(&machines);
 	put_fake_samples();
 
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 1cebd20cc91c..447fb2b5947c 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -331,7 +331,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
 
 out:
 	/* tear down everything */
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	reset_output_field();
 	machines__exit(&machines);
 	put_fake_samples();
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 996f5f0b3bd1..9646c3b7b4de 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
 
 out:
 	/* tear down everything */
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	reset_output_field();
 	machines__exit(&machines);
 	put_fake_samples();
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index ee5ec8bda60e..aa8565fbaf90 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
 
 out:
 	/* tear down everything */
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	machines__exit(&machines);
 	put_fake_samples();
 
diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
index 97ea036ebae6..7d1040619575 100644
--- a/tools/perf/tests/hwmon_pmu.c
+++ b/tools/perf/tests/hwmon_pmu.c
@@ -211,7 +211,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
 
 out:
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 729cc9cc1cb7..51cfd6522867 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
 out_err:
 	if (evlist) {
 		evlist__disable(evlist);
-		evlist__delete(evlist);
+		evlist__put(evlist);
 	}
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index a622bb8d4cc8..2591b6fbec3f 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -93,7 +93,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 				/* Permissions failure, flag the failure as a skip. */
 				err = TEST_SKIP;
 			}
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		evsels[i]->core.attr.wakeup_events = 1;
@@ -105,7 +105,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 			pr_debug("failed to open counter: %s, "
 				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 				 str_error_r(errno, sbuf, sizeof(sbuf)));
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		nr_events[i] = 0;
@@ -115,7 +115,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 	if (evlist__mmap(evlist, 128) < 0) {
 		pr_debug("failed to mmap events: %d (%s)\n", errno,
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	for (i = 0; i < nsyscalls; ++i)
@@ -133,7 +133,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 		if (event->header.type != PERF_RECORD_SAMPLE) {
 			pr_debug("unexpected %s event\n",
 				 perf_event__name(event->header.type));
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		perf_sample__init(&sample, /*all=*/false);
@@ -141,7 +141,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 		if (err) {
 			pr_err("Can't parse sample, err = %d\n", err);
 			perf_sample__exit(&sample);
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		err = -1;
@@ -150,7 +150,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 		if (evsel == NULL) {
 			pr_debug("event with id %" PRIu64
 				 " doesn't map to an evsel\n", sample.id);
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 		nr_events[evsel->core.idx]++;
 		perf_mmap__consume(&md->core);
@@ -165,12 +165,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 				 expected_nr_events[evsel->core.idx],
 				 evsel__name(evsel), nr_events[evsel->core.idx]);
 			err = -1;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 
-out_delete_evlist:
-	evlist__delete(evlist);
+out_put_evlist:
+	evlist__put(evlist);
 out_free_cpus:
 	perf_cpu_map__put(cpus);
 out_free_threads:
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 2a139d2781a8..3ff595c7a86a 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 	if (IS_ERR(evsel)) {
 		pr_debug("%s: evsel__newtp\n", __func__);
 		ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__add(evlist, evsel);
@@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 	err = evlist__create_maps(evlist, &opts.target);
 	if (err < 0) {
 		pr_debug("%s: evlist__create_maps\n", __func__);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evsel__config(evsel, &opts, NULL);
@@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 	if (err < 0) {
 		pr_debug("perf_evlist__open: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	err = evlist__mmap(evlist, UINT_MAX);
 	if (err < 0) {
 		pr_debug("evlist__mmap: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__enable(evlist);
@@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 				if (err) {
 					pr_debug("Can't parse sample, err = %d\n", err);
 					perf_sample__exit(&sample);
-					goto out_delete_evlist;
+					goto out_put_evlist;
 				}
 
 				tp_flags = evsel__intval(evsel, &sample, "flags");
@@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 				if (flags != tp_flags) {
 					pr_debug("%s: Expected flags=%#x, got %#x\n",
 						 __func__, flags, tp_flags);
-					goto out_delete_evlist;
+					goto out_put_evlist;
 				}
 
 				goto out_ok;
@@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
 
 		if (++nr_polls > 5) {
 			pr_debug("%s: no events!\n", __func__);
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 	}
 out_ok:
 	ret = TEST_OK;
-out_delete_evlist:
-	evlist__delete(evlist);
+out_put_evlist:
+	evlist__put(evlist);
 out:
 	return ret;
 }
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index e4cdb517c10e..0778462016f7 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -2550,7 +2550,7 @@ static int test_event(const struct evlist_test *e)
 		ret = e->check(evlist);
 	}
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 
 	return ret;
 }
@@ -2576,7 +2576,7 @@ static int test_event_fake_pmu(const char *str)
 	}
 
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 
 	return ret;
 }
diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 66a5275917e2..b343628c7a7e 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -83,7 +83,7 @@ static int __compute_metric(const char *name, struct value *vals,
 
 	cpus = perf_cpu_map__new("0");
 	if (!cpus) {
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		return -ENOMEM;
 	}
 
@@ -112,7 +112,7 @@ static int __compute_metric(const char *name, struct value *vals,
 	/* ... cleanup. */
 	evlist__free_stats(evlist);
 	perf_cpu_map__put(cpus);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return err;
 }
 
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 50e68b7d43aa..d5a8d065809e 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
 	for (i = 0; i < count && !err; i++)
 		err = process_event(&evlist, events[i]);
 
-	evlist__delete(evlist);
+	evlist__put(evlist);
 
 	return err;
 }
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index efbd9cd60c63..babec674b83c 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -102,7 +102,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 	err = evlist__create_maps(evlist, &opts.target);
 	if (err < 0) {
 		pr_debug("Not enough memory to create thread/cpu maps\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	/*
@@ -114,7 +114,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 	err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
 	if (err < 0) {
 		pr_debug("Couldn't run the workload!\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	/*
@@ -131,7 +131,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 		pr_debug("sched__get_first_possible_cpu: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		evlist__cancel_workload(evlist);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	cpu = err;
@@ -143,7 +143,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 		pr_debug("sched_setaffinity: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		evlist__cancel_workload(evlist);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	/*
@@ -155,7 +155,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 		pr_debug("perf_evlist__open: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		evlist__cancel_workload(evlist);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	/*
@@ -168,7 +168,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 		pr_debug("evlist__mmap: %s\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		evlist__cancel_workload(evlist);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	/*
@@ -206,7 +206,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 					if (verbose > 0)
 						perf_event__fprintf(event, NULL, stderr);
 					pr_debug("Couldn't parse sample\n");
-					goto out_delete_evlist;
+					goto out_put_evlist;
 				}
 
 				if (verbose > 0) {
@@ -346,9 +346,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
 		pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
 		++errs;
 	}
-out_delete_evlist:
+out_put_evlist:
 	CPU_FREE(cpu_mask);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 out:
 	perf_sample__exit(&sample);
 	if (err == -EACCES)
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index cca41bd37ae3..d3538fa20af3 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
 	err = TEST_OK;
 
 out_err:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
 	return err;
diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
index 2e38dfa34b6c..099a50dec37e 100644
--- a/tools/perf/tests/pfm.c
+++ b/tools/perf/tests/pfm.c
@@ -79,7 +79,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
 				evlist__nr_groups(evlist),
 				0);
 
-		evlist__delete(evlist);
+		evlist__put(evlist);
 	}
 	return 0;
 }
@@ -164,7 +164,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
 				evlist__nr_groups(evlist),
 				table[i].nr_groups);
 
-		evlist__delete(evlist);
+		evlist__put(evlist);
 	}
 	return 0;
 }
diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
index f40a828c9861..ab547f301c61 100644
--- a/tools/perf/tests/pmu-events.c
+++ b/tools/perf/tests/pmu-events.c
@@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
 			     /*warn_if_reordered=*/true, /*fake_tp=*/false);
 	free(dup);
 
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
@@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
 
 	cpus = perf_cpu_map__new("0");
 	if (!cpus) {
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		return -ENOMEM;
 	}
 
@@ -901,7 +901,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
 	/* ... cleanup. */
 	evlist__free_stats(evlist);
 	perf_cpu_map__put(cpus);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return err;
 }
 
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index cbded2c6faa4..bd3f4a2806ed 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -249,7 +249,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
 	ret = TEST_OK;
 err_out:
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	test_pmu_put(dir, pmu);
 	return ret;
 }
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 4a2ad7176fa0..f7f1f16638b4 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -58,7 +58,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 	evsel = evsel__new(&attr);
 	if (evsel == NULL) {
 		pr_debug("evsel__new\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 	evlist__add(evlist, evsel);
 
@@ -67,7 +67,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 	if (!cpus || !threads) {
 		err = -ENOMEM;
 		pr_debug("Not enough memory to create thread/cpu maps\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	perf_evlist__set_maps(&evlist->core, cpus, threads);
@@ -79,14 +79,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 		pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)),
 			 knob, (u64)attr.sample_freq);
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	err = evlist__mmap(evlist, 128);
 	if (err < 0) {
 		pr_debug("failed to mmap event: %d (%s)\n", errno,
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__enable(evlist);
@@ -112,7 +112,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 		if (err < 0) {
 			pr_debug("Error during parse sample\n");
 			perf_sample__exit(&sample);
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		total_periods += sample.period;
@@ -130,10 +130,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
 		err = -1;
 	}
 
-out_delete_evlist:
+out_put_evlist:
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return err;
 }
 
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index 15791fcb76b2..c3d5825df0a8 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -577,7 +577,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
 out:
 	if (evlist) {
 		evlist__disable(evlist);
-		evlist__delete(evlist);
+		evlist__put(evlist);
 	}
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 4053ff2813bb..a46650b10689 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
 	if (!cpus || !threads) {
 		err = -ENOMEM;
 		pr_debug("Not enough memory to create thread/cpu maps\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	perf_evlist__set_maps(&evlist->core, cpus, threads);
@@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
 	err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
 	if (err < 0) {
 		pr_debug("Couldn't run the workload!\n");
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evsel = evlist__first(evlist);
@@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
 	if (err < 0) {
 		pr_debug("Couldn't open the evlist: %s\n",
 			 str_error_r(-err, sbuf, sizeof(sbuf)));
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	if (evlist__mmap(evlist, 128) < 0) {
 		pr_debug("failed to mmap events: %d (%s)\n", errno,
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		err = -1;
-		goto out_delete_evlist;
+		goto out_put_evlist;
 	}
 
 	evlist__start_workload(evlist);
@@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
 		if (retry_count++ > 1000) {
 			pr_debug("Failed after retrying 1000 times\n");
 			err = -1;
-			goto out_delete_evlist;
+			goto out_put_evlist;
 		}
 
 		goto retry;
@@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
 		err = -1;
 	}
 
-out_delete_evlist:
+out_put_evlist:
 	perf_cpu_map__put(cpus);
 	perf_thread_map__put(threads);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return err;
 }
 
diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
index 1e900ef92e37..e78ff9dcea97 100644
--- a/tools/perf/tests/tool_pmu.c
+++ b/tools/perf/tests/tool_pmu.c
@@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
 
 out:
 	parse_events_error__exit(&err);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return ret;
 }
 
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index af4618c3124a..b88447899021 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -55,7 +55,7 @@ static int session_write_header(char *path)
 			!perf_session__write_header(session, session->evlist,
 						    perf_data__fd(&data), true));
 
-	evlist__delete(session->evlist);
+	evlist__put(session->evlist);
 	perf_session__delete(session);
 
 	return 0;
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 25e2769b5e74..ed230cd44ba7 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -503,8 +503,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
 	cgrp_event_expanded = true;
 
 out_err:
-	evlist__delete(orig_list);
-	evlist__delete(tmp_list);
+	evlist__put(orig_list);
+	evlist__put(tmp_list);
 	metricgroup__rblist_exit(&orig_metric_events);
 	release_cgroup_list();
 
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 3d2e437e1354..1166cdb00aca 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1331,7 +1331,7 @@ static void cleanup_events(struct perf_session *session)
 		zfree(&evsel->priv);
 	}
 
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	session->evlist = NULL;
 }
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d99a3f12606f..ea1f398c14e3 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -73,7 +73,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
 #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
 #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
 
-void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
+static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
 		  struct perf_thread_map *threads)
 {
 	perf_evlist__init(&evlist->core);
@@ -85,6 +85,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
 	evlist->ctl_fd.pos = -1;
 	evlist->nr_br_cntr = -1;
 	metricgroup__rblist_init(&evlist->metric_events);
+	refcount_set(&evlist->refcnt, 1);
 }
 
 struct evlist *evlist__new(void)
@@ -116,7 +117,7 @@ struct evlist *evlist__new_default(void)
 			 can_profile_kernel ? "P" : "Pu");
 		err = parse_event(evlist, buf);
 		if (err) {
-			evlist__delete(evlist);
+			evlist__put(evlist);
 			return NULL;
 		}
 	}
@@ -136,13 +137,19 @@ struct evlist *evlist__new_dummy(void)
 	struct evlist *evlist = evlist__new();
 
 	if (evlist && evlist__add_dummy(evlist)) {
-		evlist__delete(evlist);
+		evlist__put(evlist);
 		evlist = NULL;
 	}
 
 	return evlist;
 }
 
+struct evlist *evlist__get(struct evlist *evlist)
+{
+	refcount_inc(&evlist->refcnt);
+	return evlist;
+}
+
 /**
  * evlist__set_id_pos - set the positions of event ids.
  * @evlist: selected event list
@@ -181,7 +188,7 @@ static void evlist__purge(struct evlist *evlist)
 	evlist->core.nr_entries = 0;
 }
 
-void evlist__exit(struct evlist *evlist)
+static void evlist__exit(struct evlist *evlist)
 {
 	metricgroup__rblist_exit(&evlist->metric_events);
 	event_enable_timer__exit(&evlist->eet);
@@ -190,11 +197,14 @@ void evlist__exit(struct evlist *evlist)
 	perf_evlist__exit(&evlist->core);
 }
 
-void evlist__delete(struct evlist *evlist)
+void evlist__put(struct evlist *evlist)
 {
 	if (evlist == NULL)
 		return;
 
+	if (!refcount_dec_and_test(&evlist->refcnt))
+		return;
+
 	evlist__free_stats(evlist);
 	evlist__munmap(evlist);
 	evlist__close(evlist);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 61acbb10d9a5..66fb5da08160 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -59,6 +59,7 @@ struct event_enable_timer;
 
 struct evlist {
 	struct perf_evlist core;
+	refcount_t	 refcnt;
 	bool		 enabled;
 	int		 id_pos;
 	int		 is_pos;
@@ -104,10 +105,8 @@ struct evsel_str_handler {
 struct evlist *evlist__new(void);
 struct evlist *evlist__new_default(void);
 struct evlist *evlist__new_dummy(void);
-void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
-		  struct perf_thread_map *threads);
-void evlist__exit(struct evlist *evlist);
-void evlist__delete(struct evlist *evlist);
+struct evlist *evlist__get(struct evlist *evlist);
+void evlist__put(struct evlist *evlist);
 
 void evlist__add(struct evlist *evlist, struct evsel *entry);
 void evlist__remove(struct evlist *evlist, struct evsel *evsel);
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index 7fda0ff89c16..4304b53b5a37 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -451,7 +451,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
 		ret = parse_event(tmp, id) ? 0 : 1;
 	}
 out:
-	evlist__delete(tmp);
+	evlist__put(tmp);
 	return ret;
 }
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4f2a6e10ed5c..e959ddb12dc8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -4307,12 +4307,12 @@ int perf_session__read_header(struct perf_session *session)
 		evsel = evsel__new(&f_attr.attr);
 
 		if (evsel == NULL)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 
 		evsel->needs_swap = header->needs_swap;
 		/*
 		 * Do it before so that if perf_evsel__alloc_id fails, this
-		 * entry gets purged too at evlist__delete().
+		 * entry gets purged too at evlist__put().
 		 */
 		evlist__add(session->evlist, evsel);
 
@@ -4323,7 +4323,7 @@ int perf_session__read_header(struct perf_session *session)
 		 * hattr->ids threads.
 		 */
 		if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
-			goto out_delete_evlist;
+			goto out_put_evlist;
 
 		lseek(fd, f_attr.ids.offset, SEEK_SET);
 
@@ -4342,7 +4342,7 @@ int perf_session__read_header(struct perf_session *session)
 				      perf_file_section__process);
 
 	if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
-		goto out_delete_evlist;
+		goto out_put_evlist;
 #else
 	perf_header__process_sections(header, fd, NULL, perf_file_section__process);
 #endif
@@ -4351,8 +4351,8 @@ int perf_session__read_header(struct perf_session *session)
 out_errno:
 	return -errno;
 
-out_delete_evlist:
-	evlist__delete(session->evlist);
+out_put_evlist:
+	evlist__put(session->evlist);
 	session->evlist = NULL;
 	return -ENOMEM;
 }
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index 595b83142d2c..64c64dff7424 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -212,7 +212,7 @@ static void metric__free(struct metric *m)
 	zfree(&m->metric_refs);
 	expr__ctx_free(m->pctx);
 	zfree(&m->modifier);
-	evlist__delete(m->evlist);
+	evlist__put(m->evlist);
 	free(m);
 }
 
@@ -1318,7 +1318,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
 	parsed_evlist = NULL;
 err_out:
 	parse_events_error__exit(&parse_error);
-	evlist__delete(parsed_evlist);
+	evlist__put(parsed_evlist);
 	strbuf_release(&events);
 	return ret;
 }
@@ -1470,7 +1470,7 @@ static int parse_groups(struct evlist *perf_evlist,
 
 	if (combined_evlist) {
 		evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
-		evlist__delete(combined_evlist);
+		evlist__put(combined_evlist);
 	}
 
 	list_for_each_entry(m, &metric_list, nd) {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 0c0dc20b1c13..607ab7b82486 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -2223,7 +2223,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
 
 	/*
 	 * There are 2 users - builtin-record and builtin-test objects.
-	 * Both call evlist__delete in case of error, so we dont
+	 * Both call evlist__put in case of error, so we dont
 	 * need to bother.
 	 */
 	return ret;
@@ -2424,7 +2424,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
 	}
 	ret = parse_events_option(opt, str, unset);
 	if (ret) {
-		evlist__delete(*args->evlistp);
+		evlist__put(*args->evlistp);
 		*args->evlistp = NULL;
 	}
 
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index 3345145a9307..8cd254d36220 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -56,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
 	err = 0;
 
 out_delete:
-	evlist__delete(evlist);
+	evlist__put(evlist);
 	return err;
 }
 
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index dfc6e9299af9..4149a51e9878 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1273,7 +1273,7 @@ static int pyrf_evsel__setup_types(void)
 struct pyrf_evlist {
 	PyObject_HEAD
 
-	struct evlist evlist;
+	struct evlist *evlist;
 };
 
 static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
@@ -1286,15 +1286,21 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
 	if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
 		return -1;
 
+	pevlist->evlist = evlist__new();
+	if (!pevlist->evlist) {
+		PyErr_NoMemory();
+		return -1;
+	}
 	threads = ((struct pyrf_thread_map *)pthreads)->threads;
 	cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
-	evlist__init(&pevlist->evlist, cpus, threads);
+	perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
+
 	return 0;
 }
 
 static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
 {
-	evlist__exit(&pevlist->evlist);
+	evlist__put(pevlist->evlist);
 	Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
 }
 
@@ -1303,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
 	struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
 
 	if (pcpu_map)
-		pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
+		pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
 
 	return (PyObject *)pcpu_map;
 }
@@ -1316,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
 	if (!list)
 		return NULL;
 
-	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
+	for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
 	     node = rb_next(node)) {
 		struct metric_event *me = container_of(node, struct metric_event, nd);
 		struct list_head *pos;
@@ -1400,7 +1406,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
 	if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
 		return NULL;
 
-	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
+	for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
 	     mexp == NULL && node;
 	     node = rb_next(node)) {
 		struct metric_event *me = container_of(node, struct metric_event, nd);
@@ -1456,7 +1462,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 	static char *kwlist[] = { "pages", "overwrite", NULL };
 	int pages = 128, overwrite = false;
 
@@ -1476,7 +1482,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 	static char *kwlist[] = { "timeout", NULL };
 	int timeout = -1, n;
 
@@ -1496,7 +1502,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
 					 PyObject *args __maybe_unused,
 					 PyObject *kwargs __maybe_unused)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
         PyObject *list = PyList_New(0);
 	int i;
 
@@ -1525,7 +1531,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
 				  PyObject *args,
 				  PyObject *kwargs __maybe_unused)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 	PyObject *pevsel;
 	struct evsel *evsel;
 
@@ -1557,7 +1563,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
 static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
 					  PyObject *args, PyObject *kwargs)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 	union perf_event *event;
 	int sample_id_all = 1, cpu;
 	static char *kwlist[] = { "cpu", "sample_id_all", NULL };
@@ -1614,7 +1620,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
 static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
 				   PyObject *args, PyObject *kwargs)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 
 	if (evlist__open(evlist) < 0) {
 		PyErr_SetFromErrno(PyExc_OSError);
@@ -1627,7 +1633,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
 
 static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
 {
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 
 	evlist__close(evlist);
 
@@ -1653,7 +1659,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
 		.no_buffering        = true,
 		.no_inherit          = true,
 	};
-	struct evlist *evlist = &pevlist->evlist;
+	struct evlist *evlist = pevlist->evlist;
 
 	evlist__config(evlist, &opts, &callchain_param);
 	Py_INCREF(Py_None);
@@ -1662,14 +1668,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
 
 static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
 {
-	evlist__disable(&pevlist->evlist);
+	evlist__disable(pevlist->evlist);
 	Py_INCREF(Py_None);
 	return Py_None;
 }
 
 static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
 {
-	evlist__enable(&pevlist->evlist);
+	evlist__enable(pevlist->evlist);
 	Py_INCREF(Py_None);
 	return Py_None;
 }
@@ -1760,7 +1766,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
 {
 	struct pyrf_evlist *pevlist = (void *)obj;
 
-	return pevlist->evlist.core.nr_entries;
+	return pevlist->evlist->core.nr_entries;
+}
+
+static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
+{
+	struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
+
+	if (!pevsel)
+		return NULL;
+
+	memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
+	evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
+
+	evsel__clone(&pevsel->evsel, evsel);
+	if (evsel__is_group_leader(evsel))
+		evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
+	return (PyObject *)pevsel;
 }
 
 static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
@@ -1768,17 +1790,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
 	struct pyrf_evlist *pevlist = (void *)obj;
 	struct evsel *pos;
 
-	if (i >= pevlist->evlist.core.nr_entries) {
+	if (i >= pevlist->evlist->core.nr_entries) {
 		PyErr_SetString(PyExc_IndexError, "Index out of range");
 		return NULL;
 	}
 
-	evlist__for_each_entry(&pevlist->evlist, pos) {
+	evlist__for_each_entry(pevlist->evlist, pos) {
 		if (i-- == 0)
 			break;
 	}
-
-	return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
+	return pyrf_evsel__from_evsel(pos);
 }
 
 static PyObject *pyrf_evlist__str(PyObject *self)
@@ -1790,7 +1811,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
 	PyObject *result;
 
 	strbuf_addstr(&sb, "evlist([");
-	evlist__for_each_entry(&pevlist->evlist, pos) {
+	evlist__for_each_entry(pevlist->evlist, pos) {
 		if (!first)
 			strbuf_addch(&sb, ',');
 		if (!pos->pmu)
@@ -1931,110 +1952,30 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
 	return PyLong_FromLong(tp_pmu__id(sys, name));
 }
 
-static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
-{
-	struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
-
-	if (!pevsel)
-		return NULL;
-
-	memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
-	evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
-
-	evsel__clone(&pevsel->evsel, evsel);
-	if (evsel__is_group_leader(evsel))
-		evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
-	return (PyObject *)pevsel;
-}
-
-static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
-{
-	struct evsel *pos;
-	int idx = 0;
-
-	evlist__for_each_entry(evlist, pos) {
-		if (evsel == pos)
-			return idx;
-		idx++;
-	}
-	return -1;
-}
-
-static struct evsel *evlist__at(struct evlist *evlist, int idx)
-{
-	struct evsel *pos;
-	int idx2 = 0;
-
-	evlist__for_each_entry(evlist, pos) {
-		if (idx == idx2)
-			return pos;
-		idx2++;
-	}
-	return NULL;
-}
-
 static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
 {
 	struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
-	struct evsel *pos;
-	struct rb_node *node;
 
 	if (!pevlist)
 		return NULL;
 
-	memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
-	evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
-	evlist__for_each_entry(evlist, pos) {
-		struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
-
-		evlist__add(&pevlist->evlist, &pevsel->evsel);
-	}
-	evlist__for_each_entry(&pevlist->evlist, pos) {
-		struct evsel *leader = evsel__leader(pos);
-
-		if (pos != leader) {
-			int idx = evlist__pos(evlist, leader);
-
-			if (idx >= 0)
-				evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
-			else if (leader == NULL)
-				evsel__set_leader(pos, pos);
-		}
-	}
-	metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
-					&pevlist->evlist.metric_events,
-					&evlist->metric_events);
-	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
-	     node = rb_next(node)) {
-		struct metric_event *me = container_of(node, struct metric_event, nd);
-		struct list_head *mpos;
-		int idx = evlist__pos(evlist, me->evsel);
-
-		if (idx >= 0)
-			me->evsel = evlist__at(&pevlist->evlist, idx);
-		list_for_each(mpos, &me->head) {
-			struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
-
-			for (int j = 0; e->metric_events[j]; j++) {
-				idx = evlist__pos(evlist, e->metric_events[j]);
-				if (idx >= 0)
-					e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
-			}
-		}
-	}
+	pevlist->evlist = evlist__get(evlist);
 	return (PyObject *)pevlist;
 }
 
 static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
 {
 	const char *input;
-	struct evlist evlist = {};
+	struct evlist *evlist = evlist__new();
 	struct parse_events_error err;
 	PyObject *result;
 	PyObject *pcpus = NULL, *pthreads = NULL;
 	struct perf_cpu_map *cpus;
 	struct perf_thread_map *threads;
 
+	if (!evlist)
+		return PyErr_NoMemory();
+
 	if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
 		return NULL;
 
@@ -2042,35 +1983,38 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
 	cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
 
 	parse_events_error__init(&err);
-	evlist__init(&evlist, cpus, threads);
-	if (parse_events(&evlist, input, &err)) {
+	perf_evlist__set_maps(&evlist->core, cpus, threads);
+	if (parse_events(evlist, input, &err)) {
 		parse_events_error__print(&err, input);
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
-	result = pyrf_evlist__from_evlist(&evlist);
-	evlist__exit(&evlist);
+	result = pyrf_evlist__from_evlist(evlist);
+	evlist__put(evlist);
 	return result;
 }
 
 static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
 {
 	const char *input, *pmu = NULL;
-	struct evlist evlist = {};
+	struct evlist *evlist = evlist__new();
 	PyObject *result;
 	PyObject *pcpus = NULL, *pthreads = NULL;
 	struct perf_cpu_map *cpus;
 	struct perf_thread_map *threads;
 	int ret;
 
+	if (!evlist)
+		return PyErr_NoMemory();
+
 	if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
 		return NULL;
 
 	threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
 	cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
 
-	evlist__init(&evlist, cpus, threads);
-	ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
+	perf_evlist__set_maps(&evlist->core, cpus, threads);
+	ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
 					/*metric_no_group=*/ false,
 					/*metric_no_merge=*/ false,
 					/*metric_no_threshold=*/ true,
@@ -2082,8 +2026,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
 		PyErr_SetFromErrno(PyExc_OSError);
 		return NULL;
 	}
-	result = pyrf_evlist__from_evlist(&evlist);
-	evlist__exit(&evlist);
+	result = pyrf_evlist__from_evlist(evlist);
+	evlist__put(evlist);
 	return result;
 }
 
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index e867de8ddaaa..8a5fc7d5e43c 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
 	ret = true;
 
 out_delete:
-	evlist__delete(temp_evlist);
+	evlist__put(temp_evlist);
 	return ret;
 }
 
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 081e68c72c30..f241d91221d7 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -256,7 +256,7 @@ void perf_session__delete(struct perf_session *session)
 	machines__exit(&session->machines);
 	if (session->data) {
 		if (perf_data__is_read(session->data))
-			evlist__delete(session->evlist);
+			evlist__put(session->evlist);
 		perf_data__close(session->data);
 	}
 #ifdef HAVE_LIBTRACEEVENT
diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
index 388846f17bc1..b84a5463e039 100644
--- a/tools/perf/util/sideband_evlist.c
+++ b/tools/perf/util/sideband_evlist.c
@@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
 		return 0;
 
 	if (evlist__create_maps(evlist, target))
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	if (evlist->core.nr_entries > 1) {
 		bool can_sample_identifier = perf_can_sample_identifier();
@@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
 	evlist__for_each_entry(evlist, counter) {
 		if (evsel__open(counter, evlist->core.user_requested_cpus,
 				evlist->core.threads) < 0)
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 
 	if (evlist__mmap(evlist, UINT_MAX))
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	evlist__for_each_entry(evlist, counter) {
 		if (evsel__enable(counter))
-			goto out_delete_evlist;
+			goto out_put_evlist;
 	}
 
 	evlist->thread.done = 0;
 	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
-		goto out_delete_evlist;
+		goto out_put_evlist;
 
 	return 0;
 
-out_delete_evlist:
-	evlist__delete(evlist);
+out_put_evlist:
+	evlist__put(evlist);
 	evlist = NULL;
 	return -1;
 }
@@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
 		return;
 	evlist->thread.done = 1;
 	pthread_join(evlist->thread.th, NULL);
-	evlist__delete(evlist);
+	evlist__put(evlist);
 }
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 13/15] perf evsel: Add reference count
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (11 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 12/15] perf evlist: Add reference count Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 14/15] perf python: Add access to evsel and phys_addr in event Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 15/15] perf mem-phys-addr.py: Port to standalone application from perf script Ian Rogers
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

As with evlist this a no-op for most of the perf tool. The reference
count is set to 1 at allocation, the put will see the 1, decrement it
and perform the delete. The purpose for adding the reference count is
for the python code. Prior to this change the python code would clone
evsels, but this has issues if events are opened, etc. leading to
assertion failures. With a reference count the same evsel can be used
and the reference count incremented for the python usage.  To not
change the python evsel API getset functions are added for the evsel
members, no set function is provided for size as it doesn't make sense
to alter this.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-trace.c                 |  12 +-
 tools/perf/tests/evsel-tp-sched.c          |   4 +-
 tools/perf/tests/openat-syscall-all-cpus.c |   6 +-
 tools/perf/tests/openat-syscall.c          |   6 +-
 tools/perf/util/bpf_counter_cgroup.c       |   2 +-
 tools/perf/util/cgroup.c                   |   2 +-
 tools/perf/util/evlist.c                   |   2 +-
 tools/perf/util/evsel.c                    |  26 ++-
 tools/perf/util/evsel.h                    |  11 +-
 tools/perf/util/parse-events.y             |   2 +-
 tools/perf/util/pfm.c                      |   2 +-
 tools/perf/util/print-events.c             |   2 +-
 tools/perf/util/python.c                   | 212 +++++++++++++++++----
 13 files changed, 218 insertions(+), 71 deletions(-)

diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c056df42a78f..1168759983da 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -449,10 +449,10 @@ static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field,
 	({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
 	   evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
 
-static void evsel__delete_priv(struct evsel *evsel)
+static void evsel__put_and_free_priv(struct evsel *evsel)
 {
 	zfree(&evsel->priv);
-	evsel__delete(evsel);
+	evsel__put(evsel);
 }
 
 static int evsel__init_syscall_tp(struct evsel *evsel)
@@ -532,7 +532,7 @@ static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *
 	return evsel;
 
 out_delete:
-	evsel__delete_priv(evsel);
+	evsel__put_and_free_priv(evsel);
 	return NULL;
 }
 
@@ -3560,7 +3560,7 @@ static bool evlist__add_vfs_getname(struct evlist *evlist)
 
 		list_del_init(&evsel->core.node);
 		evsel->evlist = NULL;
-		evsel__delete(evsel);
+		evsel__put(evsel);
 	}
 
 	return found;
@@ -3674,9 +3674,9 @@ static int trace__add_syscall_newtp(struct trace *trace)
 	return ret;
 
 out_delete_sys_exit:
-	evsel__delete_priv(sys_exit);
+	evsel__put_and_free_priv(sys_exit);
 out_delete_sys_enter:
-	evsel__delete_priv(sys_enter);
+	evsel__put_and_free_priv(sys_enter);
 	goto out;
 }
 
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 226196fb9677..9e456f88a13a 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -64,7 +64,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse
 	if (evsel__test_field(evsel, "next_prio", 4, true))
 		ret = TEST_FAIL;
 
-	evsel__delete(evsel);
+	evsel__put(evsel);
 
 	evsel = evsel__newtp("sched", "sched_wakeup");
 
@@ -85,7 +85,7 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse
 	if (evsel__test_field(evsel, "target_cpu", 4, true))
 		ret = TEST_FAIL;
 
-	evsel__delete(evsel);
+	evsel__put(evsel);
 	return ret;
 }
 
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index 3644d6f52c07..605d41295e8a 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -58,7 +58,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb
 			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		err = TEST_SKIP;
-		goto out_evsel_delete;
+		goto out_evsel_put;
 	}
 
 	perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
@@ -115,8 +115,8 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb
 	evsel__free_counts(evsel);
 out_close_fd:
 	perf_evsel__close_fd(&evsel->core);
-out_evsel_delete:
-	evsel__delete(evsel);
+out_evsel_put:
+	evsel__put(evsel);
 out_cpu_map_delete:
 	perf_cpu_map__put(cpus);
 out_thread_map_delete:
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index b54cbe5f1808..9f16f0dd3a29 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -42,7 +42,7 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused,
 			 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 			 str_error_r(errno, sbuf, sizeof(sbuf)));
 		err = TEST_SKIP;
-		goto out_evsel_delete;
+		goto out_evsel_put;
 	}
 
 	for (i = 0; i < nr_openat_calls; ++i) {
@@ -64,8 +64,8 @@ static int test__openat_syscall_event(struct test_suite *test __maybe_unused,
 	err = TEST_OK;
 out_close_fd:
 	perf_evsel__close_fd(&evsel->core);
-out_evsel_delete:
-	evsel__delete(evsel);
+out_evsel_put:
+	evsel__put(evsel);
 out_thread_map_delete:
 	perf_thread_map__put(threads);
 	return err;
diff --git a/tools/perf/util/bpf_counter_cgroup.c b/tools/perf/util/bpf_counter_cgroup.c
index 68bd994c8880..f12c45c27c40 100644
--- a/tools/perf/util/bpf_counter_cgroup.c
+++ b/tools/perf/util/bpf_counter_cgroup.c
@@ -314,7 +314,7 @@ static int bperf_cgrp__destroy(struct evsel *evsel)
 		return 0;
 
 	bperf_cgroup_bpf__destroy(skel);
-	evsel__delete(cgrp_switch);  // it'll destroy on_switch progs too
+	evsel__put(cgrp_switch);  // it'll destroy on_switch progs too
 
 	return 0;
 }
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index ed230cd44ba7..5409878e3ec6 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -468,7 +468,7 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
 
 		leader = NULL;
 		evlist__for_each_entry(orig_list, pos) {
-			evsel = evsel__clone(/*dest=*/NULL, pos);
+			evsel = evsel__clone(pos);
 			if (evsel == NULL)
 				goto out_err;
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea1f398c14e3..bfa99d0c9e25 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -182,7 +182,7 @@ static void evlist__purge(struct evlist *evlist)
 	evlist__for_each_entry_safe(evlist, n, pos) {
 		list_del_init(&pos->core.node);
 		pos->evlist = NULL;
-		evsel__delete(pos);
+		evsel__put(pos);
 	}
 
 	evlist->core.nr_entries = 0;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 6769cd27b6e4..514ad4797562 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -385,10 +385,11 @@ bool evsel__is_function_event(struct evsel *evsel)
 #undef FUNCTION_EVENT
 }
 
-void evsel__init(struct evsel *evsel,
+static void evsel__init(struct evsel *evsel,
 		 struct perf_event_attr *attr, int idx)
 {
 	perf_evsel__init(&evsel->core, attr, idx);
+	refcount_set(&evsel->refcnt, 1);
 	evsel->tracking	   = !idx;
 	evsel->unit	   = strdup("");
 	evsel->scale	   = 1.0;
@@ -470,7 +471,7 @@ static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src)
  * The assumption is that @orig is not configured nor opened yet.
  * So we only care about the attributes that can be set while it's parsed.
  */
-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
+struct evsel *evsel__clone(struct evsel *orig)
 {
 	struct evsel *evsel;
 
@@ -483,11 +484,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
 	if (orig->bpf_obj)
 		return NULL;
 
-	if (dest)
-		evsel = dest;
-	else
-		evsel = evsel__new(&orig->core.attr);
-
+	evsel = evsel__new(&orig->core.attr);
 	if (evsel == NULL)
 		return NULL;
 
@@ -571,7 +568,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig)
 	return evsel;
 
 out_err:
-	evsel__delete(evsel);
+	evsel__put(evsel);
 	return NULL;
 }
 
@@ -630,6 +627,12 @@ struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx, bool
 	return ERR_PTR(err);
 }
 
+struct evsel *evsel__get(struct evsel *evsel)
+{
+	refcount_inc(&evsel->refcnt);
+	return evsel;
+}
+
 #ifdef HAVE_LIBTRACEEVENT
 struct tep_event *evsel__tp_format(struct evsel *evsel)
 {
@@ -1728,7 +1731,7 @@ void evsel__set_priv_destructor(void (*destructor)(void *priv))
 	evsel__priv_destructor = destructor;
 }
 
-void evsel__exit(struct evsel *evsel)
+static void evsel__exit(struct evsel *evsel)
 {
 	assert(list_empty(&evsel->core.node));
 	assert(evsel->evlist == NULL);
@@ -1764,11 +1767,14 @@ void evsel__exit(struct evsel *evsel)
 		xyarray__delete(evsel->start_times);
 }
 
-void evsel__delete(struct evsel *evsel)
+void evsel__put(struct evsel *evsel)
 {
 	if (!evsel)
 		return;
 
+	if (!refcount_dec_and_test(&evsel->refcnt))
+		return;
+
 	evsel__exit(evsel);
 	free(evsel);
 }
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index f4540920604e..2e65a3d84a7f 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -8,6 +8,7 @@
 #include <internal/evsel.h>
 #include <linux/list.h>
 #include <linux/perf_event.h>
+#include <linux/refcount.h>
 #include <linux/types.h>
 #include <perf/evsel.h>
 
@@ -46,6 +47,7 @@ typedef int (evsel__sb_cb_t)(union perf_event *event, void *data);
 struct evsel {
 	struct perf_evsel	core;
 	struct evlist		*evlist;
+	refcount_t		refcnt;
 	off_t			id_offset;
 	int			id_pos;
 	int			is_pos;
@@ -258,7 +260,7 @@ static inline struct evsel *evsel__new(struct perf_event_attr *attr)
 	return evsel__new_idx(attr, 0);
 }
 
-struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig);
+struct evsel *evsel__clone(struct evsel *orig);
 
 int copy_config_terms(struct list_head *dst, struct list_head *src);
 void free_config_terms(struct list_head *config_terms);
@@ -273,14 +275,13 @@ static inline struct evsel *evsel__newtp(const char *sys, const char *name)
 	return evsel__newtp_idx(sys, name, 0, true);
 }
 
+struct evsel *evsel__get(struct evsel *evsel);
+void evsel__put(struct evsel *evsel);
+
 #ifdef HAVE_LIBTRACEEVENT
 struct tep_event *evsel__tp_format(struct evsel *evsel);
 #endif
 
-void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx);
-void evsel__exit(struct evsel *evsel);
-void evsel__delete(struct evsel *evsel);
-
 void evsel__set_priv_destructor(void (*destructor)(void *priv));
 
 struct callchain_param;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index c194de5ec1ec..b531b1f0ceb3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -47,7 +47,7 @@ static void free_list_evsel(struct list_head* list_evsel)
 
 	list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) {
 		list_del_init(&evsel->core.node);
-		evsel__delete(evsel);
+		evsel__put(evsel);
 	}
 	free(list_evsel);
 }
diff --git a/tools/perf/util/pfm.c b/tools/perf/util/pfm.c
index e5b3a2a5ddef..f226ffd2b596 100644
--- a/tools/perf/util/pfm.c
+++ b/tools/perf/util/pfm.c
@@ -158,7 +158,7 @@ static bool is_libpfm_event_supported(const char *name, struct perf_cpu_map *cpu
 		result = false;
 
 	evsel__close(evsel);
-	evsel__delete(evsel);
+	evsel__put(evsel);
 
 	return result;
 }
diff --git a/tools/perf/util/print-events.c b/tools/perf/util/print-events.c
index 8f3ed83853a9..bbefbc49a062 100644
--- a/tools/perf/util/print-events.c
+++ b/tools/perf/util/print-events.c
@@ -179,7 +179,7 @@ bool is_event_supported(u8 type, u64 config)
 		}
 
 		evsel__close(evsel);
-		evsel__delete(evsel);
+		evsel__put(evsel);
 	}
 
 	perf_thread_map__put(tmap);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 4149a51e9878..27410b3fb7c5 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -275,6 +275,7 @@ static PyMemberDef pyrf_sample_event__members[] = {
 
 static void pyrf_sample_event__delete(struct pyrf_event *pevent)
 {
+	evsel__put(pevent->evsel);
 	perf_sample__exit(&pevent->sample);
 	Py_TYPE(pevent)->tp_free((PyObject*)pevent);
 }
@@ -946,7 +947,7 @@ static int pyrf_counts_values__setup_types(void)
 struct pyrf_evsel {
 	PyObject_HEAD
 
-	struct evsel evsel;
+	struct evsel *evsel;
 };
 
 static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
@@ -1054,20 +1055,20 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
 	attr.sample_id_all  = sample_id_all;
 	attr.size	    = sizeof(attr);
 
-	evsel__init(&pevsel->evsel, &attr, idx);
-	return 0;
+	pevsel->evsel = evsel__new(&attr);
+	return pevsel->evsel ? 0 : -1;
 }
 
 static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
 {
-	evsel__exit(&pevsel->evsel);
+	evsel__put(pevsel->evsel);
 	Py_TYPE(pevsel)->tp_free((PyObject*)pevsel);
 }
 
 static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
 				  PyObject *args, PyObject *kwargs)
 {
-	struct evsel *evsel = &pevsel->evsel;
+	struct evsel *evsel = pevsel->evsel;
 	struct perf_cpu_map *cpus = NULL;
 	struct perf_thread_map *threads = NULL;
 	PyObject *pcpus = NULL, *pthreads = NULL;
@@ -1103,7 +1104,7 @@ static PyObject *pyrf_evsel__cpus(struct pyrf_evsel *pevsel)
 	struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
 
 	if (pcpu_map)
-		pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel.core.cpus);
+		pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel->core.cpus);
 
 	return (PyObject *)pcpu_map;
 }
@@ -1114,7 +1115,7 @@ static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel)
 		PyObject_New(struct pyrf_thread_map, &pyrf_thread_map__type);
 
 	if (pthread_map)
-		pthread_map->threads = perf_thread_map__get(pevsel->evsel.core.threads);
+		pthread_map->threads = perf_thread_map__get(pevsel->evsel->core.threads);
 
 	return (PyObject *)pthread_map;
 }
@@ -1148,7 +1149,7 @@ static int evsel__ensure_counts(struct evsel *evsel)
 static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
 				  PyObject *args, PyObject *kwargs)
 {
-	struct evsel *evsel = &pevsel->evsel;
+	struct evsel *evsel = pevsel->evsel;
 	int cpu = 0, cpu_idx, thread = 0, thread_idx;
 	struct perf_counts_values *old_count, *new_count;
 	struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values,
@@ -1193,7 +1194,7 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
 static PyObject *pyrf_evsel__str(PyObject *self)
 {
 	struct pyrf_evsel *pevsel = (void *)self;
-	struct evsel *evsel = &pevsel->evsel;
+	struct evsel *evsel = pevsel->evsel;
 
 	return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel));
 }
@@ -1226,26 +1227,170 @@ static PyMethodDef pyrf_evsel__methods[] = {
 	{ .ml_name = NULL, }
 };
 
-#define evsel_member_def(member, ptype, help) \
-	{ #member, ptype, \
-	  offsetof(struct pyrf_evsel, evsel.member), \
-	  0, help }
+static PyObject *pyrf_evsel__get_tracking(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
 
-#define evsel_attr_member_def(member, ptype, help) \
-	{ #member, ptype, \
-	  offsetof(struct pyrf_evsel, evsel.core.attr.member), \
-	  0, help }
+	if (pevsel->evsel->tracking)
+		Py_RETURN_TRUE;
+	else
+		Py_RETURN_FALSE;
+}
 
-static PyMemberDef pyrf_evsel__members[] = {
-	evsel_member_def(tracking, T_BOOL, "tracking event."),
-	evsel_attr_member_def(type, T_UINT, "attribute type."),
-	evsel_attr_member_def(size, T_UINT, "attribute size."),
-	evsel_attr_member_def(config, T_ULONGLONG, "attribute config."),
-	evsel_attr_member_def(sample_period, T_ULONGLONG, "attribute sample_period."),
-	evsel_attr_member_def(sample_type, T_ULONGLONG, "attribute sample_type."),
-	evsel_attr_member_def(read_format, T_ULONGLONG, "attribute read_format."),
-	evsel_attr_member_def(wakeup_events, T_UINT, "attribute wakeup_events."),
-	{ .name = NULL, },
+static int pyrf_evsel__set_tracking(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->tracking = Py_IsTrue(val) ? true : false;
+	return 0;
+}
+
+static int pyrf_evsel__set_attr_config(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.config = PyLong_AsUnsignedLongLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_config(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.config);
+}
+
+static int pyrf_evsel__set_attr_read_format(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.read_format = PyLong_AsUnsignedLongLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_read_format(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.read_format);
+}
+
+static int pyrf_evsel__set_attr_sample_period(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.sample_period = PyLong_AsUnsignedLongLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_sample_period(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_period);
+}
+
+static int pyrf_evsel__set_attr_sample_type(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.sample_type = PyLong_AsUnsignedLongLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_sample_type(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLongLong(pevsel->evsel->core.attr.sample_type);
+}
+
+static PyObject *pyrf_evsel__get_attr_size(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.size);
+}
+
+static int pyrf_evsel__set_attr_type(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.type = PyLong_AsUnsignedLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_type(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.type);
+}
+
+static int pyrf_evsel__set_attr_wakeup_events(PyObject *self, PyObject *val, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	pevsel->evsel->core.attr.wakeup_events = PyLong_AsUnsignedLong(val);
+	return PyErr_Occurred() ? -1 : 0;
+}
+
+static PyObject *pyrf_evsel__get_attr_wakeup_events(PyObject *self, void */*closure*/)
+{
+	struct pyrf_evsel *pevsel = (void *)self;
+
+	return PyLong_FromUnsignedLong(pevsel->evsel->core.attr.wakeup_events);
+}
+
+static PyGetSetDef pyrf_evsel__getset[] = {
+	{
+		.name = "tracking",
+		.get = pyrf_evsel__get_tracking,
+		.set = pyrf_evsel__set_tracking,
+		.doc = "tracking event.",
+	},
+	{
+		.name = "config",
+		.get = pyrf_evsel__get_attr_config,
+		.set = pyrf_evsel__set_attr_config,
+		.doc = "attribute config.",
+	},
+	{
+		.name = "read_format",
+		.get = pyrf_evsel__get_attr_read_format,
+		.set = pyrf_evsel__set_attr_read_format,
+		.doc = "attribute read_format.",
+	},
+	{
+		.name = "sample_period",
+		.get = pyrf_evsel__get_attr_sample_period,
+		.set = pyrf_evsel__set_attr_sample_period,
+		.doc = "attribute sample_period.",
+	},
+	{
+		.name = "sample_type",
+		.get = pyrf_evsel__get_attr_sample_type,
+		.set = pyrf_evsel__set_attr_sample_type,
+		.doc = "attribute sample_type.",
+	},
+	{
+		.name = "size",
+		.get = pyrf_evsel__get_attr_size,
+		.doc = "attribute size.",
+	},
+	{
+		.name = "type",
+		.get = pyrf_evsel__get_attr_type,
+		.set = pyrf_evsel__set_attr_type,
+		.doc = "attribute type.",
+	},
+	{
+		.name = "wakeup_events",
+		.get = pyrf_evsel__get_attr_wakeup_events,
+		.set = pyrf_evsel__set_attr_wakeup_events,
+		.doc = "attribute wakeup_events.",
+	},
+	{ .name = NULL},
 };
 
 static const char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
@@ -1257,7 +1402,7 @@ static PyTypeObject pyrf_evsel__type = {
 	.tp_dealloc	= (destructor)pyrf_evsel__delete,
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_evsel__doc,
-	.tp_members	= pyrf_evsel__members,
+	.tp_getset	= pyrf_evsel__getset,
 	.tp_methods	= pyrf_evsel__methods,
 	.tp_init	= (initproc)pyrf_evsel__init,
 	.tp_str         = pyrf_evsel__str,
@@ -1539,7 +1684,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
 		return NULL;
 
 	Py_INCREF(pevsel);
-	evsel = &((struct pyrf_evsel *)pevsel)->evsel;
+	evsel = ((struct pyrf_evsel *)pevsel)->evsel;
 	evsel->core.idx = evlist->core.nr_entries;
 	evlist__add(evlist, evsel);
 
@@ -1776,12 +1921,7 @@ static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
 	if (!pevsel)
 		return NULL;
 
-	memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
-	evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
-
-	evsel__clone(&pevsel->evsel, evsel);
-	if (evsel__is_group_leader(evsel))
-		evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
+	pevsel->evsel = evsel__get(evsel);
 	return (PyObject *)pevsel;
 }
 
@@ -2188,7 +2328,7 @@ static int pyrf_session_tool__sample(const struct perf_tool *tool,
 	if (pyevent == NULL)
 		return -ENOMEM;
 
-	pevent->evsel = evsel;
+	pevent->evsel = evsel__get(evsel);
 	memcpy(&pevent->sample, sample, sizeof(struct perf_sample));
 
 	PyObject_CallFunction(psession->sample, "O", pyevent);
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 14/15] perf python: Add access to evsel and phys_addr in event
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (12 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 13/15] perf evsel: " Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  2025-10-29  5:34 ` [RFC PATCH v1 15/15] perf mem-phys-addr.py: Port to standalone application from perf script Ian Rogers
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Use the reference counting to wrap the evsel in the sample processing
pyrf_event and access using a getter routine.
Expose the phys_addr in the perf_sample.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/util/python.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 27410b3fb7c5..09098c1112d3 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -32,6 +32,8 @@
 
 PyMODINIT_FUNC PyInit_perf(void);
 
+static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel);
+
 #define member_def(type, member, ptype, help) \
 	{ #member, ptype, \
 	  offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
@@ -55,11 +57,29 @@ struct pyrf_event {
 	sample_member_def(sample_tid, tid, T_INT, "event tid"),			 \
 	sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"),		 \
 	sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"),		 \
+	sample_member_def(sample_phys_addr, phys_addr, T_ULONGLONG, "event physical addr"),		 \
 	sample_member_def(sample_id, id, T_ULONGLONG, "event id"),			 \
 	sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \
 	sample_member_def(sample_period, period, T_ULONGLONG, "event period"),		 \
 	sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
 
+static PyObject *pyrf_event__get_evsel(PyObject *self, void */*closure*/)
+{
+	struct pyrf_event *pevent = (void *)self;
+
+	return pyrf_evsel__from_evsel(pevent->evsel);
+}
+
+static PyGetSetDef pyrf_event__getset[] = {
+	{
+		.name = "evsel",
+		.get = pyrf_event__get_evsel,
+		.set = NULL,
+		.doc = "tracking event.",
+	},
+	{ .name = NULL, },
+};
+
 static const char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
 
 static PyMemberDef pyrf_mmap_event__members[] = {
@@ -101,6 +121,7 @@ static PyTypeObject pyrf_mmap_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_mmap_event__doc,
 	.tp_members	= pyrf_mmap_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_mmap_event__repr,
 };
 
@@ -136,6 +157,7 @@ static PyTypeObject pyrf_task_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_task_event__doc,
 	.tp_members	= pyrf_task_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_task_event__repr,
 };
 
@@ -165,6 +187,7 @@ static PyTypeObject pyrf_comm_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_comm_event__doc,
 	.tp_members	= pyrf_comm_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_comm_event__repr,
 };
 
@@ -197,6 +220,7 @@ static PyTypeObject pyrf_throttle_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_throttle_event__doc,
 	.tp_members	= pyrf_throttle_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_throttle_event__repr,
 };
 
@@ -232,6 +256,7 @@ static PyTypeObject pyrf_lost_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_lost_event__doc,
 	.tp_members	= pyrf_lost_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_lost_event__repr,
 };
 
@@ -262,6 +287,7 @@ static PyTypeObject pyrf_read_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_read_event__doc,
 	.tp_members	= pyrf_read_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_read_event__repr,
 };
 
@@ -387,6 +413,7 @@ static PyTypeObject pyrf_sample_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_sample_event__doc,
 	.tp_members	= pyrf_sample_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_sample_event__repr,
 	.tp_getattro	= (getattrofunc) pyrf_sample_event__getattro,
 };
@@ -425,6 +452,7 @@ static PyTypeObject pyrf_context_switch_event__type = {
 	.tp_flags	= Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
 	.tp_doc		= pyrf_context_switch_event__doc,
 	.tp_members	= pyrf_context_switch_event__members,
+	.tp_getset	= pyrf_event__getset,
 	.tp_repr	= (reprfunc)pyrf_context_switch_event__repr,
 };
 
@@ -1196,7 +1224,7 @@ static PyObject *pyrf_evsel__str(PyObject *self)
 	struct pyrf_evsel *pevsel = (void *)self;
 	struct evsel *evsel = pevsel->evsel;
 
-	return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel));
+	return PyUnicode_FromFormat("evsel(%s)", evsel__name(evsel));
 }
 
 static PyMethodDef pyrf_evsel__methods[] = {
@@ -1954,10 +1982,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
 	evlist__for_each_entry(pevlist->evlist, pos) {
 		if (!first)
 			strbuf_addch(&sb, ',');
-		if (!pos->pmu)
-			strbuf_addstr(&sb, evsel__name(pos));
-		else
-			strbuf_addf(&sb, "%s/%s/", pos->pmu->name, evsel__name(pos));
+		strbuf_addstr(&sb, evsel__name(pos));
 		first = false;
 	}
 	strbuf_addstr(&sb, "])");
-- 
2.51.1.851.g4ebd6896fd-goog


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

* [RFC PATCH v1 15/15] perf mem-phys-addr.py: Port to standalone application from perf script
  2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
                   ` (13 preceding siblings ...)
  2025-10-29  5:34 ` [RFC PATCH v1 14/15] perf python: Add access to evsel and phys_addr in event Ian Rogers
@ 2025-10-29  5:34 ` Ian Rogers
  14 siblings, 0 replies; 22+ messages in thread
From: Ian Rogers @ 2025-10-29  5:34 UTC (permalink / raw)
  To: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
	Jiri Olsa, Ian Rogers, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

Give an example of using the perf python session API to load a
perf.data file and perform the behavior of
tools/perf/scripts/python/mem-phys-addr.py.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/python/mem-phys-addr.py | 117 +++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 tools/perf/python/mem-phys-addr.py

diff --git a/tools/perf/python/mem-phys-addr.py b/tools/perf/python/mem-phys-addr.py
new file mode 100644
index 000000000000..32bb63598239
--- /dev/null
+++ b/tools/perf/python/mem-phys-addr.py
@@ -0,0 +1,117 @@
+# mem-phys-addr.py: Resolve physical address samples
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2018, Intel Corporation.
+
+import bisect
+import collections
+import os
+import perf
+import re
+import sys
+from dataclasses import dataclass
+from typing import (Dict, Optional)
+
+@dataclass(frozen=True)
+class IomemEntry:
+    """Read from a line in /proc/iomem"""
+    begin: int
+    end: int
+    indent: int
+    label: str
+
+# Physical memory layout from /proc/iomem. Key is the indent and then
+# a list of ranges.
+iomem: Dict[int, list[IomemEntry]] = collections.defaultdict(list)
+# Child nodes from the iomem parent.
+children: Dict[IomemEntry, set[IomemEntry]] = collections.defaultdict(set)
+# Maximum indent seen before an entry in the iomem file.
+max_indent: int = 0
+# Count for each range of memory.
+load_mem_type_cnt: Dict[IomemEntry, int] = collections.Counter()
+# Perf event name set from the first sample in the data.
+event_name: Optional[str] = None
+
+def parse_iomem():
+    """Populate iomem from /proc/iomem file"""
+    global iomem
+    global max_indent
+    global children
+    with open('/proc/iomem', 'r', encoding='ascii') as f:
+        for line in f:
+            indent = 0
+            while line[indent] == ' ':
+                indent += 1
+            if indent > max_indent:
+                max_indent = indent
+            m = re.split('-|:', line, maxsplit=2)
+            begin = int(m[0], 16)
+            end = int(m[1], 16)
+            label = m[2].strip()
+            entry = IomemEntry(begin, end, indent, label)
+            # Before adding entry, search for a parent node using its begin.
+            if indent > 0:
+                parent = find_memory_type(begin)
+                assert parent, f"Given indent expected a parent for {label}"
+                children[parent].add(entry)
+            iomem[indent].append(entry)
+
+def find_memory_type(phys_addr) -> Optional[IomemEntry]:
+    """Search iomem for the range containing phys_addr with the maximum indent"""
+    for i in range(max_indent, -1, -1):
+        if i not in iomem:
+            continue
+        position = bisect.bisect_right(iomem[i], phys_addr,
+                                       key=lambda entry: entry.begin)
+        if position is None:
+            continue
+        iomem_entry = iomem[i][position-1]
+        if  iomem_entry.begin <= phys_addr <= iomem_entry.end:
+            return iomem_entry
+    print(f"Didn't find {phys_addr}")
+    return None
+
+def print_memory_type():
+    print(f"Event: {event_name}")
+    print(f"{'Memory type':<40}  {'count':>10}  {'percentage':>10}")
+    print(f"{'-' * 40:<40}  {'-' * 10:>10}  {'-' * 10:>10}")
+    total = sum(load_mem_type_cnt.values())
+    # Add count from children into the parent.
+    for i in range(max_indent, -1, -1):
+        if i not in iomem:
+            continue
+        for entry in iomem[i]:
+            global children
+            for child in children[entry]:
+                if load_mem_type_cnt[child] > 0:
+                    load_mem_type_cnt[entry] += load_mem_type_cnt[child]
+
+    def print_entries(entries):
+        """Print counts from parents down to their children"""
+        global children
+        for entry in sorted(entries,
+                            key = lambda entry: load_mem_type_cnt[entry],
+                            reverse = True):
+            count = load_mem_type_cnt[entry]
+            if count > 0:
+                mem_type = ' ' * entry.indent + f"{entry.begin:x}-{entry.end:x} : {entry.label}"
+                percent = 100 * count / total
+                print(f"{mem_type:<40}  {count:>10}  {percent:>10.1f}")
+                print_entries(children[entry])
+
+    print_entries(iomem[0])
+
+if __name__ == "__main__":
+    def process_event(sample):
+        phys_addr  = sample.sample_phys_addr
+        entry = find_memory_type(phys_addr)
+        if entry:
+            load_mem_type_cnt[entry] += 1
+
+            global event_name
+            if event_name is None:
+                event_name  = str(sample.evsel)
+
+    parse_iomem()
+    perf.session(perf.data("perf.data"), sample=process_event).process_events()
+    print_memory_type()
-- 
2.51.1.851.g4ebd6896fd-goog


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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29  5:34 ` [RFC PATCH v1 12/15] perf evlist: Add reference count Ian Rogers
@ 2025-10-29 16:22   ` Arnaldo Carvalho de Melo
  2025-10-29 16:25     ` Arnaldo Carvalho de Melo
  2025-10-29 16:56     ` Ian Rogers
  0 siblings, 2 replies; 22+ messages in thread
From: Arnaldo Carvalho de Melo @ 2025-10-29 16:22 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> This a no-op for most of the perf tool. The reference count is set to
> 1 at allocation, the put will see the 1, decrement it and perform the
> delete. The purpose for adding the reference count is for the python
> code. Prior to this change the python code would clone evlists, but
> this has issues if events are opened, etc. This change adds a
> reference count for the evlists and a later change will add it to
> evsels. The combination is needed for the python code to operate
> correctly (not hit asserts in the evsel clone), but the changes are
> broken apart for the sake of smaller patches.

Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
are not using the RC_CHK_ACCESS stuff from the get go, why not?

All the prep patches looks ok, assuming they build in succession.

- Arnaldo
 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/arch/x86/tests/hybrid.c          |   2 +-
>  tools/perf/arch/x86/tests/topdown.c         |   2 +-
>  tools/perf/arch/x86/util/iostat.c           |   2 +-
>  tools/perf/bench/evlist-open-close.c        |  18 +-
>  tools/perf/builtin-ftrace.c                 |   8 +-
>  tools/perf/builtin-kvm.c                    |   4 +-
>  tools/perf/builtin-lock.c                   |   2 +-
>  tools/perf/builtin-record.c                 |   4 +-
>  tools/perf/builtin-stat.c                   |   8 +-
>  tools/perf/builtin-top.c                    |  52 +++---
>  tools/perf/builtin-trace.c                  |  26 +--
>  tools/perf/tests/backward-ring-buffer.c     |  18 +-
>  tools/perf/tests/code-reading.c             |   4 +-
>  tools/perf/tests/event-times.c              |   4 +-
>  tools/perf/tests/event_update.c             |   2 +-
>  tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
>  tools/perf/tests/expand-cgroup.c            |   8 +-
>  tools/perf/tests/hists_cumulate.c           |   2 +-
>  tools/perf/tests/hists_filter.c             |   2 +-
>  tools/perf/tests/hists_link.c               |   2 +-
>  tools/perf/tests/hists_output.c             |   2 +-
>  tools/perf/tests/hwmon_pmu.c                |   2 +-
>  tools/perf/tests/keep-tracking.c            |   2 +-
>  tools/perf/tests/mmap-basic.c               |  18 +-
>  tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
>  tools/perf/tests/parse-events.c             |   4 +-
>  tools/perf/tests/parse-metric.c             |   4 +-
>  tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
>  tools/perf/tests/perf-record.c              |  18 +-
>  tools/perf/tests/perf-time-to-tsc.c         |   2 +-
>  tools/perf/tests/pfm.c                      |   4 +-
>  tools/perf/tests/pmu-events.c               |   6 +-
>  tools/perf/tests/pmu.c                      |   2 +-
>  tools/perf/tests/sw-clock.c                 |  14 +-
>  tools/perf/tests/switch-tracking.c          |   2 +-
>  tools/perf/tests/task-exit.c                |  14 +-
>  tools/perf/tests/tool_pmu.c                 |   2 +-
>  tools/perf/tests/topology.c                 |   2 +-
>  tools/perf/util/cgroup.c                    |   4 +-
>  tools/perf/util/data-convert-bt.c           |   2 +-
>  tools/perf/util/evlist.c                    |  20 ++-
>  tools/perf/util/evlist.h                    |   7 +-
>  tools/perf/util/expr.c                      |   2 +-
>  tools/perf/util/header.c                    |  12 +-
>  tools/perf/util/metricgroup.c               |   6 +-
>  tools/perf/util/parse-events.c              |   4 +-
>  tools/perf/util/perf_api_probe.c            |   2 +-
>  tools/perf/util/python.c                    | 176 +++++++-------------
>  tools/perf/util/record.c                    |   2 +-
>  tools/perf/util/session.c                   |   2 +-
>  tools/perf/util/sideband_evlist.c           |  16 +-
>  51 files changed, 252 insertions(+), 299 deletions(-)
> 
> diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
> index e221ea104174..dfb0ffc0d030 100644
> --- a/tools/perf/arch/x86/tests/hybrid.c
> +++ b/tools/perf/arch/x86/tests/hybrid.c
> @@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
>  		ret = e->check(evlist);
>  	}
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  
>  	return ret;
>  }
> diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
> index 1eba3b4594ef..b31aef4ef28b 100644
> --- a/tools/perf/arch/x86/tests/topdown.c
> +++ b/tools/perf/arch/x86/tests/topdown.c
> @@ -55,7 +55,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
>  			*ret = TEST_FAIL;
>  		}
>  	}
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return 0;
>  }
>  
> diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
> index 7442a2cd87ed..e0417552b0cb 100644
> --- a/tools/perf/arch/x86/util/iostat.c
> +++ b/tools/perf/arch/x86/util/iostat.c
> @@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
>  	if (evlist->core.nr_entries > 0) {
>  		pr_warning("The -e and -M options are not supported."
>  			   "All chosen events/metrics will be dropped\n");
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		evlist = evlist__new();
>  		if (!evlist)
>  			return -ENOMEM;
> diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
> index bfaf50e4e519..a802fb005ee3 100644
> --- a/tools/perf/bench/evlist-open-close.c
> +++ b/tools/perf/bench/evlist-open-close.c
> @@ -75,7 +75,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
>  		parse_events_error__exit(&err);
>  		pr_err("Run 'perf list' for a list of valid events\n");
>  		ret = 1;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  	parse_events_error__exit(&err);
>  	if (uid_str) {
> @@ -84,24 +84,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
>  		if (uid == UINT_MAX) {
>  			pr_err("Invalid User: %s", uid_str);
>  			ret = -EINVAL;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  		ret = parse_uid_filter(evlist, uid);
>  		if (ret)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  	ret = evlist__create_maps(evlist, &opts.target);
>  	if (ret < 0) {
>  		pr_err("Not enough memory to create thread/cpu maps\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__config(evlist, &opts, NULL);
>  
>  	return evlist;
>  
> -out_delete_evlist:
> -	evlist__delete(evlist);
> +out_put_evlist:
> +	evlist__put(evlist);
>  	return NULL;
>  }
>  
> @@ -150,7 +150,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
>  		evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
>  	printf("  Number of iterations:\t%d\n", iterations);
>  
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  
>  	for (i = 0; i < iterations; i++) {
>  		pr_debug("Started iteration %d\n", i);
> @@ -161,7 +161,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
>  		gettimeofday(&start, NULL);
>  		err = bench__do_evlist_open_close(evlist);
>  		if (err) {
> -			evlist__delete(evlist);
> +			evlist__put(evlist);
>  			return err;
>  		}
>  
> @@ -170,7 +170,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
>  		runtime_us = timeval2usec(&diff);
>  		update_stats(&time_stats, runtime_us);
>  
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
>  	}
>  
> diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
> index 6b6eec65f93f..4a2fe05e9786 100644
> --- a/tools/perf/builtin-ftrace.c
> +++ b/tools/perf/builtin-ftrace.c
> @@ -1993,20 +1993,20 @@ int cmd_ftrace(int argc, const char **argv)
>  
>  	ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
>  	if (ret < 0)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if (argc) {
>  		ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
>  					       argv, false,
>  					       ftrace__workload_exec_failed_signal);
>  		if (ret < 0)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  
>  	ret = cmd_func(&ftrace);
>  
> -out_delete_evlist:
> -	evlist__delete(ftrace.evlist);
> +out_put_evlist:
> +	evlist__put(ftrace.evlist);
>  
>  out_delete_filters:
>  	delete_filter_func(&ftrace.filters);
> diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> index f0f285763f19..b07cbe051e33 100644
> --- a/tools/perf/builtin-kvm.c
> +++ b/tools/perf/builtin-kvm.c
> @@ -1806,7 +1806,7 @@ static struct evlist *kvm_live_event_list(void)
>  
>  out:
>  	if (err) {
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		evlist = NULL;
>  	}
>  
> @@ -1937,7 +1937,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
>  out:
>  	perf_session__delete(kvm->session);
>  	kvm->session = NULL;
> -	evlist__delete(kvm->evlist);
> +	evlist__put(kvm->evlist);
>  
>  	return err;
>  }
> diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
> index 078634461df2..2a57767f03a9 100644
> --- a/tools/perf/builtin-lock.c
> +++ b/tools/perf/builtin-lock.c
> @@ -2143,7 +2143,7 @@ static int __cmd_contention(int argc, const char **argv)
>  
>  out_delete:
>  	lock_filter_finish();
> -	evlist__delete(con.evlist);
> +	evlist__put(con.evlist);
>  	lock_contention_finish(&con);
>  	perf_session__delete(session);
>  	perf_env__exit(&host_env);
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 3d8cf4090a92..738dbae80eac 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -4349,7 +4349,7 @@ int cmd_record(int argc, const char **argv)
>  			goto out;
>  
>  		evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
> -		evlist__delete(def_evlist);
> +		evlist__put(def_evlist);
>  	}
>  
>  	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
> @@ -4460,7 +4460,7 @@ int cmd_record(int argc, const char **argv)
>  	auxtrace_record__free(rec->itr);
>  out_opts:
>  	evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
> -	evlist__delete(rec->evlist);
> +	evlist__put(rec->evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index 886727ae8529..282926c6abd4 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -2067,7 +2067,7 @@ static int add_default_events(void)
>  			metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
>  							&evlist->metric_events,
>  							&metric_evlist->metric_events);
> -			evlist__delete(metric_evlist);
> +			evlist__put(metric_evlist);
>  		}
>  	}
>  
> @@ -2142,7 +2142,7 @@ static int add_default_events(void)
>  	metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
>  					&evsel_list->metric_events,
>  					&evlist->metric_events);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> @@ -2373,7 +2373,7 @@ static int __cmd_report(int argc, const char **argv)
>  
>  	perf_stat.session  = session;
>  	stat_config.output = stderr;
> -	evlist__delete(evsel_list);
> +	evlist__put(evsel_list);
>  	evsel_list         = session->evlist;
>  
>  	ret = perf_session__process_events(session);
> @@ -3042,7 +3042,7 @@ int cmd_stat(int argc, const char **argv)
>  	if (smi_cost && smi_reset)
>  		sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
>  
> -	evlist__delete(evsel_list);
> +	evlist__put(evsel_list);
>  
>  	evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
>  
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 710604c4f6f6..45d5dae54dcd 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -1641,14 +1641,14 @@ int cmd_top(int argc, const char **argv)
>  	perf_env__init(&host_env);
>  	status = perf_config(perf_top_config, &top);
>  	if (status)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	/*
>  	 * Since the per arch annotation init routine may need the cpuid, read
>  	 * it here, since we are not getting this from the perf.data header.
>  	 */
>  	status = perf_env__set_cmdline(&host_env, argc, argv);
>  	if (status)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	status = perf_env__read_cpuid(&host_env);
>  	if (status) {
> @@ -1669,44 +1669,44 @@ int cmd_top(int argc, const char **argv)
>  		annotate_opts.disassembler_style = strdup(disassembler_style);
>  		if (!annotate_opts.disassembler_style) {
>  			status = -ENOMEM;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  	if (objdump_path) {
>  		annotate_opts.objdump_path = strdup(objdump_path);
>  		if (!annotate_opts.objdump_path) {
>  			status = -ENOMEM;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  	if (addr2line_path) {
>  		symbol_conf.addr2line_path = strdup(addr2line_path);
>  		if (!symbol_conf.addr2line_path) {
>  			status = -ENOMEM;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  
>  	status = symbol__validate_sym_arguments();
>  	if (status)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if (annotate_check_args() < 0)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if (!top.evlist->core.nr_entries) {
>  		struct evlist *def_evlist = evlist__new_default();
>  
>  		if (!def_evlist)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  
>  		evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
> -		evlist__delete(def_evlist);
> +		evlist__put(def_evlist);
>  	}
>  
>  	status = evswitch__init(&top.evswitch, top.evlist, stderr);
>  	if (status)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if (symbol_conf.report_hierarchy) {
>  		/* disable incompatible options */
> @@ -1717,18 +1717,18 @@ int cmd_top(int argc, const char **argv)
>  			pr_err("Error: --hierarchy and --fields options cannot be used together\n");
>  			parse_options_usage(top_usage, options, "fields", 0);
>  			parse_options_usage(NULL, options, "hierarchy", 0);
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  
>  	if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
>  		pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	if (nr_cgroups > 0 && opts->record_cgroup) {
>  		pr_err("--cgroup and --all-cgroups cannot be used together\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	if (branch_call_mode) {
> @@ -1752,7 +1752,7 @@ int cmd_top(int argc, const char **argv)
>  		status = perf_env__read_core_pmu_caps(&host_env);
>  		if (status) {
>  			pr_err("PMU capability data is not available\n");
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  
> @@ -1775,7 +1775,7 @@ int cmd_top(int argc, const char **argv)
>  	if (IS_ERR(top.session)) {
>  		status = PTR_ERR(top.session);
>  		top.session = NULL;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  	top.evlist->session = top.session;
>  
> @@ -1785,7 +1785,7 @@ int cmd_top(int argc, const char **argv)
>  		if (field_order)
>  			parse_options_usage(sort_order ? NULL : top_usage,
>  					    options, "fields", 0);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	status = target__validate(target);
> @@ -1800,11 +1800,11 @@ int cmd_top(int argc, const char **argv)
>  		if (uid == UINT_MAX) {
>  			ui__error("Invalid User: %s", top.uid_str);
>  			status = -EINVAL;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  		status = parse_uid_filter(top.evlist, uid);
>  		if (status)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  
>  	if (target__none(target))
> @@ -1814,7 +1814,7 @@ int cmd_top(int argc, const char **argv)
>  		ui__error("Couldn't create thread/CPU maps: %s\n",
>  			  errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
>  		status = -errno;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	if (top.delay_secs < 1)
> @@ -1822,7 +1822,7 @@ int cmd_top(int argc, const char **argv)
>  
>  	if (record_opts__config(opts)) {
>  		status = -EINVAL;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	top.sym_evsel = evlist__first(top.evlist);
> @@ -1837,14 +1837,14 @@ int cmd_top(int argc, const char **argv)
>  
>  	status = symbol__annotation_init();
>  	if (status < 0)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	annotation_config__init();
>  
>  	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
>  	status = symbol__init(NULL);
>  	if (status < 0)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	sort__setup_elide(stdout);
>  
> @@ -1864,13 +1864,13 @@ int cmd_top(int argc, const char **argv)
>  		if (top.sb_evlist == NULL) {
>  			pr_err("Couldn't create side band evlist.\n.");
>  			status = -EINVAL;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
>  			pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
>  			status = -EINVAL;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  #endif
> @@ -1885,8 +1885,8 @@ int cmd_top(int argc, const char **argv)
>  	if (!opts->no_bpf_event)
>  		evlist__stop_sb_thread(top.sb_evlist);
>  
> -out_delete_evlist:
> -	evlist__delete(top.evlist);
> +out_put_evlist:
> +	evlist__put(top.evlist);
>  	perf_session__delete(top.session);
>  	annotation_options__exit();
>  	perf_env__exit(&host_env);
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index a743bda294bd..c056df42a78f 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
> @@ -4364,7 +4364,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  
>  	if (trace->summary_bpf) {
>  		if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  
>  		if (trace->summary_only)
>  			goto create_maps;
> @@ -4432,19 +4432,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  	err = evlist__create_maps(evlist, &trace->opts.target);
>  	if (err < 0) {
>  		fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	err = trace__symbols_init(trace, argc, argv, evlist);
>  	if (err < 0) {
>  		fprintf(trace->output, "Problems initializing symbol libraries!\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
>  		trace->syscall_stats = alloc_syscall_stats();
>  		if (IS_ERR(trace->syscall_stats))
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  
>  	evlist__config(evlist, &trace->opts, &callchain_param);
> @@ -4453,7 +4453,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  		err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
>  		if (err < 0) {
>  			fprintf(trace->output, "Couldn't run the workload!\n");
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  		workload_pid = evlist->workload.pid;
>  	}
> @@ -4501,7 +4501,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  
>  	err = trace__expand_filters(trace, &evsel);
>  	if (err)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
>  	if (err < 0)
>  		goto out_error_apply_filters;
> @@ -4618,12 +4618,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  		}
>  	}
>  
> -out_delete_evlist:
> +out_put_evlist:
>  	trace_cleanup_bpf_summary();
>  	delete_syscall_stats(trace->syscall_stats);
>  	trace__symbols__exit(trace);
>  	evlist__free_syscall_tp_fields(evlist);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	cgroup__put(trace->cgroup);
>  	trace->evlist = NULL;
>  	trace->live = false;
> @@ -4648,22 +4648,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
>  
>  out_error:
>  	fprintf(trace->output, "%s\n", errbuf);
> -	goto out_delete_evlist;
> +	goto out_put_evlist;
>  
>  out_error_apply_filters:
>  	fprintf(trace->output,
>  		"Failed to set filter \"%s\" on event %s with %d (%s)\n",
>  		evsel->filter, evsel__name(evsel), errno,
>  		str_error_r(errno, errbuf, sizeof(errbuf)));
> -	goto out_delete_evlist;
> +	goto out_put_evlist;
>  }
>  out_error_mem:
>  	fprintf(trace->output, "Not enough memory to run!\n");
> -	goto out_delete_evlist;
> +	goto out_put_evlist;
>  
>  out_errno:
>  	fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
> -	goto out_delete_evlist;
> +	goto out_put_evlist;
>  }
>  
>  static int trace__replay(struct trace *trace)
> @@ -5331,7 +5331,7 @@ static void trace__exit(struct trace *trace)
>  		zfree(&trace->syscalls.table);
>  	}
>  	zfree(&trace->perfconfig_events);
> -	evlist__delete(trace->evlist);
> +	evlist__put(trace->evlist);
>  	trace->evlist = NULL;
>  	ordered_events__free(&trace->oe.data);
>  #ifdef HAVE_LIBBPF_SUPPORT
> diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
> index c5e7999f2817..2b49b002d749 100644
> --- a/tools/perf/tests/backward-ring-buffer.c
> +++ b/tools/perf/tests/backward-ring-buffer.c
> @@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
>  	err = evlist__create_maps(evlist, &opts.target);
>  	if (err < 0) {
>  		pr_debug("Not enough memory to create thread/cpu maps\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	parse_events_error__init(&parse_error);
> @@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
>  	if (err) {
>  		pr_debug("Failed to parse tracepoint event, try use root\n");
>  		ret = TEST_SKIP;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__config(evlist, &opts, NULL);
> @@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
>  	if (err < 0) {
>  		pr_debug("perf_evlist__open: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	ret = TEST_FAIL;
>  	err = do_test(evlist, opts.mmap_pages, &sample_count,
>  		      &comm_count);
>  	if (err != TEST_OK)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
>  		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
>  		       sample_count, comm_count);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__close(evlist);
> @@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
>  	if (err < 0) {
>  		pr_debug("perf_evlist__open: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	err = do_test(evlist, 1, &sample_count, &comm_count);
>  	if (err != TEST_OK)
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	ret = TEST_OK;
> -out_delete_evlist:
> -	evlist__delete(evlist);
> +out_put_evlist:
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
> index 5927d1ea20e2..8da8951154d8 100644
> --- a/tools/perf/tests/code-reading.c
> +++ b/tools/perf/tests/code-reading.c
> @@ -806,7 +806,7 @@ static int do_test_code_reading(bool try_kcore)
>  			}
>  
>  			perf_evlist__set_maps(&evlist->core, NULL, NULL);
> -			evlist__delete(evlist);
> +			evlist__put(evlist);
>  			evlist = NULL;
>  			continue;
>  		}
> @@ -843,7 +843,7 @@ static int do_test_code_reading(bool try_kcore)
>  out_put:
>  	thread__put(thread);
>  out_err:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
>  	machine__delete(machine);
> diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
> index ae3b98bb42cf..94ab54ecd3f9 100644
> --- a/tools/perf/tests/event-times.c
> +++ b/tools/perf/tests/event-times.c
> @@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
>  	err = attach(evlist);
>  	if (err == TEST_SKIP) {
>  		pr_debug("  SKIP  : not enough rights\n");
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		return err;
>  	}
>  
> @@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
>  		 count.ena, count.run);
>  
>  out_err:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return !err ? TEST_OK : TEST_FAIL;
>  }
>  
> diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
> index cb9e6de2e033..8de66dac52b0 100644
> --- a/tools/perf/tests/event_update.c
> +++ b/tools/perf/tests/event_update.c
> @@ -115,7 +115,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
>  	TEST_ASSERT_VAL("failed to synthesize attr update cpus",
>  			!perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
>  
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return 0;
>  }
>  
> diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
> index 1922cac13a24..6a220634c52f 100644
> --- a/tools/perf/tests/evsel-roundtrip-name.c
> +++ b/tools/perf/tests/evsel-roundtrip-name.c
> @@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
>  				if (err) {
>  					pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
>  						name);
> -					evlist__delete(evlist);
> +					evlist__put(evlist);
>  					continue;
>  				}
>  				evlist__for_each_entry(evlist, evsel) {
> @@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
>  						ret = TEST_FAIL;
>  					}
>  				}
> -				evlist__delete(evlist);
> +				evlist__put(evlist);
>  			}
>  		}
>  	}
> @@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
>  		if (err) {
>  			pr_debug("failed to parse event '%s', err %d\n",
>  				 names[i], err);
> -			evlist__delete(evlist);
> +			evlist__put(evlist);
>  			ret = TEST_FAIL;
>  			continue;
>  		}
> @@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
>  				ret = TEST_FAIL;
>  			}
>  		}
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  	}
>  	return ret;
>  }
> diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> index c7b32a220ca1..9060b085e3de 100644
> --- a/tools/perf/tests/expand-cgroup.c
> +++ b/tools/perf/tests/expand-cgroup.c
> @@ -104,7 +104,7 @@ static int expand_default_events(void)
>  	TEST_ASSERT_VAL("failed to get evlist", evlist);
>  
>  	ret = test_expand_events(evlist);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> @@ -131,7 +131,7 @@ static int expand_group_events(void)
>  	ret = test_expand_events(evlist);
>  out:
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> @@ -162,7 +162,7 @@ static int expand_libpfm_events(void)
>  
>  	ret = test_expand_events(evlist);
>  out:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> @@ -186,7 +186,7 @@ static int expand_metric_events(void)
>  	ret = test_expand_events(evlist);
>  
>  out:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
> index 3eb9ef8d7ec6..8f7cce7b5085 100644
> --- a/tools/perf/tests/hists_cumulate.c
> +++ b/tools/perf/tests/hists_cumulate.c
> @@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
>  
>  out:
>  	/* tear down everything */
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	machines__exit(&machines);
>  	put_fake_samples();
>  
> diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
> index 1cebd20cc91c..447fb2b5947c 100644
> --- a/tools/perf/tests/hists_filter.c
> +++ b/tools/perf/tests/hists_filter.c
> @@ -331,7 +331,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
>  
>  out:
>  	/* tear down everything */
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	reset_output_field();
>  	machines__exit(&machines);
>  	put_fake_samples();
> diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
> index 996f5f0b3bd1..9646c3b7b4de 100644
> --- a/tools/perf/tests/hists_link.c
> +++ b/tools/perf/tests/hists_link.c
> @@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
>  
>  out:
>  	/* tear down everything */
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	reset_output_field();
>  	machines__exit(&machines);
>  	put_fake_samples();
> diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
> index ee5ec8bda60e..aa8565fbaf90 100644
> --- a/tools/perf/tests/hists_output.c
> +++ b/tools/perf/tests/hists_output.c
> @@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
>  
>  out:
>  	/* tear down everything */
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	machines__exit(&machines);
>  	put_fake_samples();
>  
> diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
> index 97ea036ebae6..7d1040619575 100644
> --- a/tools/perf/tests/hwmon_pmu.c
> +++ b/tools/perf/tests/hwmon_pmu.c
> @@ -211,7 +211,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
>  
>  out:
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
> index 729cc9cc1cb7..51cfd6522867 100644
> --- a/tools/perf/tests/keep-tracking.c
> +++ b/tools/perf/tests/keep-tracking.c
> @@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
>  out_err:
>  	if (evlist) {
>  		evlist__disable(evlist);
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  	}
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
> diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
> index a622bb8d4cc8..2591b6fbec3f 100644
> --- a/tools/perf/tests/mmap-basic.c
> +++ b/tools/perf/tests/mmap-basic.c
> @@ -93,7 +93,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  				/* Permissions failure, flag the failure as a skip. */
>  				err = TEST_SKIP;
>  			}
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		evsels[i]->core.attr.wakeup_events = 1;
> @@ -105,7 +105,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  			pr_debug("failed to open counter: %s, "
>  				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
>  				 str_error_r(errno, sbuf, sizeof(sbuf)));
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		nr_events[i] = 0;
> @@ -115,7 +115,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  	if (evlist__mmap(evlist, 128) < 0) {
>  		pr_debug("failed to mmap events: %d (%s)\n", errno,
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	for (i = 0; i < nsyscalls; ++i)
> @@ -133,7 +133,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  		if (event->header.type != PERF_RECORD_SAMPLE) {
>  			pr_debug("unexpected %s event\n",
>  				 perf_event__name(event->header.type));
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		perf_sample__init(&sample, /*all=*/false);
> @@ -141,7 +141,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  		if (err) {
>  			pr_err("Can't parse sample, err = %d\n", err);
>  			perf_sample__exit(&sample);
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		err = -1;
> @@ -150,7 +150,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  		if (evsel == NULL) {
>  			pr_debug("event with id %" PRIu64
>  				 " doesn't map to an evsel\n", sample.id);
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  		nr_events[evsel->core.idx]++;
>  		perf_mmap__consume(&md->core);
> @@ -165,12 +165,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  				 expected_nr_events[evsel->core.idx],
>  				 evsel__name(evsel), nr_events[evsel->core.idx]);
>  			err = -1;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  
> -out_delete_evlist:
> -	evlist__delete(evlist);
> +out_put_evlist:
> +	evlist__put(evlist);
>  out_free_cpus:
>  	perf_cpu_map__put(cpus);
>  out_free_threads:
> diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
> index 2a139d2781a8..3ff595c7a86a 100644
> --- a/tools/perf/tests/openat-syscall-tp-fields.c
> +++ b/tools/perf/tests/openat-syscall-tp-fields.c
> @@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  	if (IS_ERR(evsel)) {
>  		pr_debug("%s: evsel__newtp\n", __func__);
>  		ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__add(evlist, evsel);
> @@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  	err = evlist__create_maps(evlist, &opts.target);
>  	if (err < 0) {
>  		pr_debug("%s: evlist__create_maps\n", __func__);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evsel__config(evsel, &opts, NULL);
> @@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  	if (err < 0) {
>  		pr_debug("perf_evlist__open: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	err = evlist__mmap(evlist, UINT_MAX);
>  	if (err < 0) {
>  		pr_debug("evlist__mmap: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__enable(evlist);
> @@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  				if (err) {
>  					pr_debug("Can't parse sample, err = %d\n", err);
>  					perf_sample__exit(&sample);
> -					goto out_delete_evlist;
> +					goto out_put_evlist;
>  				}
>  
>  				tp_flags = evsel__intval(evsel, &sample, "flags");
> @@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  				if (flags != tp_flags) {
>  					pr_debug("%s: Expected flags=%#x, got %#x\n",
>  						 __func__, flags, tp_flags);
> -					goto out_delete_evlist;
> +					goto out_put_evlist;
>  				}
>  
>  				goto out_ok;
> @@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
>  
>  		if (++nr_polls > 5) {
>  			pr_debug("%s: no events!\n", __func__);
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  	}
>  out_ok:
>  	ret = TEST_OK;
> -out_delete_evlist:
> -	evlist__delete(evlist);
> +out_put_evlist:
> +	evlist__put(evlist);
>  out:
>  	return ret;
>  }
> diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
> index e4cdb517c10e..0778462016f7 100644
> --- a/tools/perf/tests/parse-events.c
> +++ b/tools/perf/tests/parse-events.c
> @@ -2550,7 +2550,7 @@ static int test_event(const struct evlist_test *e)
>  		ret = e->check(evlist);
>  	}
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  
>  	return ret;
>  }
> @@ -2576,7 +2576,7 @@ static int test_event_fake_pmu(const char *str)
>  	}
>  
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  
>  	return ret;
>  }
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 66a5275917e2..b343628c7a7e 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -83,7 +83,7 @@ static int __compute_metric(const char *name, struct value *vals,
>  
>  	cpus = perf_cpu_map__new("0");
>  	if (!cpus) {
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		return -ENOMEM;
>  	}
>  
> @@ -112,7 +112,7 @@ static int __compute_metric(const char *name, struct value *vals,
>  	/* ... cleanup. */
>  	evlist__free_stats(evlist);
>  	perf_cpu_map__put(cpus);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
> index 50e68b7d43aa..d5a8d065809e 100644
> --- a/tools/perf/tests/parse-no-sample-id-all.c
> +++ b/tools/perf/tests/parse-no-sample-id-all.c
> @@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
>  	for (i = 0; i < count && !err; i++)
>  		err = process_event(&evlist, events[i]);
>  
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  
>  	return err;
>  }
> diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> index efbd9cd60c63..babec674b83c 100644
> --- a/tools/perf/tests/perf-record.c
> +++ b/tools/perf/tests/perf-record.c
> @@ -102,7 +102,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  	err = evlist__create_maps(evlist, &opts.target);
>  	if (err < 0) {
>  		pr_debug("Not enough memory to create thread/cpu maps\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	/*
> @@ -114,7 +114,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  	err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
>  	if (err < 0) {
>  		pr_debug("Couldn't run the workload!\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	/*
> @@ -131,7 +131,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  		pr_debug("sched__get_first_possible_cpu: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
>  		evlist__cancel_workload(evlist);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	cpu = err;
> @@ -143,7 +143,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  		pr_debug("sched_setaffinity: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
>  		evlist__cancel_workload(evlist);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	/*
> @@ -155,7 +155,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  		pr_debug("perf_evlist__open: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
>  		evlist__cancel_workload(evlist);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	/*
> @@ -168,7 +168,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  		pr_debug("evlist__mmap: %s\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
>  		evlist__cancel_workload(evlist);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	/*
> @@ -206,7 +206,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  					if (verbose > 0)
>  						perf_event__fprintf(event, NULL, stderr);
>  					pr_debug("Couldn't parse sample\n");
> -					goto out_delete_evlist;
> +					goto out_put_evlist;
>  				}
>  
>  				if (verbose > 0) {
> @@ -346,9 +346,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
>  		pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
>  		++errs;
>  	}
> -out_delete_evlist:
> +out_put_evlist:
>  	CPU_FREE(cpu_mask);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  out:
>  	perf_sample__exit(&sample);
>  	if (err == -EACCES)
> diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
> index cca41bd37ae3..d3538fa20af3 100644
> --- a/tools/perf/tests/perf-time-to-tsc.c
> +++ b/tools/perf/tests/perf-time-to-tsc.c
> @@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
>  	err = TEST_OK;
>  
>  out_err:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
>  	return err;
> diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
> index 2e38dfa34b6c..099a50dec37e 100644
> --- a/tools/perf/tests/pfm.c
> +++ b/tools/perf/tests/pfm.c
> @@ -79,7 +79,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
>  				evlist__nr_groups(evlist),
>  				0);
>  
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  	}
>  	return 0;
>  }
> @@ -164,7 +164,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
>  				evlist__nr_groups(evlist),
>  				table[i].nr_groups);
>  
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  	}
>  	return 0;
>  }
> diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> index f40a828c9861..ab547f301c61 100644
> --- a/tools/perf/tests/pmu-events.c
> +++ b/tools/perf/tests/pmu-events.c
> @@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
>  			     /*warn_if_reordered=*/true, /*fake_tp=*/false);
>  	free(dup);
>  
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> @@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
>  
>  	cpus = perf_cpu_map__new("0");
>  	if (!cpus) {
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		return -ENOMEM;
>  	}
>  
> @@ -901,7 +901,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
>  	/* ... cleanup. */
>  	evlist__free_stats(evlist);
>  	perf_cpu_map__put(cpus);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
> index cbded2c6faa4..bd3f4a2806ed 100644
> --- a/tools/perf/tests/pmu.c
> +++ b/tools/perf/tests/pmu.c
> @@ -249,7 +249,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
>  	ret = TEST_OK;
>  err_out:
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	test_pmu_put(dir, pmu);
>  	return ret;
>  }
> diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
> index 4a2ad7176fa0..f7f1f16638b4 100644
> --- a/tools/perf/tests/sw-clock.c
> +++ b/tools/perf/tests/sw-clock.c
> @@ -58,7 +58,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
>  	evsel = evsel__new(&attr);
>  	if (evsel == NULL) {
>  		pr_debug("evsel__new\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  	evlist__add(evlist, evsel);
>  
> @@ -67,7 +67,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
>  	if (!cpus || !threads) {
>  		err = -ENOMEM;
>  		pr_debug("Not enough memory to create thread/cpu maps\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	perf_evlist__set_maps(&evlist->core, cpus, threads);
> @@ -79,14 +79,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
>  		pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
>  			 str_error_r(errno, sbuf, sizeof(sbuf)),
>  			 knob, (u64)attr.sample_freq);
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	err = evlist__mmap(evlist, 128);
>  	if (err < 0) {
>  		pr_debug("failed to mmap event: %d (%s)\n", errno,
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__enable(evlist);
> @@ -112,7 +112,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
>  		if (err < 0) {
>  			pr_debug("Error during parse sample\n");
>  			perf_sample__exit(&sample);
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		total_periods += sample.period;
> @@ -130,10 +130,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
>  		err = -1;
>  	}
>  
> -out_delete_evlist:
> +out_put_evlist:
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
> index 15791fcb76b2..c3d5825df0a8 100644
> --- a/tools/perf/tests/switch-tracking.c
> +++ b/tools/perf/tests/switch-tracking.c
> @@ -577,7 +577,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
>  out:
>  	if (evlist) {
>  		evlist__disable(evlist);
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  	}
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
> diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
> index 4053ff2813bb..a46650b10689 100644
> --- a/tools/perf/tests/task-exit.c
> +++ b/tools/perf/tests/task-exit.c
> @@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
>  	if (!cpus || !threads) {
>  		err = -ENOMEM;
>  		pr_debug("Not enough memory to create thread/cpu maps\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	perf_evlist__set_maps(&evlist->core, cpus, threads);
> @@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
>  	err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
>  	if (err < 0) {
>  		pr_debug("Couldn't run the workload!\n");
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evsel = evlist__first(evlist);
> @@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
>  	if (err < 0) {
>  		pr_debug("Couldn't open the evlist: %s\n",
>  			 str_error_r(-err, sbuf, sizeof(sbuf)));
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	if (evlist__mmap(evlist, 128) < 0) {
>  		pr_debug("failed to mmap events: %d (%s)\n", errno,
>  			 str_error_r(errno, sbuf, sizeof(sbuf)));
>  		err = -1;
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  	}
>  
>  	evlist__start_workload(evlist);
> @@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
>  		if (retry_count++ > 1000) {
>  			pr_debug("Failed after retrying 1000 times\n");
>  			err = -1;
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  		}
>  
>  		goto retry;
> @@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
>  		err = -1;
>  	}
>  
> -out_delete_evlist:
> +out_put_evlist:
>  	perf_cpu_map__put(cpus);
>  	perf_thread_map__put(threads);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
> index 1e900ef92e37..e78ff9dcea97 100644
> --- a/tools/perf/tests/tool_pmu.c
> +++ b/tools/perf/tests/tool_pmu.c
> @@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
>  
>  out:
>  	parse_events_error__exit(&err);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
> index af4618c3124a..b88447899021 100644
> --- a/tools/perf/tests/topology.c
> +++ b/tools/perf/tests/topology.c
> @@ -55,7 +55,7 @@ static int session_write_header(char *path)
>  			!perf_session__write_header(session, session->evlist,
>  						    perf_data__fd(&data), true));
>  
> -	evlist__delete(session->evlist);
> +	evlist__put(session->evlist);
>  	perf_session__delete(session);
>  
>  	return 0;
> diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
> index 25e2769b5e74..ed230cd44ba7 100644
> --- a/tools/perf/util/cgroup.c
> +++ b/tools/perf/util/cgroup.c
> @@ -503,8 +503,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
>  	cgrp_event_expanded = true;
>  
>  out_err:
> -	evlist__delete(orig_list);
> -	evlist__delete(tmp_list);
> +	evlist__put(orig_list);
> +	evlist__put(tmp_list);
>  	metricgroup__rblist_exit(&orig_metric_events);
>  	release_cgroup_list();
>  
> diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
> index 3d2e437e1354..1166cdb00aca 100644
> --- a/tools/perf/util/data-convert-bt.c
> +++ b/tools/perf/util/data-convert-bt.c
> @@ -1331,7 +1331,7 @@ static void cleanup_events(struct perf_session *session)
>  		zfree(&evsel->priv);
>  	}
>  
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	session->evlist = NULL;
>  }
>  
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index d99a3f12606f..ea1f398c14e3 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -73,7 +73,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
>  #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
>  #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
>  
> -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> +static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
>  		  struct perf_thread_map *threads)
>  {
>  	perf_evlist__init(&evlist->core);
> @@ -85,6 +85,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
>  	evlist->ctl_fd.pos = -1;
>  	evlist->nr_br_cntr = -1;
>  	metricgroup__rblist_init(&evlist->metric_events);
> +	refcount_set(&evlist->refcnt, 1);
>  }
>  
>  struct evlist *evlist__new(void)
> @@ -116,7 +117,7 @@ struct evlist *evlist__new_default(void)
>  			 can_profile_kernel ? "P" : "Pu");
>  		err = parse_event(evlist, buf);
>  		if (err) {
> -			evlist__delete(evlist);
> +			evlist__put(evlist);
>  			return NULL;
>  		}
>  	}
> @@ -136,13 +137,19 @@ struct evlist *evlist__new_dummy(void)
>  	struct evlist *evlist = evlist__new();
>  
>  	if (evlist && evlist__add_dummy(evlist)) {
> -		evlist__delete(evlist);
> +		evlist__put(evlist);
>  		evlist = NULL;
>  	}
>  
>  	return evlist;
>  }
>  
> +struct evlist *evlist__get(struct evlist *evlist)
> +{
> +	refcount_inc(&evlist->refcnt);
> +	return evlist;
> +}
> +
>  /**
>   * evlist__set_id_pos - set the positions of event ids.
>   * @evlist: selected event list
> @@ -181,7 +188,7 @@ static void evlist__purge(struct evlist *evlist)
>  	evlist->core.nr_entries = 0;
>  }
>  
> -void evlist__exit(struct evlist *evlist)
> +static void evlist__exit(struct evlist *evlist)
>  {
>  	metricgroup__rblist_exit(&evlist->metric_events);
>  	event_enable_timer__exit(&evlist->eet);
> @@ -190,11 +197,14 @@ void evlist__exit(struct evlist *evlist)
>  	perf_evlist__exit(&evlist->core);
>  }
>  
> -void evlist__delete(struct evlist *evlist)
> +void evlist__put(struct evlist *evlist)
>  {
>  	if (evlist == NULL)
>  		return;
>  
> +	if (!refcount_dec_and_test(&evlist->refcnt))
> +		return;
> +
>  	evlist__free_stats(evlist);
>  	evlist__munmap(evlist);
>  	evlist__close(evlist);
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index 61acbb10d9a5..66fb5da08160 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -59,6 +59,7 @@ struct event_enable_timer;
>  
>  struct evlist {
>  	struct perf_evlist core;
> +	refcount_t	 refcnt;
>  	bool		 enabled;
>  	int		 id_pos;
>  	int		 is_pos;
> @@ -104,10 +105,8 @@ struct evsel_str_handler {
>  struct evlist *evlist__new(void);
>  struct evlist *evlist__new_default(void);
>  struct evlist *evlist__new_dummy(void);
> -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> -		  struct perf_thread_map *threads);
> -void evlist__exit(struct evlist *evlist);
> -void evlist__delete(struct evlist *evlist);
> +struct evlist *evlist__get(struct evlist *evlist);
> +void evlist__put(struct evlist *evlist);
>  
>  void evlist__add(struct evlist *evlist, struct evsel *entry);
>  void evlist__remove(struct evlist *evlist, struct evsel *evsel);
> diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> index 7fda0ff89c16..4304b53b5a37 100644
> --- a/tools/perf/util/expr.c
> +++ b/tools/perf/util/expr.c
> @@ -451,7 +451,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
>  		ret = parse_event(tmp, id) ? 0 : 1;
>  	}
>  out:
> -	evlist__delete(tmp);
> +	evlist__put(tmp);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 4f2a6e10ed5c..e959ddb12dc8 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -4307,12 +4307,12 @@ int perf_session__read_header(struct perf_session *session)
>  		evsel = evsel__new(&f_attr.attr);
>  
>  		if (evsel == NULL)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  
>  		evsel->needs_swap = header->needs_swap;
>  		/*
>  		 * Do it before so that if perf_evsel__alloc_id fails, this
> -		 * entry gets purged too at evlist__delete().
> +		 * entry gets purged too at evlist__put().
>  		 */
>  		evlist__add(session->evlist, evsel);
>  
> @@ -4323,7 +4323,7 @@ int perf_session__read_header(struct perf_session *session)
>  		 * hattr->ids threads.
>  		 */
>  		if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  
>  		lseek(fd, f_attr.ids.offset, SEEK_SET);
>  
> @@ -4342,7 +4342,7 @@ int perf_session__read_header(struct perf_session *session)
>  				      perf_file_section__process);
>  
>  	if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  #else
>  	perf_header__process_sections(header, fd, NULL, perf_file_section__process);
>  #endif
> @@ -4351,8 +4351,8 @@ int perf_session__read_header(struct perf_session *session)
>  out_errno:
>  	return -errno;
>  
> -out_delete_evlist:
> -	evlist__delete(session->evlist);
> +out_put_evlist:
> +	evlist__put(session->evlist);
>  	session->evlist = NULL;
>  	return -ENOMEM;
>  }
> diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> index 595b83142d2c..64c64dff7424 100644
> --- a/tools/perf/util/metricgroup.c
> +++ b/tools/perf/util/metricgroup.c
> @@ -212,7 +212,7 @@ static void metric__free(struct metric *m)
>  	zfree(&m->metric_refs);
>  	expr__ctx_free(m->pctx);
>  	zfree(&m->modifier);
> -	evlist__delete(m->evlist);
> +	evlist__put(m->evlist);
>  	free(m);
>  }
>  
> @@ -1318,7 +1318,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
>  	parsed_evlist = NULL;
>  err_out:
>  	parse_events_error__exit(&parse_error);
> -	evlist__delete(parsed_evlist);
> +	evlist__put(parsed_evlist);
>  	strbuf_release(&events);
>  	return ret;
>  }
> @@ -1470,7 +1470,7 @@ static int parse_groups(struct evlist *perf_evlist,
>  
>  	if (combined_evlist) {
>  		evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
> -		evlist__delete(combined_evlist);
> +		evlist__put(combined_evlist);
>  	}
>  
>  	list_for_each_entry(m, &metric_list, nd) {
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 0c0dc20b1c13..607ab7b82486 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -2223,7 +2223,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
>  
>  	/*
>  	 * There are 2 users - builtin-record and builtin-test objects.
> -	 * Both call evlist__delete in case of error, so we dont
> +	 * Both call evlist__put in case of error, so we dont
>  	 * need to bother.
>  	 */
>  	return ret;
> @@ -2424,7 +2424,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
>  	}
>  	ret = parse_events_option(opt, str, unset);
>  	if (ret) {
> -		evlist__delete(*args->evlistp);
> +		evlist__put(*args->evlistp);
>  		*args->evlistp = NULL;
>  	}
>  
> diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
> index 3345145a9307..8cd254d36220 100644
> --- a/tools/perf/util/perf_api_probe.c
> +++ b/tools/perf/util/perf_api_probe.c
> @@ -56,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
>  	err = 0;
>  
>  out_delete:
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  	return err;
>  }
>  
> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> index dfc6e9299af9..4149a51e9878 100644
> --- a/tools/perf/util/python.c
> +++ b/tools/perf/util/python.c
> @@ -1273,7 +1273,7 @@ static int pyrf_evsel__setup_types(void)
>  struct pyrf_evlist {
>  	PyObject_HEAD
>  
> -	struct evlist evlist;
> +	struct evlist *evlist;
>  };
>  
>  static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> @@ -1286,15 +1286,21 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
>  	if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
>  		return -1;
>  
> +	pevlist->evlist = evlist__new();
> +	if (!pevlist->evlist) {
> +		PyErr_NoMemory();
> +		return -1;
> +	}
>  	threads = ((struct pyrf_thread_map *)pthreads)->threads;
>  	cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
> -	evlist__init(&pevlist->evlist, cpus, threads);
> +	perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
> +
>  	return 0;
>  }
>  
>  static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
>  {
> -	evlist__exit(&pevlist->evlist);
> +	evlist__put(pevlist->evlist);
>  	Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
>  }
>  
> @@ -1303,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
>  	struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
>  
>  	if (pcpu_map)
> -		pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
> +		pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
>  
>  	return (PyObject *)pcpu_map;
>  }
> @@ -1316,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
>  	if (!list)
>  		return NULL;
>  
> -	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> +	for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
>  	     node = rb_next(node)) {
>  		struct metric_event *me = container_of(node, struct metric_event, nd);
>  		struct list_head *pos;
> @@ -1400,7 +1406,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
>  	if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
>  		return NULL;
>  
> -	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
> +	for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
>  	     mexp == NULL && node;
>  	     node = rb_next(node)) {
>  		struct metric_event *me = container_of(node, struct metric_event, nd);
> @@ -1456,7 +1462,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
>  static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
>  				   PyObject *args, PyObject *kwargs)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  	static char *kwlist[] = { "pages", "overwrite", NULL };
>  	int pages = 128, overwrite = false;
>  
> @@ -1476,7 +1482,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
>  static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
>  				   PyObject *args, PyObject *kwargs)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  	static char *kwlist[] = { "timeout", NULL };
>  	int timeout = -1, n;
>  
> @@ -1496,7 +1502,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
>  					 PyObject *args __maybe_unused,
>  					 PyObject *kwargs __maybe_unused)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>          PyObject *list = PyList_New(0);
>  	int i;
>  
> @@ -1525,7 +1531,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
>  				  PyObject *args,
>  				  PyObject *kwargs __maybe_unused)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  	PyObject *pevsel;
>  	struct evsel *evsel;
>  
> @@ -1557,7 +1563,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
>  static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
>  					  PyObject *args, PyObject *kwargs)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  	union perf_event *event;
>  	int sample_id_all = 1, cpu;
>  	static char *kwlist[] = { "cpu", "sample_id_all", NULL };
> @@ -1614,7 +1620,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
>  static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
>  				   PyObject *args, PyObject *kwargs)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  
>  	if (evlist__open(evlist) < 0) {
>  		PyErr_SetFromErrno(PyExc_OSError);
> @@ -1627,7 +1633,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
>  
>  static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
>  {
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  
>  	evlist__close(evlist);
>  
> @@ -1653,7 +1659,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
>  		.no_buffering        = true,
>  		.no_inherit          = true,
>  	};
> -	struct evlist *evlist = &pevlist->evlist;
> +	struct evlist *evlist = pevlist->evlist;
>  
>  	evlist__config(evlist, &opts, &callchain_param);
>  	Py_INCREF(Py_None);
> @@ -1662,14 +1668,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
>  
>  static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
>  {
> -	evlist__disable(&pevlist->evlist);
> +	evlist__disable(pevlist->evlist);
>  	Py_INCREF(Py_None);
>  	return Py_None;
>  }
>  
>  static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
>  {
> -	evlist__enable(&pevlist->evlist);
> +	evlist__enable(pevlist->evlist);
>  	Py_INCREF(Py_None);
>  	return Py_None;
>  }
> @@ -1760,7 +1766,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
>  {
>  	struct pyrf_evlist *pevlist = (void *)obj;
>  
> -	return pevlist->evlist.core.nr_entries;
> +	return pevlist->evlist->core.nr_entries;
> +}
> +
> +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> +{
> +	struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> +
> +	if (!pevsel)
> +		return NULL;
> +
> +	memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> +	evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> +
> +	evsel__clone(&pevsel->evsel, evsel);
> +	if (evsel__is_group_leader(evsel))
> +		evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> +	return (PyObject *)pevsel;
>  }
>  
>  static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> @@ -1768,17 +1790,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
>  	struct pyrf_evlist *pevlist = (void *)obj;
>  	struct evsel *pos;
>  
> -	if (i >= pevlist->evlist.core.nr_entries) {
> +	if (i >= pevlist->evlist->core.nr_entries) {
>  		PyErr_SetString(PyExc_IndexError, "Index out of range");
>  		return NULL;
>  	}
>  
> -	evlist__for_each_entry(&pevlist->evlist, pos) {
> +	evlist__for_each_entry(pevlist->evlist, pos) {
>  		if (i-- == 0)
>  			break;
>  	}
> -
> -	return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
> +	return pyrf_evsel__from_evsel(pos);
>  }
>  
>  static PyObject *pyrf_evlist__str(PyObject *self)
> @@ -1790,7 +1811,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
>  	PyObject *result;
>  
>  	strbuf_addstr(&sb, "evlist([");
> -	evlist__for_each_entry(&pevlist->evlist, pos) {
> +	evlist__for_each_entry(pevlist->evlist, pos) {
>  		if (!first)
>  			strbuf_addch(&sb, ',');
>  		if (!pos->pmu)
> @@ -1931,110 +1952,30 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
>  	return PyLong_FromLong(tp_pmu__id(sys, name));
>  }
>  
> -static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> -{
> -	struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> -
> -	if (!pevsel)
> -		return NULL;
> -
> -	memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> -	evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> -
> -	evsel__clone(&pevsel->evsel, evsel);
> -	if (evsel__is_group_leader(evsel))
> -		evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> -	return (PyObject *)pevsel;
> -}
> -
> -static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
> -{
> -	struct evsel *pos;
> -	int idx = 0;
> -
> -	evlist__for_each_entry(evlist, pos) {
> -		if (evsel == pos)
> -			return idx;
> -		idx++;
> -	}
> -	return -1;
> -}
> -
> -static struct evsel *evlist__at(struct evlist *evlist, int idx)
> -{
> -	struct evsel *pos;
> -	int idx2 = 0;
> -
> -	evlist__for_each_entry(evlist, pos) {
> -		if (idx == idx2)
> -			return pos;
> -		idx2++;
> -	}
> -	return NULL;
> -}
> -
>  static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
>  {
>  	struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
> -	struct evsel *pos;
> -	struct rb_node *node;
>  
>  	if (!pevlist)
>  		return NULL;
>  
> -	memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
> -	evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
> -	evlist__for_each_entry(evlist, pos) {
> -		struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
> -
> -		evlist__add(&pevlist->evlist, &pevsel->evsel);
> -	}
> -	evlist__for_each_entry(&pevlist->evlist, pos) {
> -		struct evsel *leader = evsel__leader(pos);
> -
> -		if (pos != leader) {
> -			int idx = evlist__pos(evlist, leader);
> -
> -			if (idx >= 0)
> -				evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
> -			else if (leader == NULL)
> -				evsel__set_leader(pos, pos);
> -		}
> -	}
> -	metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
> -					&pevlist->evlist.metric_events,
> -					&evlist->metric_events);
> -	for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> -	     node = rb_next(node)) {
> -		struct metric_event *me = container_of(node, struct metric_event, nd);
> -		struct list_head *mpos;
> -		int idx = evlist__pos(evlist, me->evsel);
> -
> -		if (idx >= 0)
> -			me->evsel = evlist__at(&pevlist->evlist, idx);
> -		list_for_each(mpos, &me->head) {
> -			struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
> -
> -			for (int j = 0; e->metric_events[j]; j++) {
> -				idx = evlist__pos(evlist, e->metric_events[j]);
> -				if (idx >= 0)
> -					e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
> -			}
> -		}
> -	}
> +	pevlist->evlist = evlist__get(evlist);
>  	return (PyObject *)pevlist;
>  }
>  
>  static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
>  {
>  	const char *input;
> -	struct evlist evlist = {};
> +	struct evlist *evlist = evlist__new();
>  	struct parse_events_error err;
>  	PyObject *result;
>  	PyObject *pcpus = NULL, *pthreads = NULL;
>  	struct perf_cpu_map *cpus;
>  	struct perf_thread_map *threads;
>  
> +	if (!evlist)
> +		return PyErr_NoMemory();
> +
>  	if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
>  		return NULL;
>  
> @@ -2042,35 +1983,38 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
>  	cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
>  
>  	parse_events_error__init(&err);
> -	evlist__init(&evlist, cpus, threads);
> -	if (parse_events(&evlist, input, &err)) {
> +	perf_evlist__set_maps(&evlist->core, cpus, threads);
> +	if (parse_events(evlist, input, &err)) {
>  		parse_events_error__print(&err, input);
>  		PyErr_SetFromErrno(PyExc_OSError);
>  		return NULL;
>  	}
> -	result = pyrf_evlist__from_evlist(&evlist);
> -	evlist__exit(&evlist);
> +	result = pyrf_evlist__from_evlist(evlist);
> +	evlist__put(evlist);
>  	return result;
>  }
>  
>  static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
>  {
>  	const char *input, *pmu = NULL;
> -	struct evlist evlist = {};
> +	struct evlist *evlist = evlist__new();
>  	PyObject *result;
>  	PyObject *pcpus = NULL, *pthreads = NULL;
>  	struct perf_cpu_map *cpus;
>  	struct perf_thread_map *threads;
>  	int ret;
>  
> +	if (!evlist)
> +		return PyErr_NoMemory();
> +
>  	if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
>  		return NULL;
>  
>  	threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
>  	cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
>  
> -	evlist__init(&evlist, cpus, threads);
> -	ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
> +	perf_evlist__set_maps(&evlist->core, cpus, threads);
> +	ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
>  					/*metric_no_group=*/ false,
>  					/*metric_no_merge=*/ false,
>  					/*metric_no_threshold=*/ true,
> @@ -2082,8 +2026,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
>  		PyErr_SetFromErrno(PyExc_OSError);
>  		return NULL;
>  	}
> -	result = pyrf_evlist__from_evlist(&evlist);
> -	evlist__exit(&evlist);
> +	result = pyrf_evlist__from_evlist(evlist);
> +	evlist__put(evlist);
>  	return result;
>  }
>  
> diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
> index e867de8ddaaa..8a5fc7d5e43c 100644
> --- a/tools/perf/util/record.c
> +++ b/tools/perf/util/record.c
> @@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
>  	ret = true;
>  
>  out_delete:
> -	evlist__delete(temp_evlist);
> +	evlist__put(temp_evlist);
>  	return ret;
>  }
>  
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index 081e68c72c30..f241d91221d7 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -256,7 +256,7 @@ void perf_session__delete(struct perf_session *session)
>  	machines__exit(&session->machines);
>  	if (session->data) {
>  		if (perf_data__is_read(session->data))
> -			evlist__delete(session->evlist);
> +			evlist__put(session->evlist);
>  		perf_data__close(session->data);
>  	}
>  #ifdef HAVE_LIBTRACEEVENT
> diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
> index 388846f17bc1..b84a5463e039 100644
> --- a/tools/perf/util/sideband_evlist.c
> +++ b/tools/perf/util/sideband_evlist.c
> @@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
>  		return 0;
>  
>  	if (evlist__create_maps(evlist, target))
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	if (evlist->core.nr_entries > 1) {
>  		bool can_sample_identifier = perf_can_sample_identifier();
> @@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
>  	evlist__for_each_entry(evlist, counter) {
>  		if (evsel__open(counter, evlist->core.user_requested_cpus,
>  				evlist->core.threads) < 0)
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  
>  	if (evlist__mmap(evlist, UINT_MAX))
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	evlist__for_each_entry(evlist, counter) {
>  		if (evsel__enable(counter))
> -			goto out_delete_evlist;
> +			goto out_put_evlist;
>  	}
>  
>  	evlist->thread.done = 0;
>  	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
> -		goto out_delete_evlist;
> +		goto out_put_evlist;
>  
>  	return 0;
>  
> -out_delete_evlist:
> -	evlist__delete(evlist);
> +out_put_evlist:
> +	evlist__put(evlist);
>  	evlist = NULL;
>  	return -1;
>  }
> @@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
>  		return;
>  	evlist->thread.done = 1;
>  	pthread_join(evlist->thread.th, NULL);
> -	evlist__delete(evlist);
> +	evlist__put(evlist);
>  }
> -- 
> 2.51.1.851.g4ebd6896fd-goog

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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29 16:22   ` Arnaldo Carvalho de Melo
@ 2025-10-29 16:25     ` Arnaldo Carvalho de Melo
  2025-10-29 16:56     ` Ian Rogers
  1 sibling, 0 replies; 22+ messages in thread
From: Arnaldo Carvalho de Melo @ 2025-10-29 16:25 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Wed, Oct 29, 2025 at 01:22:21PM -0300, Arnaldo Carvalho de Melo wrote:
> On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> > This a no-op for most of the perf tool. The reference count is set to
> > 1 at allocation, the put will see the 1, decrement it and perform the
> > delete. The purpose for adding the reference count is for the python
> > code. Prior to this change the python code would clone evlists, but
> > this has issues if events are opened, etc. This change adds a
> > reference count for the evlists and a later change will add it to
> > evsels. The combination is needed for the python code to operate
> > correctly (not hit asserts in the evsel clone), but the changes are
> > broken apart for the sake of smaller patches.
 
> Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
> are not using the RC_CHK_ACCESS stuff from the get go, why not?
 
> All the prep patches looks ok, assuming they build in succession.

Also I tried to run the test case before the patches on a 9950x3d, AMD,
with ibs and couldn't, some perf.data format error, then on Intel I had
to hit control+c and got a deprecation warning, both, of course
completely unrelated to your work, so just FYI:

root@five:~# perf mem record -a sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 2.247 MB perf.data (12814 samples) ]
root@five:~# time perf script mem-phys-addr
/home/acme/libexec/perf-core/scripts/python/mem-phys-addr.py:49: DeprecationWarning: 'maxsplit' is passed as positional argument
  m = re.split('-|:', line, 2)
^CWarning:
929 out of order events recorded.
Event: cpu_core/mem_inst_retired.all_loads/P
Memory type                                    count  percentage
----------------------------------------  ----------  ----------
100000000-8bfbfffff : System RAM              149050        87.4
  2ac600000-2ad75cfff : Kernel rodata           1567         0.9
  2ad800000-2adc6a47f : Kernel data              517         0.3
  2ae7e8000-2aedfffff : Kernel bss               282         0.2
  2ab000000-2ac54d27e : Kernel code               21         0.0
0-fff : Reserved                               18990        11.1
100000-30093fff : System RAM                    2566         1.5

real	11m46.282s
user	0m1.317s
sys	0m0.344s
root@five:~# grep -m1 'model name' /proc/cpuinfo
model name	: Intel(R) Core(TM) i7-14700K
root@five:~# cat /etc/redhat-release
Fedora release 42 (Adams)
root@five:~# uname -a
Linux five 6.16.9-200.fc42.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Sep 25 18:05:50 UTC 2025 x86_64 GNU/Linux
root@five:~#

- Arnaldo

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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29 16:22   ` Arnaldo Carvalho de Melo
  2025-10-29 16:25     ` Arnaldo Carvalho de Melo
@ 2025-10-29 16:56     ` Ian Rogers
  2025-10-29 18:33       ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 22+ messages in thread
From: Ian Rogers @ 2025-10-29 16:56 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Wed, Oct 29, 2025 at 9:22 AM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> > This a no-op for most of the perf tool. The reference count is set to
> > 1 at allocation, the put will see the 1, decrement it and perform the
> > delete. The purpose for adding the reference count is for the python
> > code. Prior to this change the python code would clone evlists, but
> > this has issues if events are opened, etc. This change adds a
> > reference count for the evlists and a later change will add it to
> > evsels. The combination is needed for the python code to operate
> > correctly (not hit asserts in the evsel clone), but the changes are
> > broken apart for the sake of smaller patches.
>
> Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
> are not using the RC_CHK_ACCESS stuff from the get go, why not?

So if I did RC_CHK_ACCESS then every evsel access would need updating,
accessor functions, and a lot of lines of code. As the reference count
checking doesn't work with invasive lists, you need to interpose prev
and next, I think we'd need to specially handle the case probably with
an extra variable in evsel for reference count checking like:
```
RC_STRUCT(evsel) {
...
   struct evsel *evlist_ptr;
...
}
```
and things like evlist__for_each_entry need changes like:
```
#define evlist__for_each_entry(evlist, evsel) \
       __evlist__for_each_entry(&(evlist)->core.entries, orig_evsel) {
           evsel = orig_evsel->evlist_ptr
```
but it may be simpler to change evlist to use an array of evsel* as
was done in places like `struct maps`.

Anyway, those changes I think would have taken away from what the
series was trying to do and so weren't done here.

Thanks,
Ian

> All the prep patches looks ok, assuming they build in succession.
>
> - Arnaldo
>
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >  tools/perf/arch/x86/tests/hybrid.c          |   2 +-
> >  tools/perf/arch/x86/tests/topdown.c         |   2 +-
> >  tools/perf/arch/x86/util/iostat.c           |   2 +-
> >  tools/perf/bench/evlist-open-close.c        |  18 +-
> >  tools/perf/builtin-ftrace.c                 |   8 +-
> >  tools/perf/builtin-kvm.c                    |   4 +-
> >  tools/perf/builtin-lock.c                   |   2 +-
> >  tools/perf/builtin-record.c                 |   4 +-
> >  tools/perf/builtin-stat.c                   |   8 +-
> >  tools/perf/builtin-top.c                    |  52 +++---
> >  tools/perf/builtin-trace.c                  |  26 +--
> >  tools/perf/tests/backward-ring-buffer.c     |  18 +-
> >  tools/perf/tests/code-reading.c             |   4 +-
> >  tools/perf/tests/event-times.c              |   4 +-
> >  tools/perf/tests/event_update.c             |   2 +-
> >  tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
> >  tools/perf/tests/expand-cgroup.c            |   8 +-
> >  tools/perf/tests/hists_cumulate.c           |   2 +-
> >  tools/perf/tests/hists_filter.c             |   2 +-
> >  tools/perf/tests/hists_link.c               |   2 +-
> >  tools/perf/tests/hists_output.c             |   2 +-
> >  tools/perf/tests/hwmon_pmu.c                |   2 +-
> >  tools/perf/tests/keep-tracking.c            |   2 +-
> >  tools/perf/tests/mmap-basic.c               |  18 +-
> >  tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
> >  tools/perf/tests/parse-events.c             |   4 +-
> >  tools/perf/tests/parse-metric.c             |   4 +-
> >  tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
> >  tools/perf/tests/perf-record.c              |  18 +-
> >  tools/perf/tests/perf-time-to-tsc.c         |   2 +-
> >  tools/perf/tests/pfm.c                      |   4 +-
> >  tools/perf/tests/pmu-events.c               |   6 +-
> >  tools/perf/tests/pmu.c                      |   2 +-
> >  tools/perf/tests/sw-clock.c                 |  14 +-
> >  tools/perf/tests/switch-tracking.c          |   2 +-
> >  tools/perf/tests/task-exit.c                |  14 +-
> >  tools/perf/tests/tool_pmu.c                 |   2 +-
> >  tools/perf/tests/topology.c                 |   2 +-
> >  tools/perf/util/cgroup.c                    |   4 +-
> >  tools/perf/util/data-convert-bt.c           |   2 +-
> >  tools/perf/util/evlist.c                    |  20 ++-
> >  tools/perf/util/evlist.h                    |   7 +-
> >  tools/perf/util/expr.c                      |   2 +-
> >  tools/perf/util/header.c                    |  12 +-
> >  tools/perf/util/metricgroup.c               |   6 +-
> >  tools/perf/util/parse-events.c              |   4 +-
> >  tools/perf/util/perf_api_probe.c            |   2 +-
> >  tools/perf/util/python.c                    | 176 +++++++-------------
> >  tools/perf/util/record.c                    |   2 +-
> >  tools/perf/util/session.c                   |   2 +-
> >  tools/perf/util/sideband_evlist.c           |  16 +-
> >  51 files changed, 252 insertions(+), 299 deletions(-)
> >
> > diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
> > index e221ea104174..dfb0ffc0d030 100644
> > --- a/tools/perf/arch/x86/tests/hybrid.c
> > +++ b/tools/perf/arch/x86/tests/hybrid.c
> > @@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
> >               ret = e->check(evlist);
> >       }
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >
> >       return ret;
> >  }
> > diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
> > index 1eba3b4594ef..b31aef4ef28b 100644
> > --- a/tools/perf/arch/x86/tests/topdown.c
> > +++ b/tools/perf/arch/x86/tests/topdown.c
> > @@ -55,7 +55,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
> >                       *ret = TEST_FAIL;
> >               }
> >       }
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return 0;
> >  }
> >
> > diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
> > index 7442a2cd87ed..e0417552b0cb 100644
> > --- a/tools/perf/arch/x86/util/iostat.c
> > +++ b/tools/perf/arch/x86/util/iostat.c
> > @@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
> >       if (evlist->core.nr_entries > 0) {
> >               pr_warning("The -e and -M options are not supported."
> >                          "All chosen events/metrics will be dropped\n");
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               evlist = evlist__new();
> >               if (!evlist)
> >                       return -ENOMEM;
> > diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
> > index bfaf50e4e519..a802fb005ee3 100644
> > --- a/tools/perf/bench/evlist-open-close.c
> > +++ b/tools/perf/bench/evlist-open-close.c
> > @@ -75,7 +75,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> >               parse_events_error__exit(&err);
> >               pr_err("Run 'perf list' for a list of valid events\n");
> >               ret = 1;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >       parse_events_error__exit(&err);
> >       if (uid_str) {
> > @@ -84,24 +84,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> >               if (uid == UINT_MAX) {
> >                       pr_err("Invalid User: %s", uid_str);
> >                       ret = -EINVAL;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >               ret = parse_uid_filter(evlist, uid);
> >               if (ret)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >       ret = evlist__create_maps(evlist, &opts.target);
> >       if (ret < 0) {
> >               pr_err("Not enough memory to create thread/cpu maps\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__config(evlist, &opts, NULL);
> >
> >       return evlist;
> >
> > -out_delete_evlist:
> > -     evlist__delete(evlist);
> > +out_put_evlist:
> > +     evlist__put(evlist);
> >       return NULL;
> >  }
> >
> > @@ -150,7 +150,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> >               evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
> >       printf("  Number of iterations:\t%d\n", iterations);
> >
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >
> >       for (i = 0; i < iterations; i++) {
> >               pr_debug("Started iteration %d\n", i);
> > @@ -161,7 +161,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> >               gettimeofday(&start, NULL);
> >               err = bench__do_evlist_open_close(evlist);
> >               if (err) {
> > -                     evlist__delete(evlist);
> > +                     evlist__put(evlist);
> >                       return err;
> >               }
> >
> > @@ -170,7 +170,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> >               runtime_us = timeval2usec(&diff);
> >               update_stats(&time_stats, runtime_us);
> >
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
> >       }
> >
> > diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
> > index 6b6eec65f93f..4a2fe05e9786 100644
> > --- a/tools/perf/builtin-ftrace.c
> > +++ b/tools/perf/builtin-ftrace.c
> > @@ -1993,20 +1993,20 @@ int cmd_ftrace(int argc, const char **argv)
> >
> >       ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
> >       if (ret < 0)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if (argc) {
> >               ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
> >                                              argv, false,
> >                                              ftrace__workload_exec_failed_signal);
> >               if (ret < 0)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >
> >       ret = cmd_func(&ftrace);
> >
> > -out_delete_evlist:
> > -     evlist__delete(ftrace.evlist);
> > +out_put_evlist:
> > +     evlist__put(ftrace.evlist);
> >
> >  out_delete_filters:
> >       delete_filter_func(&ftrace.filters);
> > diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> > index f0f285763f19..b07cbe051e33 100644
> > --- a/tools/perf/builtin-kvm.c
> > +++ b/tools/perf/builtin-kvm.c
> > @@ -1806,7 +1806,7 @@ static struct evlist *kvm_live_event_list(void)
> >
> >  out:
> >       if (err) {
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               evlist = NULL;
> >       }
> >
> > @@ -1937,7 +1937,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
> >  out:
> >       perf_session__delete(kvm->session);
> >       kvm->session = NULL;
> > -     evlist__delete(kvm->evlist);
> > +     evlist__put(kvm->evlist);
> >
> >       return err;
> >  }
> > diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
> > index 078634461df2..2a57767f03a9 100644
> > --- a/tools/perf/builtin-lock.c
> > +++ b/tools/perf/builtin-lock.c
> > @@ -2143,7 +2143,7 @@ static int __cmd_contention(int argc, const char **argv)
> >
> >  out_delete:
> >       lock_filter_finish();
> > -     evlist__delete(con.evlist);
> > +     evlist__put(con.evlist);
> >       lock_contention_finish(&con);
> >       perf_session__delete(session);
> >       perf_env__exit(&host_env);
> > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> > index 3d8cf4090a92..738dbae80eac 100644
> > --- a/tools/perf/builtin-record.c
> > +++ b/tools/perf/builtin-record.c
> > @@ -4349,7 +4349,7 @@ int cmd_record(int argc, const char **argv)
> >                       goto out;
> >
> >               evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
> > -             evlist__delete(def_evlist);
> > +             evlist__put(def_evlist);
> >       }
> >
> >       if (rec->opts.target.tid && !rec->opts.no_inherit_set)
> > @@ -4460,7 +4460,7 @@ int cmd_record(int argc, const char **argv)
> >       auxtrace_record__free(rec->itr);
> >  out_opts:
> >       evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
> > -     evlist__delete(rec->evlist);
> > +     evlist__put(rec->evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> > index 886727ae8529..282926c6abd4 100644
> > --- a/tools/perf/builtin-stat.c
> > +++ b/tools/perf/builtin-stat.c
> > @@ -2067,7 +2067,7 @@ static int add_default_events(void)
> >                       metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
> >                                                       &evlist->metric_events,
> >                                                       &metric_evlist->metric_events);
> > -                     evlist__delete(metric_evlist);
> > +                     evlist__put(metric_evlist);
> >               }
> >       }
> >
> > @@ -2142,7 +2142,7 @@ static int add_default_events(void)
> >       metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
> >                                       &evsel_list->metric_events,
> >                                       &evlist->metric_events);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > @@ -2373,7 +2373,7 @@ static int __cmd_report(int argc, const char **argv)
> >
> >       perf_stat.session  = session;
> >       stat_config.output = stderr;
> > -     evlist__delete(evsel_list);
> > +     evlist__put(evsel_list);
> >       evsel_list         = session->evlist;
> >
> >       ret = perf_session__process_events(session);
> > @@ -3042,7 +3042,7 @@ int cmd_stat(int argc, const char **argv)
> >       if (smi_cost && smi_reset)
> >               sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
> >
> > -     evlist__delete(evsel_list);
> > +     evlist__put(evsel_list);
> >
> >       evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
> >
> > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> > index 710604c4f6f6..45d5dae54dcd 100644
> > --- a/tools/perf/builtin-top.c
> > +++ b/tools/perf/builtin-top.c
> > @@ -1641,14 +1641,14 @@ int cmd_top(int argc, const char **argv)
> >       perf_env__init(&host_env);
> >       status = perf_config(perf_top_config, &top);
> >       if (status)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       /*
> >        * Since the per arch annotation init routine may need the cpuid, read
> >        * it here, since we are not getting this from the perf.data header.
> >        */
> >       status = perf_env__set_cmdline(&host_env, argc, argv);
> >       if (status)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       status = perf_env__read_cpuid(&host_env);
> >       if (status) {
> > @@ -1669,44 +1669,44 @@ int cmd_top(int argc, const char **argv)
> >               annotate_opts.disassembler_style = strdup(disassembler_style);
> >               if (!annotate_opts.disassembler_style) {
> >                       status = -ENOMEM;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >       if (objdump_path) {
> >               annotate_opts.objdump_path = strdup(objdump_path);
> >               if (!annotate_opts.objdump_path) {
> >                       status = -ENOMEM;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >       if (addr2line_path) {
> >               symbol_conf.addr2line_path = strdup(addr2line_path);
> >               if (!symbol_conf.addr2line_path) {
> >                       status = -ENOMEM;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >
> >       status = symbol__validate_sym_arguments();
> >       if (status)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if (annotate_check_args() < 0)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if (!top.evlist->core.nr_entries) {
> >               struct evlist *def_evlist = evlist__new_default();
> >
> >               if (!def_evlist)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >
> >               evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
> > -             evlist__delete(def_evlist);
> > +             evlist__put(def_evlist);
> >       }
> >
> >       status = evswitch__init(&top.evswitch, top.evlist, stderr);
> >       if (status)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if (symbol_conf.report_hierarchy) {
> >               /* disable incompatible options */
> > @@ -1717,18 +1717,18 @@ int cmd_top(int argc, const char **argv)
> >                       pr_err("Error: --hierarchy and --fields options cannot be used together\n");
> >                       parse_options_usage(top_usage, options, "fields", 0);
> >                       parse_options_usage(NULL, options, "hierarchy", 0);
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >
> >       if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
> >               pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       if (nr_cgroups > 0 && opts->record_cgroup) {
> >               pr_err("--cgroup and --all-cgroups cannot be used together\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       if (branch_call_mode) {
> > @@ -1752,7 +1752,7 @@ int cmd_top(int argc, const char **argv)
> >               status = perf_env__read_core_pmu_caps(&host_env);
> >               if (status) {
> >                       pr_err("PMU capability data is not available\n");
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >
> > @@ -1775,7 +1775,7 @@ int cmd_top(int argc, const char **argv)
> >       if (IS_ERR(top.session)) {
> >               status = PTR_ERR(top.session);
> >               top.session = NULL;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >       top.evlist->session = top.session;
> >
> > @@ -1785,7 +1785,7 @@ int cmd_top(int argc, const char **argv)
> >               if (field_order)
> >                       parse_options_usage(sort_order ? NULL : top_usage,
> >                                           options, "fields", 0);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       status = target__validate(target);
> > @@ -1800,11 +1800,11 @@ int cmd_top(int argc, const char **argv)
> >               if (uid == UINT_MAX) {
> >                       ui__error("Invalid User: %s", top.uid_str);
> >                       status = -EINVAL;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >               status = parse_uid_filter(top.evlist, uid);
> >               if (status)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >
> >       if (target__none(target))
> > @@ -1814,7 +1814,7 @@ int cmd_top(int argc, const char **argv)
> >               ui__error("Couldn't create thread/CPU maps: %s\n",
> >                         errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
> >               status = -errno;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       if (top.delay_secs < 1)
> > @@ -1822,7 +1822,7 @@ int cmd_top(int argc, const char **argv)
> >
> >       if (record_opts__config(opts)) {
> >               status = -EINVAL;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       top.sym_evsel = evlist__first(top.evlist);
> > @@ -1837,14 +1837,14 @@ int cmd_top(int argc, const char **argv)
> >
> >       status = symbol__annotation_init();
> >       if (status < 0)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       annotation_config__init();
> >
> >       symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
> >       status = symbol__init(NULL);
> >       if (status < 0)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       sort__setup_elide(stdout);
> >
> > @@ -1864,13 +1864,13 @@ int cmd_top(int argc, const char **argv)
> >               if (top.sb_evlist == NULL) {
> >                       pr_err("Couldn't create side band evlist.\n.");
> >                       status = -EINVAL;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
> >                       pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
> >                       status = -EINVAL;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >  #endif
> > @@ -1885,8 +1885,8 @@ int cmd_top(int argc, const char **argv)
> >       if (!opts->no_bpf_event)
> >               evlist__stop_sb_thread(top.sb_evlist);
> >
> > -out_delete_evlist:
> > -     evlist__delete(top.evlist);
> > +out_put_evlist:
> > +     evlist__put(top.evlist);
> >       perf_session__delete(top.session);
> >       annotation_options__exit();
> >       perf_env__exit(&host_env);
> > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > index a743bda294bd..c056df42a78f 100644
> > --- a/tools/perf/builtin-trace.c
> > +++ b/tools/perf/builtin-trace.c
> > @@ -4364,7 +4364,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >
> >       if (trace->summary_bpf) {
> >               if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >
> >               if (trace->summary_only)
> >                       goto create_maps;
> > @@ -4432,19 +4432,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >       err = evlist__create_maps(evlist, &trace->opts.target);
> >       if (err < 0) {
> >               fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       err = trace__symbols_init(trace, argc, argv, evlist);
> >       if (err < 0) {
> >               fprintf(trace->output, "Problems initializing symbol libraries!\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
> >               trace->syscall_stats = alloc_syscall_stats();
> >               if (IS_ERR(trace->syscall_stats))
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >
> >       evlist__config(evlist, &trace->opts, &callchain_param);
> > @@ -4453,7 +4453,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >               err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
> >               if (err < 0) {
> >                       fprintf(trace->output, "Couldn't run the workload!\n");
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >               workload_pid = evlist->workload.pid;
> >       }
> > @@ -4501,7 +4501,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >
> >       err = trace__expand_filters(trace, &evsel);
> >       if (err)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
> >       if (err < 0)
> >               goto out_error_apply_filters;
> > @@ -4618,12 +4618,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >               }
> >       }
> >
> > -out_delete_evlist:
> > +out_put_evlist:
> >       trace_cleanup_bpf_summary();
> >       delete_syscall_stats(trace->syscall_stats);
> >       trace__symbols__exit(trace);
> >       evlist__free_syscall_tp_fields(evlist);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       cgroup__put(trace->cgroup);
> >       trace->evlist = NULL;
> >       trace->live = false;
> > @@ -4648,22 +4648,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> >
> >  out_error:
> >       fprintf(trace->output, "%s\n", errbuf);
> > -     goto out_delete_evlist;
> > +     goto out_put_evlist;
> >
> >  out_error_apply_filters:
> >       fprintf(trace->output,
> >               "Failed to set filter \"%s\" on event %s with %d (%s)\n",
> >               evsel->filter, evsel__name(evsel), errno,
> >               str_error_r(errno, errbuf, sizeof(errbuf)));
> > -     goto out_delete_evlist;
> > +     goto out_put_evlist;
> >  }
> >  out_error_mem:
> >       fprintf(trace->output, "Not enough memory to run!\n");
> > -     goto out_delete_evlist;
> > +     goto out_put_evlist;
> >
> >  out_errno:
> >       fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
> > -     goto out_delete_evlist;
> > +     goto out_put_evlist;
> >  }
> >
> >  static int trace__replay(struct trace *trace)
> > @@ -5331,7 +5331,7 @@ static void trace__exit(struct trace *trace)
> >               zfree(&trace->syscalls.table);
> >       }
> >       zfree(&trace->perfconfig_events);
> > -     evlist__delete(trace->evlist);
> > +     evlist__put(trace->evlist);
> >       trace->evlist = NULL;
> >       ordered_events__free(&trace->oe.data);
> >  #ifdef HAVE_LIBBPF_SUPPORT
> > diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
> > index c5e7999f2817..2b49b002d749 100644
> > --- a/tools/perf/tests/backward-ring-buffer.c
> > +++ b/tools/perf/tests/backward-ring-buffer.c
> > @@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> >       err = evlist__create_maps(evlist, &opts.target);
> >       if (err < 0) {
> >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       parse_events_error__init(&parse_error);
> > @@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> >       if (err) {
> >               pr_debug("Failed to parse tracepoint event, try use root\n");
> >               ret = TEST_SKIP;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__config(evlist, &opts, NULL);
> > @@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> >       if (err < 0) {
> >               pr_debug("perf_evlist__open: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       ret = TEST_FAIL;
> >       err = do_test(evlist, opts.mmap_pages, &sample_count,
> >                     &comm_count);
> >       if (err != TEST_OK)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
> >               pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
> >                      sample_count, comm_count);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__close(evlist);
> > @@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> >       if (err < 0) {
> >               pr_debug("perf_evlist__open: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       err = do_test(evlist, 1, &sample_count, &comm_count);
> >       if (err != TEST_OK)
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       ret = TEST_OK;
> > -out_delete_evlist:
> > -     evlist__delete(evlist);
> > +out_put_evlist:
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
> > index 5927d1ea20e2..8da8951154d8 100644
> > --- a/tools/perf/tests/code-reading.c
> > +++ b/tools/perf/tests/code-reading.c
> > @@ -806,7 +806,7 @@ static int do_test_code_reading(bool try_kcore)
> >                       }
> >
> >                       perf_evlist__set_maps(&evlist->core, NULL, NULL);
> > -                     evlist__delete(evlist);
> > +                     evlist__put(evlist);
> >                       evlist = NULL;
> >                       continue;
> >               }
> > @@ -843,7 +843,7 @@ static int do_test_code_reading(bool try_kcore)
> >  out_put:
> >       thread__put(thread);
> >  out_err:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> >       machine__delete(machine);
> > diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
> > index ae3b98bb42cf..94ab54ecd3f9 100644
> > --- a/tools/perf/tests/event-times.c
> > +++ b/tools/perf/tests/event-times.c
> > @@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
> >       err = attach(evlist);
> >       if (err == TEST_SKIP) {
> >               pr_debug("  SKIP  : not enough rights\n");
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               return err;
> >       }
> >
> > @@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
> >                count.ena, count.run);
> >
> >  out_err:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return !err ? TEST_OK : TEST_FAIL;
> >  }
> >
> > diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
> > index cb9e6de2e033..8de66dac52b0 100644
> > --- a/tools/perf/tests/event_update.c
> > +++ b/tools/perf/tests/event_update.c
> > @@ -115,7 +115,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
> >       TEST_ASSERT_VAL("failed to synthesize attr update cpus",
> >                       !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
> >
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return 0;
> >  }
> >
> > diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
> > index 1922cac13a24..6a220634c52f 100644
> > --- a/tools/perf/tests/evsel-roundtrip-name.c
> > +++ b/tools/perf/tests/evsel-roundtrip-name.c
> > @@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> >                               if (err) {
> >                                       pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
> >                                               name);
> > -                                     evlist__delete(evlist);
> > +                                     evlist__put(evlist);
> >                                       continue;
> >                               }
> >                               evlist__for_each_entry(evlist, evsel) {
> > @@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> >                                               ret = TEST_FAIL;
> >                                       }
> >                               }
> > -                             evlist__delete(evlist);
> > +                             evlist__put(evlist);
> >                       }
> >               }
> >       }
> > @@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> >               if (err) {
> >                       pr_debug("failed to parse event '%s', err %d\n",
> >                                names[i], err);
> > -                     evlist__delete(evlist);
> > +                     evlist__put(evlist);
> >                       ret = TEST_FAIL;
> >                       continue;
> >               }
> > @@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> >                               ret = TEST_FAIL;
> >                       }
> >               }
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >       }
> >       return ret;
> >  }
> > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > index c7b32a220ca1..9060b085e3de 100644
> > --- a/tools/perf/tests/expand-cgroup.c
> > +++ b/tools/perf/tests/expand-cgroup.c
> > @@ -104,7 +104,7 @@ static int expand_default_events(void)
> >       TEST_ASSERT_VAL("failed to get evlist", evlist);
> >
> >       ret = test_expand_events(evlist);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > @@ -131,7 +131,7 @@ static int expand_group_events(void)
> >       ret = test_expand_events(evlist);
> >  out:
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > @@ -162,7 +162,7 @@ static int expand_libpfm_events(void)
> >
> >       ret = test_expand_events(evlist);
> >  out:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > @@ -186,7 +186,7 @@ static int expand_metric_events(void)
> >       ret = test_expand_events(evlist);
> >
> >  out:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
> > index 3eb9ef8d7ec6..8f7cce7b5085 100644
> > --- a/tools/perf/tests/hists_cumulate.c
> > +++ b/tools/perf/tests/hists_cumulate.c
> > @@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
> >
> >  out:
> >       /* tear down everything */
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       machines__exit(&machines);
> >       put_fake_samples();
> >
> > diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
> > index 1cebd20cc91c..447fb2b5947c 100644
> > --- a/tools/perf/tests/hists_filter.c
> > +++ b/tools/perf/tests/hists_filter.c
> > @@ -331,7 +331,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
> >
> >  out:
> >       /* tear down everything */
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       reset_output_field();
> >       machines__exit(&machines);
> >       put_fake_samples();
> > diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
> > index 996f5f0b3bd1..9646c3b7b4de 100644
> > --- a/tools/perf/tests/hists_link.c
> > +++ b/tools/perf/tests/hists_link.c
> > @@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
> >
> >  out:
> >       /* tear down everything */
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       reset_output_field();
> >       machines__exit(&machines);
> >       put_fake_samples();
> > diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
> > index ee5ec8bda60e..aa8565fbaf90 100644
> > --- a/tools/perf/tests/hists_output.c
> > +++ b/tools/perf/tests/hists_output.c
> > @@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
> >
> >  out:
> >       /* tear down everything */
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       machines__exit(&machines);
> >       put_fake_samples();
> >
> > diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
> > index 97ea036ebae6..7d1040619575 100644
> > --- a/tools/perf/tests/hwmon_pmu.c
> > +++ b/tools/perf/tests/hwmon_pmu.c
> > @@ -211,7 +211,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
> >
> >  out:
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
> > index 729cc9cc1cb7..51cfd6522867 100644
> > --- a/tools/perf/tests/keep-tracking.c
> > +++ b/tools/perf/tests/keep-tracking.c
> > @@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
> >  out_err:
> >       if (evlist) {
> >               evlist__disable(evlist);
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >       }
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> > diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
> > index a622bb8d4cc8..2591b6fbec3f 100644
> > --- a/tools/perf/tests/mmap-basic.c
> > +++ b/tools/perf/tests/mmap-basic.c
> > @@ -93,7 +93,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >                               /* Permissions failure, flag the failure as a skip. */
> >                               err = TEST_SKIP;
> >                       }
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               evsels[i]->core.attr.wakeup_events = 1;
> > @@ -105,7 +105,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >                       pr_debug("failed to open counter: %s, "
> >                                "tweak /proc/sys/kernel/perf_event_paranoid?\n",
> >                                str_error_r(errno, sbuf, sizeof(sbuf)));
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               nr_events[i] = 0;
> > @@ -115,7 +115,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >       if (evlist__mmap(evlist, 128) < 0) {
> >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       for (i = 0; i < nsyscalls; ++i)
> > @@ -133,7 +133,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >               if (event->header.type != PERF_RECORD_SAMPLE) {
> >                       pr_debug("unexpected %s event\n",
> >                                perf_event__name(event->header.type));
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               perf_sample__init(&sample, /*all=*/false);
> > @@ -141,7 +141,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >               if (err) {
> >                       pr_err("Can't parse sample, err = %d\n", err);
> >                       perf_sample__exit(&sample);
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               err = -1;
> > @@ -150,7 +150,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >               if (evsel == NULL) {
> >                       pr_debug("event with id %" PRIu64
> >                                " doesn't map to an evsel\n", sample.id);
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >               nr_events[evsel->core.idx]++;
> >               perf_mmap__consume(&md->core);
> > @@ -165,12 +165,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> >                                expected_nr_events[evsel->core.idx],
> >                                evsel__name(evsel), nr_events[evsel->core.idx]);
> >                       err = -1;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >
> > -out_delete_evlist:
> > -     evlist__delete(evlist);
> > +out_put_evlist:
> > +     evlist__put(evlist);
> >  out_free_cpus:
> >       perf_cpu_map__put(cpus);
> >  out_free_threads:
> > diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
> > index 2a139d2781a8..3ff595c7a86a 100644
> > --- a/tools/perf/tests/openat-syscall-tp-fields.c
> > +++ b/tools/perf/tests/openat-syscall-tp-fields.c
> > @@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >       if (IS_ERR(evsel)) {
> >               pr_debug("%s: evsel__newtp\n", __func__);
> >               ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__add(evlist, evsel);
> > @@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >       err = evlist__create_maps(evlist, &opts.target);
> >       if (err < 0) {
> >               pr_debug("%s: evlist__create_maps\n", __func__);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evsel__config(evsel, &opts, NULL);
> > @@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >       if (err < 0) {
> >               pr_debug("perf_evlist__open: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       err = evlist__mmap(evlist, UINT_MAX);
> >       if (err < 0) {
> >               pr_debug("evlist__mmap: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__enable(evlist);
> > @@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >                               if (err) {
> >                                       pr_debug("Can't parse sample, err = %d\n", err);
> >                                       perf_sample__exit(&sample);
> > -                                     goto out_delete_evlist;
> > +                                     goto out_put_evlist;
> >                               }
> >
> >                               tp_flags = evsel__intval(evsel, &sample, "flags");
> > @@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >                               if (flags != tp_flags) {
> >                                       pr_debug("%s: Expected flags=%#x, got %#x\n",
> >                                                __func__, flags, tp_flags);
> > -                                     goto out_delete_evlist;
> > +                                     goto out_put_evlist;
> >                               }
> >
> >                               goto out_ok;
> > @@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> >
> >               if (++nr_polls > 5) {
> >                       pr_debug("%s: no events!\n", __func__);
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >       }
> >  out_ok:
> >       ret = TEST_OK;
> > -out_delete_evlist:
> > -     evlist__delete(evlist);
> > +out_put_evlist:
> > +     evlist__put(evlist);
> >  out:
> >       return ret;
> >  }
> > diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
> > index e4cdb517c10e..0778462016f7 100644
> > --- a/tools/perf/tests/parse-events.c
> > +++ b/tools/perf/tests/parse-events.c
> > @@ -2550,7 +2550,7 @@ static int test_event(const struct evlist_test *e)
> >               ret = e->check(evlist);
> >       }
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >
> >       return ret;
> >  }
> > @@ -2576,7 +2576,7 @@ static int test_event_fake_pmu(const char *str)
> >       }
> >
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >
> >       return ret;
> >  }
> > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > index 66a5275917e2..b343628c7a7e 100644
> > --- a/tools/perf/tests/parse-metric.c
> > +++ b/tools/perf/tests/parse-metric.c
> > @@ -83,7 +83,7 @@ static int __compute_metric(const char *name, struct value *vals,
> >
> >       cpus = perf_cpu_map__new("0");
> >       if (!cpus) {
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               return -ENOMEM;
> >       }
> >
> > @@ -112,7 +112,7 @@ static int __compute_metric(const char *name, struct value *vals,
> >       /* ... cleanup. */
> >       evlist__free_stats(evlist);
> >       perf_cpu_map__put(cpus);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
> > index 50e68b7d43aa..d5a8d065809e 100644
> > --- a/tools/perf/tests/parse-no-sample-id-all.c
> > +++ b/tools/perf/tests/parse-no-sample-id-all.c
> > @@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
> >       for (i = 0; i < count && !err; i++)
> >               err = process_event(&evlist, events[i]);
> >
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >
> >       return err;
> >  }
> > diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> > index efbd9cd60c63..babec674b83c 100644
> > --- a/tools/perf/tests/perf-record.c
> > +++ b/tools/perf/tests/perf-record.c
> > @@ -102,7 +102,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >       err = evlist__create_maps(evlist, &opts.target);
> >       if (err < 0) {
> >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       /*
> > @@ -114,7 +114,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >       err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
> >       if (err < 0) {
> >               pr_debug("Couldn't run the workload!\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       /*
> > @@ -131,7 +131,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >               pr_debug("sched__get_first_possible_cpu: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> >               evlist__cancel_workload(evlist);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       cpu = err;
> > @@ -143,7 +143,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >               pr_debug("sched_setaffinity: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> >               evlist__cancel_workload(evlist);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       /*
> > @@ -155,7 +155,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >               pr_debug("perf_evlist__open: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> >               evlist__cancel_workload(evlist);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       /*
> > @@ -168,7 +168,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >               pr_debug("evlist__mmap: %s\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> >               evlist__cancel_workload(evlist);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       /*
> > @@ -206,7 +206,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >                                       if (verbose > 0)
> >                                               perf_event__fprintf(event, NULL, stderr);
> >                                       pr_debug("Couldn't parse sample\n");
> > -                                     goto out_delete_evlist;
> > +                                     goto out_put_evlist;
> >                               }
> >
> >                               if (verbose > 0) {
> > @@ -346,9 +346,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> >               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
> >               ++errs;
> >       }
> > -out_delete_evlist:
> > +out_put_evlist:
> >       CPU_FREE(cpu_mask);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >  out:
> >       perf_sample__exit(&sample);
> >       if (err == -EACCES)
> > diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
> > index cca41bd37ae3..d3538fa20af3 100644
> > --- a/tools/perf/tests/perf-time-to-tsc.c
> > +++ b/tools/perf/tests/perf-time-to-tsc.c
> > @@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
> >       err = TEST_OK;
> >
> >  out_err:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> >       return err;
> > diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
> > index 2e38dfa34b6c..099a50dec37e 100644
> > --- a/tools/perf/tests/pfm.c
> > +++ b/tools/perf/tests/pfm.c
> > @@ -79,7 +79,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
> >                               evlist__nr_groups(evlist),
> >                               0);
> >
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >       }
> >       return 0;
> >  }
> > @@ -164,7 +164,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
> >                               evlist__nr_groups(evlist),
> >                               table[i].nr_groups);
> >
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >       }
> >       return 0;
> >  }
> > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > index f40a828c9861..ab547f301c61 100644
> > --- a/tools/perf/tests/pmu-events.c
> > +++ b/tools/perf/tests/pmu-events.c
> > @@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
> >                            /*warn_if_reordered=*/true, /*fake_tp=*/false);
> >       free(dup);
> >
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > @@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> >
> >       cpus = perf_cpu_map__new("0");
> >       if (!cpus) {
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               return -ENOMEM;
> >       }
> >
> > @@ -901,7 +901,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> >       /* ... cleanup. */
> >       evlist__free_stats(evlist);
> >       perf_cpu_map__put(cpus);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
> > index cbded2c6faa4..bd3f4a2806ed 100644
> > --- a/tools/perf/tests/pmu.c
> > +++ b/tools/perf/tests/pmu.c
> > @@ -249,7 +249,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
> >       ret = TEST_OK;
> >  err_out:
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       test_pmu_put(dir, pmu);
> >       return ret;
> >  }
> > diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
> > index 4a2ad7176fa0..f7f1f16638b4 100644
> > --- a/tools/perf/tests/sw-clock.c
> > +++ b/tools/perf/tests/sw-clock.c
> > @@ -58,7 +58,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> >       evsel = evsel__new(&attr);
> >       if (evsel == NULL) {
> >               pr_debug("evsel__new\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >       evlist__add(evlist, evsel);
> >
> > @@ -67,7 +67,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> >       if (!cpus || !threads) {
> >               err = -ENOMEM;
> >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > @@ -79,14 +79,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> >               pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
> >                        str_error_r(errno, sbuf, sizeof(sbuf)),
> >                        knob, (u64)attr.sample_freq);
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       err = evlist__mmap(evlist, 128);
> >       if (err < 0) {
> >               pr_debug("failed to mmap event: %d (%s)\n", errno,
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__enable(evlist);
> > @@ -112,7 +112,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> >               if (err < 0) {
> >                       pr_debug("Error during parse sample\n");
> >                       perf_sample__exit(&sample);
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               total_periods += sample.period;
> > @@ -130,10 +130,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> >               err = -1;
> >       }
> >
> > -out_delete_evlist:
> > +out_put_evlist:
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
> > index 15791fcb76b2..c3d5825df0a8 100644
> > --- a/tools/perf/tests/switch-tracking.c
> > +++ b/tools/perf/tests/switch-tracking.c
> > @@ -577,7 +577,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
> >  out:
> >       if (evlist) {
> >               evlist__disable(evlist);
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >       }
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> > diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
> > index 4053ff2813bb..a46650b10689 100644
> > --- a/tools/perf/tests/task-exit.c
> > +++ b/tools/perf/tests/task-exit.c
> > @@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> >       if (!cpus || !threads) {
> >               err = -ENOMEM;
> >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > @@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> >       err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
> >       if (err < 0) {
> >               pr_debug("Couldn't run the workload!\n");
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evsel = evlist__first(evlist);
> > @@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> >       if (err < 0) {
> >               pr_debug("Couldn't open the evlist: %s\n",
> >                        str_error_r(-err, sbuf, sizeof(sbuf)));
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       if (evlist__mmap(evlist, 128) < 0) {
> >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> >               err = -1;
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >       }
> >
> >       evlist__start_workload(evlist);
> > @@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> >               if (retry_count++ > 1000) {
> >                       pr_debug("Failed after retrying 1000 times\n");
> >                       err = -1;
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >               }
> >
> >               goto retry;
> > @@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> >               err = -1;
> >       }
> >
> > -out_delete_evlist:
> > +out_put_evlist:
> >       perf_cpu_map__put(cpus);
> >       perf_thread_map__put(threads);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
> > index 1e900ef92e37..e78ff9dcea97 100644
> > --- a/tools/perf/tests/tool_pmu.c
> > +++ b/tools/perf/tests/tool_pmu.c
> > @@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
> >
> >  out:
> >       parse_events_error__exit(&err);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
> > index af4618c3124a..b88447899021 100644
> > --- a/tools/perf/tests/topology.c
> > +++ b/tools/perf/tests/topology.c
> > @@ -55,7 +55,7 @@ static int session_write_header(char *path)
> >                       !perf_session__write_header(session, session->evlist,
> >                                                   perf_data__fd(&data), true));
> >
> > -     evlist__delete(session->evlist);
> > +     evlist__put(session->evlist);
> >       perf_session__delete(session);
> >
> >       return 0;
> > diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
> > index 25e2769b5e74..ed230cd44ba7 100644
> > --- a/tools/perf/util/cgroup.c
> > +++ b/tools/perf/util/cgroup.c
> > @@ -503,8 +503,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
> >       cgrp_event_expanded = true;
> >
> >  out_err:
> > -     evlist__delete(orig_list);
> > -     evlist__delete(tmp_list);
> > +     evlist__put(orig_list);
> > +     evlist__put(tmp_list);
> >       metricgroup__rblist_exit(&orig_metric_events);
> >       release_cgroup_list();
> >
> > diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
> > index 3d2e437e1354..1166cdb00aca 100644
> > --- a/tools/perf/util/data-convert-bt.c
> > +++ b/tools/perf/util/data-convert-bt.c
> > @@ -1331,7 +1331,7 @@ static void cleanup_events(struct perf_session *session)
> >               zfree(&evsel->priv);
> >       }
> >
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       session->evlist = NULL;
> >  }
> >
> > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > index d99a3f12606f..ea1f398c14e3 100644
> > --- a/tools/perf/util/evlist.c
> > +++ b/tools/perf/util/evlist.c
> > @@ -73,7 +73,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
> >  #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
> >  #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
> >
> > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > +static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> >                 struct perf_thread_map *threads)
> >  {
> >       perf_evlist__init(&evlist->core);
> > @@ -85,6 +85,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> >       evlist->ctl_fd.pos = -1;
> >       evlist->nr_br_cntr = -1;
> >       metricgroup__rblist_init(&evlist->metric_events);
> > +     refcount_set(&evlist->refcnt, 1);
> >  }
> >
> >  struct evlist *evlist__new(void)
> > @@ -116,7 +117,7 @@ struct evlist *evlist__new_default(void)
> >                        can_profile_kernel ? "P" : "Pu");
> >               err = parse_event(evlist, buf);
> >               if (err) {
> > -                     evlist__delete(evlist);
> > +                     evlist__put(evlist);
> >                       return NULL;
> >               }
> >       }
> > @@ -136,13 +137,19 @@ struct evlist *evlist__new_dummy(void)
> >       struct evlist *evlist = evlist__new();
> >
> >       if (evlist && evlist__add_dummy(evlist)) {
> > -             evlist__delete(evlist);
> > +             evlist__put(evlist);
> >               evlist = NULL;
> >       }
> >
> >       return evlist;
> >  }
> >
> > +struct evlist *evlist__get(struct evlist *evlist)
> > +{
> > +     refcount_inc(&evlist->refcnt);
> > +     return evlist;
> > +}
> > +
> >  /**
> >   * evlist__set_id_pos - set the positions of event ids.
> >   * @evlist: selected event list
> > @@ -181,7 +188,7 @@ static void evlist__purge(struct evlist *evlist)
> >       evlist->core.nr_entries = 0;
> >  }
> >
> > -void evlist__exit(struct evlist *evlist)
> > +static void evlist__exit(struct evlist *evlist)
> >  {
> >       metricgroup__rblist_exit(&evlist->metric_events);
> >       event_enable_timer__exit(&evlist->eet);
> > @@ -190,11 +197,14 @@ void evlist__exit(struct evlist *evlist)
> >       perf_evlist__exit(&evlist->core);
> >  }
> >
> > -void evlist__delete(struct evlist *evlist)
> > +void evlist__put(struct evlist *evlist)
> >  {
> >       if (evlist == NULL)
> >               return;
> >
> > +     if (!refcount_dec_and_test(&evlist->refcnt))
> > +             return;
> > +
> >       evlist__free_stats(evlist);
> >       evlist__munmap(evlist);
> >       evlist__close(evlist);
> > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > index 61acbb10d9a5..66fb5da08160 100644
> > --- a/tools/perf/util/evlist.h
> > +++ b/tools/perf/util/evlist.h
> > @@ -59,6 +59,7 @@ struct event_enable_timer;
> >
> >  struct evlist {
> >       struct perf_evlist core;
> > +     refcount_t       refcnt;
> >       bool             enabled;
> >       int              id_pos;
> >       int              is_pos;
> > @@ -104,10 +105,8 @@ struct evsel_str_handler {
> >  struct evlist *evlist__new(void);
> >  struct evlist *evlist__new_default(void);
> >  struct evlist *evlist__new_dummy(void);
> > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > -               struct perf_thread_map *threads);
> > -void evlist__exit(struct evlist *evlist);
> > -void evlist__delete(struct evlist *evlist);
> > +struct evlist *evlist__get(struct evlist *evlist);
> > +void evlist__put(struct evlist *evlist);
> >
> >  void evlist__add(struct evlist *evlist, struct evsel *entry);
> >  void evlist__remove(struct evlist *evlist, struct evsel *evsel);
> > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > index 7fda0ff89c16..4304b53b5a37 100644
> > --- a/tools/perf/util/expr.c
> > +++ b/tools/perf/util/expr.c
> > @@ -451,7 +451,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
> >               ret = parse_event(tmp, id) ? 0 : 1;
> >       }
> >  out:
> > -     evlist__delete(tmp);
> > +     evlist__put(tmp);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> > index 4f2a6e10ed5c..e959ddb12dc8 100644
> > --- a/tools/perf/util/header.c
> > +++ b/tools/perf/util/header.c
> > @@ -4307,12 +4307,12 @@ int perf_session__read_header(struct perf_session *session)
> >               evsel = evsel__new(&f_attr.attr);
> >
> >               if (evsel == NULL)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >
> >               evsel->needs_swap = header->needs_swap;
> >               /*
> >                * Do it before so that if perf_evsel__alloc_id fails, this
> > -              * entry gets purged too at evlist__delete().
> > +              * entry gets purged too at evlist__put().
> >                */
> >               evlist__add(session->evlist, evsel);
> >
> > @@ -4323,7 +4323,7 @@ int perf_session__read_header(struct perf_session *session)
> >                * hattr->ids threads.
> >                */
> >               if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >
> >               lseek(fd, f_attr.ids.offset, SEEK_SET);
> >
> > @@ -4342,7 +4342,7 @@ int perf_session__read_header(struct perf_session *session)
> >                                     perf_file_section__process);
> >
> >       if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >  #else
> >       perf_header__process_sections(header, fd, NULL, perf_file_section__process);
> >  #endif
> > @@ -4351,8 +4351,8 @@ int perf_session__read_header(struct perf_session *session)
> >  out_errno:
> >       return -errno;
> >
> > -out_delete_evlist:
> > -     evlist__delete(session->evlist);
> > +out_put_evlist:
> > +     evlist__put(session->evlist);
> >       session->evlist = NULL;
> >       return -ENOMEM;
> >  }
> > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > index 595b83142d2c..64c64dff7424 100644
> > --- a/tools/perf/util/metricgroup.c
> > +++ b/tools/perf/util/metricgroup.c
> > @@ -212,7 +212,7 @@ static void metric__free(struct metric *m)
> >       zfree(&m->metric_refs);
> >       expr__ctx_free(m->pctx);
> >       zfree(&m->modifier);
> > -     evlist__delete(m->evlist);
> > +     evlist__put(m->evlist);
> >       free(m);
> >  }
> >
> > @@ -1318,7 +1318,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
> >       parsed_evlist = NULL;
> >  err_out:
> >       parse_events_error__exit(&parse_error);
> > -     evlist__delete(parsed_evlist);
> > +     evlist__put(parsed_evlist);
> >       strbuf_release(&events);
> >       return ret;
> >  }
> > @@ -1470,7 +1470,7 @@ static int parse_groups(struct evlist *perf_evlist,
> >
> >       if (combined_evlist) {
> >               evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
> > -             evlist__delete(combined_evlist);
> > +             evlist__put(combined_evlist);
> >       }
> >
> >       list_for_each_entry(m, &metric_list, nd) {
> > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> > index 0c0dc20b1c13..607ab7b82486 100644
> > --- a/tools/perf/util/parse-events.c
> > +++ b/tools/perf/util/parse-events.c
> > @@ -2223,7 +2223,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
> >
> >       /*
> >        * There are 2 users - builtin-record and builtin-test objects.
> > -      * Both call evlist__delete in case of error, so we dont
> > +      * Both call evlist__put in case of error, so we dont
> >        * need to bother.
> >        */
> >       return ret;
> > @@ -2424,7 +2424,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
> >       }
> >       ret = parse_events_option(opt, str, unset);
> >       if (ret) {
> > -             evlist__delete(*args->evlistp);
> > +             evlist__put(*args->evlistp);
> >               *args->evlistp = NULL;
> >       }
> >
> > diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
> > index 3345145a9307..8cd254d36220 100644
> > --- a/tools/perf/util/perf_api_probe.c
> > +++ b/tools/perf/util/perf_api_probe.c
> > @@ -56,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
> >       err = 0;
> >
> >  out_delete:
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >       return err;
> >  }
> >
> > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> > index dfc6e9299af9..4149a51e9878 100644
> > --- a/tools/perf/util/python.c
> > +++ b/tools/perf/util/python.c
> > @@ -1273,7 +1273,7 @@ static int pyrf_evsel__setup_types(void)
> >  struct pyrf_evlist {
> >       PyObject_HEAD
> >
> > -     struct evlist evlist;
> > +     struct evlist *evlist;
> >  };
> >
> >  static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> > @@ -1286,15 +1286,21 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> >       if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
> >               return -1;
> >
> > +     pevlist->evlist = evlist__new();
> > +     if (!pevlist->evlist) {
> > +             PyErr_NoMemory();
> > +             return -1;
> > +     }
> >       threads = ((struct pyrf_thread_map *)pthreads)->threads;
> >       cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
> > -     evlist__init(&pevlist->evlist, cpus, threads);
> > +     perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
> > +
> >       return 0;
> >  }
> >
> >  static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
> >  {
> > -     evlist__exit(&pevlist->evlist);
> > +     evlist__put(pevlist->evlist);
> >       Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
> >  }
> >
> > @@ -1303,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
> >       struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
> >
> >       if (pcpu_map)
> > -             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
> > +             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
> >
> >       return (PyObject *)pcpu_map;
> >  }
> > @@ -1316,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
> >       if (!list)
> >               return NULL;
> >
> > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
> >            node = rb_next(node)) {
> >               struct metric_event *me = container_of(node, struct metric_event, nd);
> >               struct list_head *pos;
> > @@ -1400,7 +1406,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> >       if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
> >               return NULL;
> >
> > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
> > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
> >            mexp == NULL && node;
> >            node = rb_next(node)) {
> >               struct metric_event *me = container_of(node, struct metric_event, nd);
> > @@ -1456,7 +1462,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> >  static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> >                                  PyObject *args, PyObject *kwargs)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >       static char *kwlist[] = { "pages", "overwrite", NULL };
> >       int pages = 128, overwrite = false;
> >
> > @@ -1476,7 +1482,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> >  static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
> >                                  PyObject *args, PyObject *kwargs)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >       static char *kwlist[] = { "timeout", NULL };
> >       int timeout = -1, n;
> >
> > @@ -1496,7 +1502,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
> >                                        PyObject *args __maybe_unused,
> >                                        PyObject *kwargs __maybe_unused)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >          PyObject *list = PyList_New(0);
> >       int i;
> >
> > @@ -1525,7 +1531,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
> >                                 PyObject *args,
> >                                 PyObject *kwargs __maybe_unused)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >       PyObject *pevsel;
> >       struct evsel *evsel;
> >
> > @@ -1557,7 +1563,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
> >  static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> >                                         PyObject *args, PyObject *kwargs)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >       union perf_event *event;
> >       int sample_id_all = 1, cpu;
> >       static char *kwlist[] = { "cpu", "sample_id_all", NULL };
> > @@ -1614,7 +1620,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> >  static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> >                                  PyObject *args, PyObject *kwargs)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >
> >       if (evlist__open(evlist) < 0) {
> >               PyErr_SetFromErrno(PyExc_OSError);
> > @@ -1627,7 +1633,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> >
> >  static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
> >  {
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >
> >       evlist__close(evlist);
> >
> > @@ -1653,7 +1659,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> >               .no_buffering        = true,
> >               .no_inherit          = true,
> >       };
> > -     struct evlist *evlist = &pevlist->evlist;
> > +     struct evlist *evlist = pevlist->evlist;
> >
> >       evlist__config(evlist, &opts, &callchain_param);
> >       Py_INCREF(Py_None);
> > @@ -1662,14 +1668,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> >
> >  static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
> >  {
> > -     evlist__disable(&pevlist->evlist);
> > +     evlist__disable(pevlist->evlist);
> >       Py_INCREF(Py_None);
> >       return Py_None;
> >  }
> >
> >  static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
> >  {
> > -     evlist__enable(&pevlist->evlist);
> > +     evlist__enable(pevlist->evlist);
> >       Py_INCREF(Py_None);
> >       return Py_None;
> >  }
> > @@ -1760,7 +1766,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
> >  {
> >       struct pyrf_evlist *pevlist = (void *)obj;
> >
> > -     return pevlist->evlist.core.nr_entries;
> > +     return pevlist->evlist->core.nr_entries;
> > +}
> > +
> > +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > +{
> > +     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > +
> > +     if (!pevsel)
> > +             return NULL;
> > +
> > +     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > +     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > +
> > +     evsel__clone(&pevsel->evsel, evsel);
> > +     if (evsel__is_group_leader(evsel))
> > +             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > +     return (PyObject *)pevsel;
> >  }
> >
> >  static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> > @@ -1768,17 +1790,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> >       struct pyrf_evlist *pevlist = (void *)obj;
> >       struct evsel *pos;
> >
> > -     if (i >= pevlist->evlist.core.nr_entries) {
> > +     if (i >= pevlist->evlist->core.nr_entries) {
> >               PyErr_SetString(PyExc_IndexError, "Index out of range");
> >               return NULL;
> >       }
> >
> > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > +     evlist__for_each_entry(pevlist->evlist, pos) {
> >               if (i-- == 0)
> >                       break;
> >       }
> > -
> > -     return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
> > +     return pyrf_evsel__from_evsel(pos);
> >  }
> >
> >  static PyObject *pyrf_evlist__str(PyObject *self)
> > @@ -1790,7 +1811,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
> >       PyObject *result;
> >
> >       strbuf_addstr(&sb, "evlist([");
> > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > +     evlist__for_each_entry(pevlist->evlist, pos) {
> >               if (!first)
> >                       strbuf_addch(&sb, ',');
> >               if (!pos->pmu)
> > @@ -1931,110 +1952,30 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
> >       return PyLong_FromLong(tp_pmu__id(sys, name));
> >  }
> >
> > -static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > -{
> > -     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > -
> > -     if (!pevsel)
> > -             return NULL;
> > -
> > -     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > -     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > -
> > -     evsel__clone(&pevsel->evsel, evsel);
> > -     if (evsel__is_group_leader(evsel))
> > -             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > -     return (PyObject *)pevsel;
> > -}
> > -
> > -static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
> > -{
> > -     struct evsel *pos;
> > -     int idx = 0;
> > -
> > -     evlist__for_each_entry(evlist, pos) {
> > -             if (evsel == pos)
> > -                     return idx;
> > -             idx++;
> > -     }
> > -     return -1;
> > -}
> > -
> > -static struct evsel *evlist__at(struct evlist *evlist, int idx)
> > -{
> > -     struct evsel *pos;
> > -     int idx2 = 0;
> > -
> > -     evlist__for_each_entry(evlist, pos) {
> > -             if (idx == idx2)
> > -                     return pos;
> > -             idx2++;
> > -     }
> > -     return NULL;
> > -}
> > -
> >  static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
> >  {
> >       struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
> > -     struct evsel *pos;
> > -     struct rb_node *node;
> >
> >       if (!pevlist)
> >               return NULL;
> >
> > -     memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
> > -     evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
> > -     evlist__for_each_entry(evlist, pos) {
> > -             struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
> > -
> > -             evlist__add(&pevlist->evlist, &pevsel->evsel);
> > -     }
> > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > -             struct evsel *leader = evsel__leader(pos);
> > -
> > -             if (pos != leader) {
> > -                     int idx = evlist__pos(evlist, leader);
> > -
> > -                     if (idx >= 0)
> > -                             evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
> > -                     else if (leader == NULL)
> > -                             evsel__set_leader(pos, pos);
> > -             }
> > -     }
> > -     metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
> > -                                     &pevlist->evlist.metric_events,
> > -                                     &evlist->metric_events);
> > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > -          node = rb_next(node)) {
> > -             struct metric_event *me = container_of(node, struct metric_event, nd);
> > -             struct list_head *mpos;
> > -             int idx = evlist__pos(evlist, me->evsel);
> > -
> > -             if (idx >= 0)
> > -                     me->evsel = evlist__at(&pevlist->evlist, idx);
> > -             list_for_each(mpos, &me->head) {
> > -                     struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
> > -
> > -                     for (int j = 0; e->metric_events[j]; j++) {
> > -                             idx = evlist__pos(evlist, e->metric_events[j]);
> > -                             if (idx >= 0)
> > -                                     e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
> > -                     }
> > -             }
> > -     }
> > +     pevlist->evlist = evlist__get(evlist);
> >       return (PyObject *)pevlist;
> >  }
> >
> >  static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> >  {
> >       const char *input;
> > -     struct evlist evlist = {};
> > +     struct evlist *evlist = evlist__new();
> >       struct parse_events_error err;
> >       PyObject *result;
> >       PyObject *pcpus = NULL, *pthreads = NULL;
> >       struct perf_cpu_map *cpus;
> >       struct perf_thread_map *threads;
> >
> > +     if (!evlist)
> > +             return PyErr_NoMemory();
> > +
> >       if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
> >               return NULL;
> >
> > @@ -2042,35 +1983,38 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> >
> >       parse_events_error__init(&err);
> > -     evlist__init(&evlist, cpus, threads);
> > -     if (parse_events(&evlist, input, &err)) {
> > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > +     if (parse_events(evlist, input, &err)) {
> >               parse_events_error__print(&err, input);
> >               PyErr_SetFromErrno(PyExc_OSError);
> >               return NULL;
> >       }
> > -     result = pyrf_evlist__from_evlist(&evlist);
> > -     evlist__exit(&evlist);
> > +     result = pyrf_evlist__from_evlist(evlist);
> > +     evlist__put(evlist);
> >       return result;
> >  }
> >
> >  static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> >  {
> >       const char *input, *pmu = NULL;
> > -     struct evlist evlist = {};
> > +     struct evlist *evlist = evlist__new();
> >       PyObject *result;
> >       PyObject *pcpus = NULL, *pthreads = NULL;
> >       struct perf_cpu_map *cpus;
> >       struct perf_thread_map *threads;
> >       int ret;
> >
> > +     if (!evlist)
> > +             return PyErr_NoMemory();
> > +
> >       if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
> >               return NULL;
> >
> >       threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
> >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> >
> > -     evlist__init(&evlist, cpus, threads);
> > -     ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
> > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > +     ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
> >                                       /*metric_no_group=*/ false,
> >                                       /*metric_no_merge=*/ false,
> >                                       /*metric_no_threshold=*/ true,
> > @@ -2082,8 +2026,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> >               PyErr_SetFromErrno(PyExc_OSError);
> >               return NULL;
> >       }
> > -     result = pyrf_evlist__from_evlist(&evlist);
> > -     evlist__exit(&evlist);
> > +     result = pyrf_evlist__from_evlist(evlist);
> > +     evlist__put(evlist);
> >       return result;
> >  }
> >
> > diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
> > index e867de8ddaaa..8a5fc7d5e43c 100644
> > --- a/tools/perf/util/record.c
> > +++ b/tools/perf/util/record.c
> > @@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
> >       ret = true;
> >
> >  out_delete:
> > -     evlist__delete(temp_evlist);
> > +     evlist__put(temp_evlist);
> >       return ret;
> >  }
> >
> > diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> > index 081e68c72c30..f241d91221d7 100644
> > --- a/tools/perf/util/session.c
> > +++ b/tools/perf/util/session.c
> > @@ -256,7 +256,7 @@ void perf_session__delete(struct perf_session *session)
> >       machines__exit(&session->machines);
> >       if (session->data) {
> >               if (perf_data__is_read(session->data))
> > -                     evlist__delete(session->evlist);
> > +                     evlist__put(session->evlist);
> >               perf_data__close(session->data);
> >       }
> >  #ifdef HAVE_LIBTRACEEVENT
> > diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
> > index 388846f17bc1..b84a5463e039 100644
> > --- a/tools/perf/util/sideband_evlist.c
> > +++ b/tools/perf/util/sideband_evlist.c
> > @@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> >               return 0;
> >
> >       if (evlist__create_maps(evlist, target))
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       if (evlist->core.nr_entries > 1) {
> >               bool can_sample_identifier = perf_can_sample_identifier();
> > @@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> >       evlist__for_each_entry(evlist, counter) {
> >               if (evsel__open(counter, evlist->core.user_requested_cpus,
> >                               evlist->core.threads) < 0)
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >
> >       if (evlist__mmap(evlist, UINT_MAX))
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       evlist__for_each_entry(evlist, counter) {
> >               if (evsel__enable(counter))
> > -                     goto out_delete_evlist;
> > +                     goto out_put_evlist;
> >       }
> >
> >       evlist->thread.done = 0;
> >       if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
> > -             goto out_delete_evlist;
> > +             goto out_put_evlist;
> >
> >       return 0;
> >
> > -out_delete_evlist:
> > -     evlist__delete(evlist);
> > +out_put_evlist:
> > +     evlist__put(evlist);
> >       evlist = NULL;
> >       return -1;
> >  }
> > @@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
> >               return;
> >       evlist->thread.done = 1;
> >       pthread_join(evlist->thread.th, NULL);
> > -     evlist__delete(evlist);
> > +     evlist__put(evlist);
> >  }
> > --
> > 2.51.1.851.g4ebd6896fd-goog

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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29 16:56     ` Ian Rogers
@ 2025-10-29 18:33       ` Arnaldo Carvalho de Melo
  2025-10-29 21:12         ` Ian Rogers
  0 siblings, 1 reply; 22+ messages in thread
From: Arnaldo Carvalho de Melo @ 2025-10-29 18:33 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Wed, Oct 29, 2025 at 09:56:50AM -0700, Ian Rogers wrote:
> On Wed, Oct 29, 2025 at 9:22 AM Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
> >
> > On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> > > This a no-op for most of the perf tool. The reference count is set to
> > > 1 at allocation, the put will see the 1, decrement it and perform the
> > > delete. The purpose for adding the reference count is for the python
> > > code. Prior to this change the python code would clone evlists, but
> > > this has issues if events are opened, etc. This change adds a
> > > reference count for the evlists and a later change will add it to
> > > evsels. The combination is needed for the python code to operate
> > > correctly (not hit asserts in the evsel clone), but the changes are
> > > broken apart for the sake of smaller patches.
> >
> > Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
> > are not using the RC_CHK_ACCESS stuff from the get go, why not?
> 
> So if I did RC_CHK_ACCESS then every evsel access would need updating,

Fair enough, I think it would be informative to have a comment
mentioning this near the refcount_t to avoid this question popping up
again.

- Arnaldo

> accessor functions, and a lot of lines of code. As the reference count
> checking doesn't work with invasive lists, you need to interpose prev
> and next, I think we'd need to specially handle the case probably with
> an extra variable in evsel for reference count checking like:
> ```
> RC_STRUCT(evsel) {
> ...
>    struct evsel *evlist_ptr;
> ...
> }
> ```
> and things like evlist__for_each_entry need changes like:
> ```
> #define evlist__for_each_entry(evlist, evsel) \
>        __evlist__for_each_entry(&(evlist)->core.entries, orig_evsel) {
>            evsel = orig_evsel->evlist_ptr
> ```
> but it may be simpler to change evlist to use an array of evsel* as
> was done in places like `struct maps`.
> 
> Anyway, those changes I think would have taken away from what the
> series was trying to do and so weren't done here.
> 
> Thanks,
> Ian
> 
> > All the prep patches looks ok, assuming they build in succession.
> >
> > - Arnaldo
> >
> > > Signed-off-by: Ian Rogers <irogers@google.com>
> > > ---
> > >  tools/perf/arch/x86/tests/hybrid.c          |   2 +-
> > >  tools/perf/arch/x86/tests/topdown.c         |   2 +-
> > >  tools/perf/arch/x86/util/iostat.c           |   2 +-
> > >  tools/perf/bench/evlist-open-close.c        |  18 +-
> > >  tools/perf/builtin-ftrace.c                 |   8 +-
> > >  tools/perf/builtin-kvm.c                    |   4 +-
> > >  tools/perf/builtin-lock.c                   |   2 +-
> > >  tools/perf/builtin-record.c                 |   4 +-
> > >  tools/perf/builtin-stat.c                   |   8 +-
> > >  tools/perf/builtin-top.c                    |  52 +++---
> > >  tools/perf/builtin-trace.c                  |  26 +--
> > >  tools/perf/tests/backward-ring-buffer.c     |  18 +-
> > >  tools/perf/tests/code-reading.c             |   4 +-
> > >  tools/perf/tests/event-times.c              |   4 +-
> > >  tools/perf/tests/event_update.c             |   2 +-
> > >  tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
> > >  tools/perf/tests/expand-cgroup.c            |   8 +-
> > >  tools/perf/tests/hists_cumulate.c           |   2 +-
> > >  tools/perf/tests/hists_filter.c             |   2 +-
> > >  tools/perf/tests/hists_link.c               |   2 +-
> > >  tools/perf/tests/hists_output.c             |   2 +-
> > >  tools/perf/tests/hwmon_pmu.c                |   2 +-
> > >  tools/perf/tests/keep-tracking.c            |   2 +-
> > >  tools/perf/tests/mmap-basic.c               |  18 +-
> > >  tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
> > >  tools/perf/tests/parse-events.c             |   4 +-
> > >  tools/perf/tests/parse-metric.c             |   4 +-
> > >  tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
> > >  tools/perf/tests/perf-record.c              |  18 +-
> > >  tools/perf/tests/perf-time-to-tsc.c         |   2 +-
> > >  tools/perf/tests/pfm.c                      |   4 +-
> > >  tools/perf/tests/pmu-events.c               |   6 +-
> > >  tools/perf/tests/pmu.c                      |   2 +-
> > >  tools/perf/tests/sw-clock.c                 |  14 +-
> > >  tools/perf/tests/switch-tracking.c          |   2 +-
> > >  tools/perf/tests/task-exit.c                |  14 +-
> > >  tools/perf/tests/tool_pmu.c                 |   2 +-
> > >  tools/perf/tests/topology.c                 |   2 +-
> > >  tools/perf/util/cgroup.c                    |   4 +-
> > >  tools/perf/util/data-convert-bt.c           |   2 +-
> > >  tools/perf/util/evlist.c                    |  20 ++-
> > >  tools/perf/util/evlist.h                    |   7 +-
> > >  tools/perf/util/expr.c                      |   2 +-
> > >  tools/perf/util/header.c                    |  12 +-
> > >  tools/perf/util/metricgroup.c               |   6 +-
> > >  tools/perf/util/parse-events.c              |   4 +-
> > >  tools/perf/util/perf_api_probe.c            |   2 +-
> > >  tools/perf/util/python.c                    | 176 +++++++-------------
> > >  tools/perf/util/record.c                    |   2 +-
> > >  tools/perf/util/session.c                   |   2 +-
> > >  tools/perf/util/sideband_evlist.c           |  16 +-
> > >  51 files changed, 252 insertions(+), 299 deletions(-)
> > >
> > > diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
> > > index e221ea104174..dfb0ffc0d030 100644
> > > --- a/tools/perf/arch/x86/tests/hybrid.c
> > > +++ b/tools/perf/arch/x86/tests/hybrid.c
> > > @@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
> > >               ret = e->check(evlist);
> > >       }
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >
> > >       return ret;
> > >  }
> > > diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
> > > index 1eba3b4594ef..b31aef4ef28b 100644
> > > --- a/tools/perf/arch/x86/tests/topdown.c
> > > +++ b/tools/perf/arch/x86/tests/topdown.c
> > > @@ -55,7 +55,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
> > >                       *ret = TEST_FAIL;
> > >               }
> > >       }
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return 0;
> > >  }
> > >
> > > diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
> > > index 7442a2cd87ed..e0417552b0cb 100644
> > > --- a/tools/perf/arch/x86/util/iostat.c
> > > +++ b/tools/perf/arch/x86/util/iostat.c
> > > @@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
> > >       if (evlist->core.nr_entries > 0) {
> > >               pr_warning("The -e and -M options are not supported."
> > >                          "All chosen events/metrics will be dropped\n");
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               evlist = evlist__new();
> > >               if (!evlist)
> > >                       return -ENOMEM;
> > > diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
> > > index bfaf50e4e519..a802fb005ee3 100644
> > > --- a/tools/perf/bench/evlist-open-close.c
> > > +++ b/tools/perf/bench/evlist-open-close.c
> > > @@ -75,7 +75,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> > >               parse_events_error__exit(&err);
> > >               pr_err("Run 'perf list' for a list of valid events\n");
> > >               ret = 1;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >       parse_events_error__exit(&err);
> > >       if (uid_str) {
> > > @@ -84,24 +84,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> > >               if (uid == UINT_MAX) {
> > >                       pr_err("Invalid User: %s", uid_str);
> > >                       ret = -EINVAL;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >               ret = parse_uid_filter(evlist, uid);
> > >               if (ret)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >       ret = evlist__create_maps(evlist, &opts.target);
> > >       if (ret < 0) {
> > >               pr_err("Not enough memory to create thread/cpu maps\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__config(evlist, &opts, NULL);
> > >
> > >       return evlist;
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(evlist);
> > > +out_put_evlist:
> > > +     evlist__put(evlist);
> > >       return NULL;
> > >  }
> > >
> > > @@ -150,7 +150,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > >               evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
> > >       printf("  Number of iterations:\t%d\n", iterations);
> > >
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >
> > >       for (i = 0; i < iterations; i++) {
> > >               pr_debug("Started iteration %d\n", i);
> > > @@ -161,7 +161,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > >               gettimeofday(&start, NULL);
> > >               err = bench__do_evlist_open_close(evlist);
> > >               if (err) {
> > > -                     evlist__delete(evlist);
> > > +                     evlist__put(evlist);
> > >                       return err;
> > >               }
> > >
> > > @@ -170,7 +170,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > >               runtime_us = timeval2usec(&diff);
> > >               update_stats(&time_stats, runtime_us);
> > >
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
> > >       }
> > >
> > > diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
> > > index 6b6eec65f93f..4a2fe05e9786 100644
> > > --- a/tools/perf/builtin-ftrace.c
> > > +++ b/tools/perf/builtin-ftrace.c
> > > @@ -1993,20 +1993,20 @@ int cmd_ftrace(int argc, const char **argv)
> > >
> > >       ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
> > >       if (ret < 0)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if (argc) {
> > >               ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
> > >                                              argv, false,
> > >                                              ftrace__workload_exec_failed_signal);
> > >               if (ret < 0)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >
> > >       ret = cmd_func(&ftrace);
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(ftrace.evlist);
> > > +out_put_evlist:
> > > +     evlist__put(ftrace.evlist);
> > >
> > >  out_delete_filters:
> > >       delete_filter_func(&ftrace.filters);
> > > diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> > > index f0f285763f19..b07cbe051e33 100644
> > > --- a/tools/perf/builtin-kvm.c
> > > +++ b/tools/perf/builtin-kvm.c
> > > @@ -1806,7 +1806,7 @@ static struct evlist *kvm_live_event_list(void)
> > >
> > >  out:
> > >       if (err) {
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               evlist = NULL;
> > >       }
> > >
> > > @@ -1937,7 +1937,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
> > >  out:
> > >       perf_session__delete(kvm->session);
> > >       kvm->session = NULL;
> > > -     evlist__delete(kvm->evlist);
> > > +     evlist__put(kvm->evlist);
> > >
> > >       return err;
> > >  }
> > > diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
> > > index 078634461df2..2a57767f03a9 100644
> > > --- a/tools/perf/builtin-lock.c
> > > +++ b/tools/perf/builtin-lock.c
> > > @@ -2143,7 +2143,7 @@ static int __cmd_contention(int argc, const char **argv)
> > >
> > >  out_delete:
> > >       lock_filter_finish();
> > > -     evlist__delete(con.evlist);
> > > +     evlist__put(con.evlist);
> > >       lock_contention_finish(&con);
> > >       perf_session__delete(session);
> > >       perf_env__exit(&host_env);
> > > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> > > index 3d8cf4090a92..738dbae80eac 100644
> > > --- a/tools/perf/builtin-record.c
> > > +++ b/tools/perf/builtin-record.c
> > > @@ -4349,7 +4349,7 @@ int cmd_record(int argc, const char **argv)
> > >                       goto out;
> > >
> > >               evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
> > > -             evlist__delete(def_evlist);
> > > +             evlist__put(def_evlist);
> > >       }
> > >
> > >       if (rec->opts.target.tid && !rec->opts.no_inherit_set)
> > > @@ -4460,7 +4460,7 @@ int cmd_record(int argc, const char **argv)
> > >       auxtrace_record__free(rec->itr);
> > >  out_opts:
> > >       evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
> > > -     evlist__delete(rec->evlist);
> > > +     evlist__put(rec->evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> > > index 886727ae8529..282926c6abd4 100644
> > > --- a/tools/perf/builtin-stat.c
> > > +++ b/tools/perf/builtin-stat.c
> > > @@ -2067,7 +2067,7 @@ static int add_default_events(void)
> > >                       metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
> > >                                                       &evlist->metric_events,
> > >                                                       &metric_evlist->metric_events);
> > > -                     evlist__delete(metric_evlist);
> > > +                     evlist__put(metric_evlist);
> > >               }
> > >       }
> > >
> > > @@ -2142,7 +2142,7 @@ static int add_default_events(void)
> > >       metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
> > >                                       &evsel_list->metric_events,
> > >                                       &evlist->metric_events);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > @@ -2373,7 +2373,7 @@ static int __cmd_report(int argc, const char **argv)
> > >
> > >       perf_stat.session  = session;
> > >       stat_config.output = stderr;
> > > -     evlist__delete(evsel_list);
> > > +     evlist__put(evsel_list);
> > >       evsel_list         = session->evlist;
> > >
> > >       ret = perf_session__process_events(session);
> > > @@ -3042,7 +3042,7 @@ int cmd_stat(int argc, const char **argv)
> > >       if (smi_cost && smi_reset)
> > >               sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
> > >
> > > -     evlist__delete(evsel_list);
> > > +     evlist__put(evsel_list);
> > >
> > >       evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
> > >
> > > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> > > index 710604c4f6f6..45d5dae54dcd 100644
> > > --- a/tools/perf/builtin-top.c
> > > +++ b/tools/perf/builtin-top.c
> > > @@ -1641,14 +1641,14 @@ int cmd_top(int argc, const char **argv)
> > >       perf_env__init(&host_env);
> > >       status = perf_config(perf_top_config, &top);
> > >       if (status)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       /*
> > >        * Since the per arch annotation init routine may need the cpuid, read
> > >        * it here, since we are not getting this from the perf.data header.
> > >        */
> > >       status = perf_env__set_cmdline(&host_env, argc, argv);
> > >       if (status)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       status = perf_env__read_cpuid(&host_env);
> > >       if (status) {
> > > @@ -1669,44 +1669,44 @@ int cmd_top(int argc, const char **argv)
> > >               annotate_opts.disassembler_style = strdup(disassembler_style);
> > >               if (!annotate_opts.disassembler_style) {
> > >                       status = -ENOMEM;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >       if (objdump_path) {
> > >               annotate_opts.objdump_path = strdup(objdump_path);
> > >               if (!annotate_opts.objdump_path) {
> > >                       status = -ENOMEM;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >       if (addr2line_path) {
> > >               symbol_conf.addr2line_path = strdup(addr2line_path);
> > >               if (!symbol_conf.addr2line_path) {
> > >                       status = -ENOMEM;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >
> > >       status = symbol__validate_sym_arguments();
> > >       if (status)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if (annotate_check_args() < 0)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if (!top.evlist->core.nr_entries) {
> > >               struct evlist *def_evlist = evlist__new_default();
> > >
> > >               if (!def_evlist)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >
> > >               evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
> > > -             evlist__delete(def_evlist);
> > > +             evlist__put(def_evlist);
> > >       }
> > >
> > >       status = evswitch__init(&top.evswitch, top.evlist, stderr);
> > >       if (status)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if (symbol_conf.report_hierarchy) {
> > >               /* disable incompatible options */
> > > @@ -1717,18 +1717,18 @@ int cmd_top(int argc, const char **argv)
> > >                       pr_err("Error: --hierarchy and --fields options cannot be used together\n");
> > >                       parse_options_usage(top_usage, options, "fields", 0);
> > >                       parse_options_usage(NULL, options, "hierarchy", 0);
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >
> > >       if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
> > >               pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       if (nr_cgroups > 0 && opts->record_cgroup) {
> > >               pr_err("--cgroup and --all-cgroups cannot be used together\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       if (branch_call_mode) {
> > > @@ -1752,7 +1752,7 @@ int cmd_top(int argc, const char **argv)
> > >               status = perf_env__read_core_pmu_caps(&host_env);
> > >               if (status) {
> > >                       pr_err("PMU capability data is not available\n");
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >
> > > @@ -1775,7 +1775,7 @@ int cmd_top(int argc, const char **argv)
> > >       if (IS_ERR(top.session)) {
> > >               status = PTR_ERR(top.session);
> > >               top.session = NULL;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >       top.evlist->session = top.session;
> > >
> > > @@ -1785,7 +1785,7 @@ int cmd_top(int argc, const char **argv)
> > >               if (field_order)
> > >                       parse_options_usage(sort_order ? NULL : top_usage,
> > >                                           options, "fields", 0);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       status = target__validate(target);
> > > @@ -1800,11 +1800,11 @@ int cmd_top(int argc, const char **argv)
> > >               if (uid == UINT_MAX) {
> > >                       ui__error("Invalid User: %s", top.uid_str);
> > >                       status = -EINVAL;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >               status = parse_uid_filter(top.evlist, uid);
> > >               if (status)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >
> > >       if (target__none(target))
> > > @@ -1814,7 +1814,7 @@ int cmd_top(int argc, const char **argv)
> > >               ui__error("Couldn't create thread/CPU maps: %s\n",
> > >                         errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
> > >               status = -errno;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       if (top.delay_secs < 1)
> > > @@ -1822,7 +1822,7 @@ int cmd_top(int argc, const char **argv)
> > >
> > >       if (record_opts__config(opts)) {
> > >               status = -EINVAL;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       top.sym_evsel = evlist__first(top.evlist);
> > > @@ -1837,14 +1837,14 @@ int cmd_top(int argc, const char **argv)
> > >
> > >       status = symbol__annotation_init();
> > >       if (status < 0)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       annotation_config__init();
> > >
> > >       symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
> > >       status = symbol__init(NULL);
> > >       if (status < 0)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       sort__setup_elide(stdout);
> > >
> > > @@ -1864,13 +1864,13 @@ int cmd_top(int argc, const char **argv)
> > >               if (top.sb_evlist == NULL) {
> > >                       pr_err("Couldn't create side band evlist.\n.");
> > >                       status = -EINVAL;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
> > >                       pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
> > >                       status = -EINVAL;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >  #endif
> > > @@ -1885,8 +1885,8 @@ int cmd_top(int argc, const char **argv)
> > >       if (!opts->no_bpf_event)
> > >               evlist__stop_sb_thread(top.sb_evlist);
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(top.evlist);
> > > +out_put_evlist:
> > > +     evlist__put(top.evlist);
> > >       perf_session__delete(top.session);
> > >       annotation_options__exit();
> > >       perf_env__exit(&host_env);
> > > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > > index a743bda294bd..c056df42a78f 100644
> > > --- a/tools/perf/builtin-trace.c
> > > +++ b/tools/perf/builtin-trace.c
> > > @@ -4364,7 +4364,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >
> > >       if (trace->summary_bpf) {
> > >               if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >
> > >               if (trace->summary_only)
> > >                       goto create_maps;
> > > @@ -4432,19 +4432,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >       err = evlist__create_maps(evlist, &trace->opts.target);
> > >       if (err < 0) {
> > >               fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       err = trace__symbols_init(trace, argc, argv, evlist);
> > >       if (err < 0) {
> > >               fprintf(trace->output, "Problems initializing symbol libraries!\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
> > >               trace->syscall_stats = alloc_syscall_stats();
> > >               if (IS_ERR(trace->syscall_stats))
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >
> > >       evlist__config(evlist, &trace->opts, &callchain_param);
> > > @@ -4453,7 +4453,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >               err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
> > >               if (err < 0) {
> > >                       fprintf(trace->output, "Couldn't run the workload!\n");
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >               workload_pid = evlist->workload.pid;
> > >       }
> > > @@ -4501,7 +4501,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >
> > >       err = trace__expand_filters(trace, &evsel);
> > >       if (err)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
> > >       if (err < 0)
> > >               goto out_error_apply_filters;
> > > @@ -4618,12 +4618,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >               }
> > >       }
> > >
> > > -out_delete_evlist:
> > > +out_put_evlist:
> > >       trace_cleanup_bpf_summary();
> > >       delete_syscall_stats(trace->syscall_stats);
> > >       trace__symbols__exit(trace);
> > >       evlist__free_syscall_tp_fields(evlist);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       cgroup__put(trace->cgroup);
> > >       trace->evlist = NULL;
> > >       trace->live = false;
> > > @@ -4648,22 +4648,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > >
> > >  out_error:
> > >       fprintf(trace->output, "%s\n", errbuf);
> > > -     goto out_delete_evlist;
> > > +     goto out_put_evlist;
> > >
> > >  out_error_apply_filters:
> > >       fprintf(trace->output,
> > >               "Failed to set filter \"%s\" on event %s with %d (%s)\n",
> > >               evsel->filter, evsel__name(evsel), errno,
> > >               str_error_r(errno, errbuf, sizeof(errbuf)));
> > > -     goto out_delete_evlist;
> > > +     goto out_put_evlist;
> > >  }
> > >  out_error_mem:
> > >       fprintf(trace->output, "Not enough memory to run!\n");
> > > -     goto out_delete_evlist;
> > > +     goto out_put_evlist;
> > >
> > >  out_errno:
> > >       fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
> > > -     goto out_delete_evlist;
> > > +     goto out_put_evlist;
> > >  }
> > >
> > >  static int trace__replay(struct trace *trace)
> > > @@ -5331,7 +5331,7 @@ static void trace__exit(struct trace *trace)
> > >               zfree(&trace->syscalls.table);
> > >       }
> > >       zfree(&trace->perfconfig_events);
> > > -     evlist__delete(trace->evlist);
> > > +     evlist__put(trace->evlist);
> > >       trace->evlist = NULL;
> > >       ordered_events__free(&trace->oe.data);
> > >  #ifdef HAVE_LIBBPF_SUPPORT
> > > diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
> > > index c5e7999f2817..2b49b002d749 100644
> > > --- a/tools/perf/tests/backward-ring-buffer.c
> > > +++ b/tools/perf/tests/backward-ring-buffer.c
> > > @@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > >       err = evlist__create_maps(evlist, &opts.target);
> > >       if (err < 0) {
> > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       parse_events_error__init(&parse_error);
> > > @@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > >       if (err) {
> > >               pr_debug("Failed to parse tracepoint event, try use root\n");
> > >               ret = TEST_SKIP;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__config(evlist, &opts, NULL);
> > > @@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > >       if (err < 0) {
> > >               pr_debug("perf_evlist__open: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       ret = TEST_FAIL;
> > >       err = do_test(evlist, opts.mmap_pages, &sample_count,
> > >                     &comm_count);
> > >       if (err != TEST_OK)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
> > >               pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
> > >                      sample_count, comm_count);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__close(evlist);
> > > @@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > >       if (err < 0) {
> > >               pr_debug("perf_evlist__open: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       err = do_test(evlist, 1, &sample_count, &comm_count);
> > >       if (err != TEST_OK)
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       ret = TEST_OK;
> > > -out_delete_evlist:
> > > -     evlist__delete(evlist);
> > > +out_put_evlist:
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
> > > index 5927d1ea20e2..8da8951154d8 100644
> > > --- a/tools/perf/tests/code-reading.c
> > > +++ b/tools/perf/tests/code-reading.c
> > > @@ -806,7 +806,7 @@ static int do_test_code_reading(bool try_kcore)
> > >                       }
> > >
> > >                       perf_evlist__set_maps(&evlist->core, NULL, NULL);
> > > -                     evlist__delete(evlist);
> > > +                     evlist__put(evlist);
> > >                       evlist = NULL;
> > >                       continue;
> > >               }
> > > @@ -843,7 +843,7 @@ static int do_test_code_reading(bool try_kcore)
> > >  out_put:
> > >       thread__put(thread);
> > >  out_err:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > >       machine__delete(machine);
> > > diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
> > > index ae3b98bb42cf..94ab54ecd3f9 100644
> > > --- a/tools/perf/tests/event-times.c
> > > +++ b/tools/perf/tests/event-times.c
> > > @@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
> > >       err = attach(evlist);
> > >       if (err == TEST_SKIP) {
> > >               pr_debug("  SKIP  : not enough rights\n");
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               return err;
> > >       }
> > >
> > > @@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
> > >                count.ena, count.run);
> > >
> > >  out_err:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return !err ? TEST_OK : TEST_FAIL;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
> > > index cb9e6de2e033..8de66dac52b0 100644
> > > --- a/tools/perf/tests/event_update.c
> > > +++ b/tools/perf/tests/event_update.c
> > > @@ -115,7 +115,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
> > >       TEST_ASSERT_VAL("failed to synthesize attr update cpus",
> > >                       !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
> > >
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return 0;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
> > > index 1922cac13a24..6a220634c52f 100644
> > > --- a/tools/perf/tests/evsel-roundtrip-name.c
> > > +++ b/tools/perf/tests/evsel-roundtrip-name.c
> > > @@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> > >                               if (err) {
> > >                                       pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
> > >                                               name);
> > > -                                     evlist__delete(evlist);
> > > +                                     evlist__put(evlist);
> > >                                       continue;
> > >                               }
> > >                               evlist__for_each_entry(evlist, evsel) {
> > > @@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> > >                                               ret = TEST_FAIL;
> > >                                       }
> > >                               }
> > > -                             evlist__delete(evlist);
> > > +                             evlist__put(evlist);
> > >                       }
> > >               }
> > >       }
> > > @@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> > >               if (err) {
> > >                       pr_debug("failed to parse event '%s', err %d\n",
> > >                                names[i], err);
> > > -                     evlist__delete(evlist);
> > > +                     evlist__put(evlist);
> > >                       ret = TEST_FAIL;
> > >                       continue;
> > >               }
> > > @@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> > >                               ret = TEST_FAIL;
> > >                       }
> > >               }
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >       }
> > >       return ret;
> > >  }
> > > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > > index c7b32a220ca1..9060b085e3de 100644
> > > --- a/tools/perf/tests/expand-cgroup.c
> > > +++ b/tools/perf/tests/expand-cgroup.c
> > > @@ -104,7 +104,7 @@ static int expand_default_events(void)
> > >       TEST_ASSERT_VAL("failed to get evlist", evlist);
> > >
> > >       ret = test_expand_events(evlist);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > @@ -131,7 +131,7 @@ static int expand_group_events(void)
> > >       ret = test_expand_events(evlist);
> > >  out:
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > @@ -162,7 +162,7 @@ static int expand_libpfm_events(void)
> > >
> > >       ret = test_expand_events(evlist);
> > >  out:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > @@ -186,7 +186,7 @@ static int expand_metric_events(void)
> > >       ret = test_expand_events(evlist);
> > >
> > >  out:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
> > > index 3eb9ef8d7ec6..8f7cce7b5085 100644
> > > --- a/tools/perf/tests/hists_cumulate.c
> > > +++ b/tools/perf/tests/hists_cumulate.c
> > > @@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
> > >
> > >  out:
> > >       /* tear down everything */
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       machines__exit(&machines);
> > >       put_fake_samples();
> > >
> > > diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
> > > index 1cebd20cc91c..447fb2b5947c 100644
> > > --- a/tools/perf/tests/hists_filter.c
> > > +++ b/tools/perf/tests/hists_filter.c
> > > @@ -331,7 +331,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
> > >
> > >  out:
> > >       /* tear down everything */
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       reset_output_field();
> > >       machines__exit(&machines);
> > >       put_fake_samples();
> > > diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
> > > index 996f5f0b3bd1..9646c3b7b4de 100644
> > > --- a/tools/perf/tests/hists_link.c
> > > +++ b/tools/perf/tests/hists_link.c
> > > @@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
> > >
> > >  out:
> > >       /* tear down everything */
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       reset_output_field();
> > >       machines__exit(&machines);
> > >       put_fake_samples();
> > > diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
> > > index ee5ec8bda60e..aa8565fbaf90 100644
> > > --- a/tools/perf/tests/hists_output.c
> > > +++ b/tools/perf/tests/hists_output.c
> > > @@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
> > >
> > >  out:
> > >       /* tear down everything */
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       machines__exit(&machines);
> > >       put_fake_samples();
> > >
> > > diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
> > > index 97ea036ebae6..7d1040619575 100644
> > > --- a/tools/perf/tests/hwmon_pmu.c
> > > +++ b/tools/perf/tests/hwmon_pmu.c
> > > @@ -211,7 +211,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
> > >
> > >  out:
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
> > > index 729cc9cc1cb7..51cfd6522867 100644
> > > --- a/tools/perf/tests/keep-tracking.c
> > > +++ b/tools/perf/tests/keep-tracking.c
> > > @@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
> > >  out_err:
> > >       if (evlist) {
> > >               evlist__disable(evlist);
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >       }
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > > diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
> > > index a622bb8d4cc8..2591b6fbec3f 100644
> > > --- a/tools/perf/tests/mmap-basic.c
> > > +++ b/tools/perf/tests/mmap-basic.c
> > > @@ -93,7 +93,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >                               /* Permissions failure, flag the failure as a skip. */
> > >                               err = TEST_SKIP;
> > >                       }
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               evsels[i]->core.attr.wakeup_events = 1;
> > > @@ -105,7 +105,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >                       pr_debug("failed to open counter: %s, "
> > >                                "tweak /proc/sys/kernel/perf_event_paranoid?\n",
> > >                                str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               nr_events[i] = 0;
> > > @@ -115,7 +115,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >       if (evlist__mmap(evlist, 128) < 0) {
> > >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       for (i = 0; i < nsyscalls; ++i)
> > > @@ -133,7 +133,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >               if (event->header.type != PERF_RECORD_SAMPLE) {
> > >                       pr_debug("unexpected %s event\n",
> > >                                perf_event__name(event->header.type));
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               perf_sample__init(&sample, /*all=*/false);
> > > @@ -141,7 +141,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >               if (err) {
> > >                       pr_err("Can't parse sample, err = %d\n", err);
> > >                       perf_sample__exit(&sample);
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               err = -1;
> > > @@ -150,7 +150,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >               if (evsel == NULL) {
> > >                       pr_debug("event with id %" PRIu64
> > >                                " doesn't map to an evsel\n", sample.id);
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >               nr_events[evsel->core.idx]++;
> > >               perf_mmap__consume(&md->core);
> > > @@ -165,12 +165,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > >                                expected_nr_events[evsel->core.idx],
> > >                                evsel__name(evsel), nr_events[evsel->core.idx]);
> > >                       err = -1;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(evlist);
> > > +out_put_evlist:
> > > +     evlist__put(evlist);
> > >  out_free_cpus:
> > >       perf_cpu_map__put(cpus);
> > >  out_free_threads:
> > > diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
> > > index 2a139d2781a8..3ff595c7a86a 100644
> > > --- a/tools/perf/tests/openat-syscall-tp-fields.c
> > > +++ b/tools/perf/tests/openat-syscall-tp-fields.c
> > > @@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >       if (IS_ERR(evsel)) {
> > >               pr_debug("%s: evsel__newtp\n", __func__);
> > >               ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__add(evlist, evsel);
> > > @@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >       err = evlist__create_maps(evlist, &opts.target);
> > >       if (err < 0) {
> > >               pr_debug("%s: evlist__create_maps\n", __func__);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evsel__config(evsel, &opts, NULL);
> > > @@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >       if (err < 0) {
> > >               pr_debug("perf_evlist__open: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       err = evlist__mmap(evlist, UINT_MAX);
> > >       if (err < 0) {
> > >               pr_debug("evlist__mmap: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__enable(evlist);
> > > @@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >                               if (err) {
> > >                                       pr_debug("Can't parse sample, err = %d\n", err);
> > >                                       perf_sample__exit(&sample);
> > > -                                     goto out_delete_evlist;
> > > +                                     goto out_put_evlist;
> > >                               }
> > >
> > >                               tp_flags = evsel__intval(evsel, &sample, "flags");
> > > @@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >                               if (flags != tp_flags) {
> > >                                       pr_debug("%s: Expected flags=%#x, got %#x\n",
> > >                                                __func__, flags, tp_flags);
> > > -                                     goto out_delete_evlist;
> > > +                                     goto out_put_evlist;
> > >                               }
> > >
> > >                               goto out_ok;
> > > @@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > >
> > >               if (++nr_polls > 5) {
> > >                       pr_debug("%s: no events!\n", __func__);
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >       }
> > >  out_ok:
> > >       ret = TEST_OK;
> > > -out_delete_evlist:
> > > -     evlist__delete(evlist);
> > > +out_put_evlist:
> > > +     evlist__put(evlist);
> > >  out:
> > >       return ret;
> > >  }
> > > diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
> > > index e4cdb517c10e..0778462016f7 100644
> > > --- a/tools/perf/tests/parse-events.c
> > > +++ b/tools/perf/tests/parse-events.c
> > > @@ -2550,7 +2550,7 @@ static int test_event(const struct evlist_test *e)
> > >               ret = e->check(evlist);
> > >       }
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >
> > >       return ret;
> > >  }
> > > @@ -2576,7 +2576,7 @@ static int test_event_fake_pmu(const char *str)
> > >       }
> > >
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >
> > >       return ret;
> > >  }
> > > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > > index 66a5275917e2..b343628c7a7e 100644
> > > --- a/tools/perf/tests/parse-metric.c
> > > +++ b/tools/perf/tests/parse-metric.c
> > > @@ -83,7 +83,7 @@ static int __compute_metric(const char *name, struct value *vals,
> > >
> > >       cpus = perf_cpu_map__new("0");
> > >       if (!cpus) {
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               return -ENOMEM;
> > >       }
> > >
> > > @@ -112,7 +112,7 @@ static int __compute_metric(const char *name, struct value *vals,
> > >       /* ... cleanup. */
> > >       evlist__free_stats(evlist);
> > >       perf_cpu_map__put(cpus);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
> > > index 50e68b7d43aa..d5a8d065809e 100644
> > > --- a/tools/perf/tests/parse-no-sample-id-all.c
> > > +++ b/tools/perf/tests/parse-no-sample-id-all.c
> > > @@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
> > >       for (i = 0; i < count && !err; i++)
> > >               err = process_event(&evlist, events[i]);
> > >
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >
> > >       return err;
> > >  }
> > > diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> > > index efbd9cd60c63..babec674b83c 100644
> > > --- a/tools/perf/tests/perf-record.c
> > > +++ b/tools/perf/tests/perf-record.c
> > > @@ -102,7 +102,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >       err = evlist__create_maps(evlist, &opts.target);
> > >       if (err < 0) {
> > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       /*
> > > @@ -114,7 +114,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >       err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
> > >       if (err < 0) {
> > >               pr_debug("Couldn't run the workload!\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       /*
> > > @@ -131,7 +131,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >               pr_debug("sched__get_first_possible_cpu: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > >               evlist__cancel_workload(evlist);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       cpu = err;
> > > @@ -143,7 +143,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >               pr_debug("sched_setaffinity: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > >               evlist__cancel_workload(evlist);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       /*
> > > @@ -155,7 +155,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >               pr_debug("perf_evlist__open: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > >               evlist__cancel_workload(evlist);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       /*
> > > @@ -168,7 +168,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >               pr_debug("evlist__mmap: %s\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > >               evlist__cancel_workload(evlist);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       /*
> > > @@ -206,7 +206,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >                                       if (verbose > 0)
> > >                                               perf_event__fprintf(event, NULL, stderr);
> > >                                       pr_debug("Couldn't parse sample\n");
> > > -                                     goto out_delete_evlist;
> > > +                                     goto out_put_evlist;
> > >                               }
> > >
> > >                               if (verbose > 0) {
> > > @@ -346,9 +346,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > >               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
> > >               ++errs;
> > >       }
> > > -out_delete_evlist:
> > > +out_put_evlist:
> > >       CPU_FREE(cpu_mask);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >  out:
> > >       perf_sample__exit(&sample);
> > >       if (err == -EACCES)
> > > diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
> > > index cca41bd37ae3..d3538fa20af3 100644
> > > --- a/tools/perf/tests/perf-time-to-tsc.c
> > > +++ b/tools/perf/tests/perf-time-to-tsc.c
> > > @@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
> > >       err = TEST_OK;
> > >
> > >  out_err:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > >       return err;
> > > diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
> > > index 2e38dfa34b6c..099a50dec37e 100644
> > > --- a/tools/perf/tests/pfm.c
> > > +++ b/tools/perf/tests/pfm.c
> > > @@ -79,7 +79,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
> > >                               evlist__nr_groups(evlist),
> > >                               0);
> > >
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >       }
> > >       return 0;
> > >  }
> > > @@ -164,7 +164,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
> > >                               evlist__nr_groups(evlist),
> > >                               table[i].nr_groups);
> > >
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >       }
> > >       return 0;
> > >  }
> > > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > > index f40a828c9861..ab547f301c61 100644
> > > --- a/tools/perf/tests/pmu-events.c
> > > +++ b/tools/perf/tests/pmu-events.c
> > > @@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
> > >                            /*warn_if_reordered=*/true, /*fake_tp=*/false);
> > >       free(dup);
> > >
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > @@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> > >
> > >       cpus = perf_cpu_map__new("0");
> > >       if (!cpus) {
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               return -ENOMEM;
> > >       }
> > >
> > > @@ -901,7 +901,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> > >       /* ... cleanup. */
> > >       evlist__free_stats(evlist);
> > >       perf_cpu_map__put(cpus);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
> > > index cbded2c6faa4..bd3f4a2806ed 100644
> > > --- a/tools/perf/tests/pmu.c
> > > +++ b/tools/perf/tests/pmu.c
> > > @@ -249,7 +249,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
> > >       ret = TEST_OK;
> > >  err_out:
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       test_pmu_put(dir, pmu);
> > >       return ret;
> > >  }
> > > diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
> > > index 4a2ad7176fa0..f7f1f16638b4 100644
> > > --- a/tools/perf/tests/sw-clock.c
> > > +++ b/tools/perf/tests/sw-clock.c
> > > @@ -58,7 +58,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > >       evsel = evsel__new(&attr);
> > >       if (evsel == NULL) {
> > >               pr_debug("evsel__new\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >       evlist__add(evlist, evsel);
> > >
> > > @@ -67,7 +67,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > >       if (!cpus || !threads) {
> > >               err = -ENOMEM;
> > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > @@ -79,14 +79,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > >               pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)),
> > >                        knob, (u64)attr.sample_freq);
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       err = evlist__mmap(evlist, 128);
> > >       if (err < 0) {
> > >               pr_debug("failed to mmap event: %d (%s)\n", errno,
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__enable(evlist);
> > > @@ -112,7 +112,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > >               if (err < 0) {
> > >                       pr_debug("Error during parse sample\n");
> > >                       perf_sample__exit(&sample);
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               total_periods += sample.period;
> > > @@ -130,10 +130,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > >               err = -1;
> > >       }
> > >
> > > -out_delete_evlist:
> > > +out_put_evlist:
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
> > > index 15791fcb76b2..c3d5825df0a8 100644
> > > --- a/tools/perf/tests/switch-tracking.c
> > > +++ b/tools/perf/tests/switch-tracking.c
> > > @@ -577,7 +577,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
> > >  out:
> > >       if (evlist) {
> > >               evlist__disable(evlist);
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >       }
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > > diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
> > > index 4053ff2813bb..a46650b10689 100644
> > > --- a/tools/perf/tests/task-exit.c
> > > +++ b/tools/perf/tests/task-exit.c
> > > @@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > >       if (!cpus || !threads) {
> > >               err = -ENOMEM;
> > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > @@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > >       err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
> > >       if (err < 0) {
> > >               pr_debug("Couldn't run the workload!\n");
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evsel = evlist__first(evlist);
> > > @@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > >       if (err < 0) {
> > >               pr_debug("Couldn't open the evlist: %s\n",
> > >                        str_error_r(-err, sbuf, sizeof(sbuf)));
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       if (evlist__mmap(evlist, 128) < 0) {
> > >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > >               err = -1;
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >       }
> > >
> > >       evlist__start_workload(evlist);
> > > @@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > >               if (retry_count++ > 1000) {
> > >                       pr_debug("Failed after retrying 1000 times\n");
> > >                       err = -1;
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >               }
> > >
> > >               goto retry;
> > > @@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > >               err = -1;
> > >       }
> > >
> > > -out_delete_evlist:
> > > +out_put_evlist:
> > >       perf_cpu_map__put(cpus);
> > >       perf_thread_map__put(threads);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
> > > index 1e900ef92e37..e78ff9dcea97 100644
> > > --- a/tools/perf/tests/tool_pmu.c
> > > +++ b/tools/perf/tests/tool_pmu.c
> > > @@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
> > >
> > >  out:
> > >       parse_events_error__exit(&err);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
> > > index af4618c3124a..b88447899021 100644
> > > --- a/tools/perf/tests/topology.c
> > > +++ b/tools/perf/tests/topology.c
> > > @@ -55,7 +55,7 @@ static int session_write_header(char *path)
> > >                       !perf_session__write_header(session, session->evlist,
> > >                                                   perf_data__fd(&data), true));
> > >
> > > -     evlist__delete(session->evlist);
> > > +     evlist__put(session->evlist);
> > >       perf_session__delete(session);
> > >
> > >       return 0;
> > > diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
> > > index 25e2769b5e74..ed230cd44ba7 100644
> > > --- a/tools/perf/util/cgroup.c
> > > +++ b/tools/perf/util/cgroup.c
> > > @@ -503,8 +503,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
> > >       cgrp_event_expanded = true;
> > >
> > >  out_err:
> > > -     evlist__delete(orig_list);
> > > -     evlist__delete(tmp_list);
> > > +     evlist__put(orig_list);
> > > +     evlist__put(tmp_list);
> > >       metricgroup__rblist_exit(&orig_metric_events);
> > >       release_cgroup_list();
> > >
> > > diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
> > > index 3d2e437e1354..1166cdb00aca 100644
> > > --- a/tools/perf/util/data-convert-bt.c
> > > +++ b/tools/perf/util/data-convert-bt.c
> > > @@ -1331,7 +1331,7 @@ static void cleanup_events(struct perf_session *session)
> > >               zfree(&evsel->priv);
> > >       }
> > >
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       session->evlist = NULL;
> > >  }
> > >
> > > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > > index d99a3f12606f..ea1f398c14e3 100644
> > > --- a/tools/perf/util/evlist.c
> > > +++ b/tools/perf/util/evlist.c
> > > @@ -73,7 +73,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
> > >  #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
> > >  #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
> > >
> > > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > +static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > >                 struct perf_thread_map *threads)
> > >  {
> > >       perf_evlist__init(&evlist->core);
> > > @@ -85,6 +85,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > >       evlist->ctl_fd.pos = -1;
> > >       evlist->nr_br_cntr = -1;
> > >       metricgroup__rblist_init(&evlist->metric_events);
> > > +     refcount_set(&evlist->refcnt, 1);
> > >  }
> > >
> > >  struct evlist *evlist__new(void)
> > > @@ -116,7 +117,7 @@ struct evlist *evlist__new_default(void)
> > >                        can_profile_kernel ? "P" : "Pu");
> > >               err = parse_event(evlist, buf);
> > >               if (err) {
> > > -                     evlist__delete(evlist);
> > > +                     evlist__put(evlist);
> > >                       return NULL;
> > >               }
> > >       }
> > > @@ -136,13 +137,19 @@ struct evlist *evlist__new_dummy(void)
> > >       struct evlist *evlist = evlist__new();
> > >
> > >       if (evlist && evlist__add_dummy(evlist)) {
> > > -             evlist__delete(evlist);
> > > +             evlist__put(evlist);
> > >               evlist = NULL;
> > >       }
> > >
> > >       return evlist;
> > >  }
> > >
> > > +struct evlist *evlist__get(struct evlist *evlist)
> > > +{
> > > +     refcount_inc(&evlist->refcnt);
> > > +     return evlist;
> > > +}
> > > +
> > >  /**
> > >   * evlist__set_id_pos - set the positions of event ids.
> > >   * @evlist: selected event list
> > > @@ -181,7 +188,7 @@ static void evlist__purge(struct evlist *evlist)
> > >       evlist->core.nr_entries = 0;
> > >  }
> > >
> > > -void evlist__exit(struct evlist *evlist)
> > > +static void evlist__exit(struct evlist *evlist)
> > >  {
> > >       metricgroup__rblist_exit(&evlist->metric_events);
> > >       event_enable_timer__exit(&evlist->eet);
> > > @@ -190,11 +197,14 @@ void evlist__exit(struct evlist *evlist)
> > >       perf_evlist__exit(&evlist->core);
> > >  }
> > >
> > > -void evlist__delete(struct evlist *evlist)
> > > +void evlist__put(struct evlist *evlist)
> > >  {
> > >       if (evlist == NULL)
> > >               return;
> > >
> > > +     if (!refcount_dec_and_test(&evlist->refcnt))
> > > +             return;
> > > +
> > >       evlist__free_stats(evlist);
> > >       evlist__munmap(evlist);
> > >       evlist__close(evlist);
> > > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > > index 61acbb10d9a5..66fb5da08160 100644
> > > --- a/tools/perf/util/evlist.h
> > > +++ b/tools/perf/util/evlist.h
> > > @@ -59,6 +59,7 @@ struct event_enable_timer;
> > >
> > >  struct evlist {
> > >       struct perf_evlist core;
> > > +     refcount_t       refcnt;
> > >       bool             enabled;
> > >       int              id_pos;
> > >       int              is_pos;
> > > @@ -104,10 +105,8 @@ struct evsel_str_handler {
> > >  struct evlist *evlist__new(void);
> > >  struct evlist *evlist__new_default(void);
> > >  struct evlist *evlist__new_dummy(void);
> > > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > -               struct perf_thread_map *threads);
> > > -void evlist__exit(struct evlist *evlist);
> > > -void evlist__delete(struct evlist *evlist);
> > > +struct evlist *evlist__get(struct evlist *evlist);
> > > +void evlist__put(struct evlist *evlist);
> > >
> > >  void evlist__add(struct evlist *evlist, struct evsel *entry);
> > >  void evlist__remove(struct evlist *evlist, struct evsel *evsel);
> > > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > > index 7fda0ff89c16..4304b53b5a37 100644
> > > --- a/tools/perf/util/expr.c
> > > +++ b/tools/perf/util/expr.c
> > > @@ -451,7 +451,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
> > >               ret = parse_event(tmp, id) ? 0 : 1;
> > >       }
> > >  out:
> > > -     evlist__delete(tmp);
> > > +     evlist__put(tmp);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> > > index 4f2a6e10ed5c..e959ddb12dc8 100644
> > > --- a/tools/perf/util/header.c
> > > +++ b/tools/perf/util/header.c
> > > @@ -4307,12 +4307,12 @@ int perf_session__read_header(struct perf_session *session)
> > >               evsel = evsel__new(&f_attr.attr);
> > >
> > >               if (evsel == NULL)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >
> > >               evsel->needs_swap = header->needs_swap;
> > >               /*
> > >                * Do it before so that if perf_evsel__alloc_id fails, this
> > > -              * entry gets purged too at evlist__delete().
> > > +              * entry gets purged too at evlist__put().
> > >                */
> > >               evlist__add(session->evlist, evsel);
> > >
> > > @@ -4323,7 +4323,7 @@ int perf_session__read_header(struct perf_session *session)
> > >                * hattr->ids threads.
> > >                */
> > >               if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >
> > >               lseek(fd, f_attr.ids.offset, SEEK_SET);
> > >
> > > @@ -4342,7 +4342,7 @@ int perf_session__read_header(struct perf_session *session)
> > >                                     perf_file_section__process);
> > >
> > >       if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >  #else
> > >       perf_header__process_sections(header, fd, NULL, perf_file_section__process);
> > >  #endif
> > > @@ -4351,8 +4351,8 @@ int perf_session__read_header(struct perf_session *session)
> > >  out_errno:
> > >       return -errno;
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(session->evlist);
> > > +out_put_evlist:
> > > +     evlist__put(session->evlist);
> > >       session->evlist = NULL;
> > >       return -ENOMEM;
> > >  }
> > > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > > index 595b83142d2c..64c64dff7424 100644
> > > --- a/tools/perf/util/metricgroup.c
> > > +++ b/tools/perf/util/metricgroup.c
> > > @@ -212,7 +212,7 @@ static void metric__free(struct metric *m)
> > >       zfree(&m->metric_refs);
> > >       expr__ctx_free(m->pctx);
> > >       zfree(&m->modifier);
> > > -     evlist__delete(m->evlist);
> > > +     evlist__put(m->evlist);
> > >       free(m);
> > >  }
> > >
> > > @@ -1318,7 +1318,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
> > >       parsed_evlist = NULL;
> > >  err_out:
> > >       parse_events_error__exit(&parse_error);
> > > -     evlist__delete(parsed_evlist);
> > > +     evlist__put(parsed_evlist);
> > >       strbuf_release(&events);
> > >       return ret;
> > >  }
> > > @@ -1470,7 +1470,7 @@ static int parse_groups(struct evlist *perf_evlist,
> > >
> > >       if (combined_evlist) {
> > >               evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
> > > -             evlist__delete(combined_evlist);
> > > +             evlist__put(combined_evlist);
> > >       }
> > >
> > >       list_for_each_entry(m, &metric_list, nd) {
> > > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> > > index 0c0dc20b1c13..607ab7b82486 100644
> > > --- a/tools/perf/util/parse-events.c
> > > +++ b/tools/perf/util/parse-events.c
> > > @@ -2223,7 +2223,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
> > >
> > >       /*
> > >        * There are 2 users - builtin-record and builtin-test objects.
> > > -      * Both call evlist__delete in case of error, so we dont
> > > +      * Both call evlist__put in case of error, so we dont
> > >        * need to bother.
> > >        */
> > >       return ret;
> > > @@ -2424,7 +2424,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
> > >       }
> > >       ret = parse_events_option(opt, str, unset);
> > >       if (ret) {
> > > -             evlist__delete(*args->evlistp);
> > > +             evlist__put(*args->evlistp);
> > >               *args->evlistp = NULL;
> > >       }
> > >
> > > diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
> > > index 3345145a9307..8cd254d36220 100644
> > > --- a/tools/perf/util/perf_api_probe.c
> > > +++ b/tools/perf/util/perf_api_probe.c
> > > @@ -56,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
> > >       err = 0;
> > >
> > >  out_delete:
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >       return err;
> > >  }
> > >
> > > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> > > index dfc6e9299af9..4149a51e9878 100644
> > > --- a/tools/perf/util/python.c
> > > +++ b/tools/perf/util/python.c
> > > @@ -1273,7 +1273,7 @@ static int pyrf_evsel__setup_types(void)
> > >  struct pyrf_evlist {
> > >       PyObject_HEAD
> > >
> > > -     struct evlist evlist;
> > > +     struct evlist *evlist;
> > >  };
> > >
> > >  static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> > > @@ -1286,15 +1286,21 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> > >       if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
> > >               return -1;
> > >
> > > +     pevlist->evlist = evlist__new();
> > > +     if (!pevlist->evlist) {
> > > +             PyErr_NoMemory();
> > > +             return -1;
> > > +     }
> > >       threads = ((struct pyrf_thread_map *)pthreads)->threads;
> > >       cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
> > > -     evlist__init(&pevlist->evlist, cpus, threads);
> > > +     perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
> > > +
> > >       return 0;
> > >  }
> > >
> > >  static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
> > >  {
> > > -     evlist__exit(&pevlist->evlist);
> > > +     evlist__put(pevlist->evlist);
> > >       Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
> > >  }
> > >
> > > @@ -1303,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
> > >       struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
> > >
> > >       if (pcpu_map)
> > > -             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
> > > +             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
> > >
> > >       return (PyObject *)pcpu_map;
> > >  }
> > > @@ -1316,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
> > >       if (!list)
> > >               return NULL;
> > >
> > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
> > >            node = rb_next(node)) {
> > >               struct metric_event *me = container_of(node, struct metric_event, nd);
> > >               struct list_head *pos;
> > > @@ -1400,7 +1406,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> > >       if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
> > >               return NULL;
> > >
> > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
> > > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
> > >            mexp == NULL && node;
> > >            node = rb_next(node)) {
> > >               struct metric_event *me = container_of(node, struct metric_event, nd);
> > > @@ -1456,7 +1462,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> > >  static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> > >                                  PyObject *args, PyObject *kwargs)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >       static char *kwlist[] = { "pages", "overwrite", NULL };
> > >       int pages = 128, overwrite = false;
> > >
> > > @@ -1476,7 +1482,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> > >  static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
> > >                                  PyObject *args, PyObject *kwargs)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >       static char *kwlist[] = { "timeout", NULL };
> > >       int timeout = -1, n;
> > >
> > > @@ -1496,7 +1502,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
> > >                                        PyObject *args __maybe_unused,
> > >                                        PyObject *kwargs __maybe_unused)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >          PyObject *list = PyList_New(0);
> > >       int i;
> > >
> > > @@ -1525,7 +1531,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
> > >                                 PyObject *args,
> > >                                 PyObject *kwargs __maybe_unused)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >       PyObject *pevsel;
> > >       struct evsel *evsel;
> > >
> > > @@ -1557,7 +1563,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
> > >  static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> > >                                         PyObject *args, PyObject *kwargs)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >       union perf_event *event;
> > >       int sample_id_all = 1, cpu;
> > >       static char *kwlist[] = { "cpu", "sample_id_all", NULL };
> > > @@ -1614,7 +1620,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> > >  static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> > >                                  PyObject *args, PyObject *kwargs)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >
> > >       if (evlist__open(evlist) < 0) {
> > >               PyErr_SetFromErrno(PyExc_OSError);
> > > @@ -1627,7 +1633,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> > >
> > >  static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
> > >  {
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >
> > >       evlist__close(evlist);
> > >
> > > @@ -1653,7 +1659,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> > >               .no_buffering        = true,
> > >               .no_inherit          = true,
> > >       };
> > > -     struct evlist *evlist = &pevlist->evlist;
> > > +     struct evlist *evlist = pevlist->evlist;
> > >
> > >       evlist__config(evlist, &opts, &callchain_param);
> > >       Py_INCREF(Py_None);
> > > @@ -1662,14 +1668,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> > >
> > >  static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
> > >  {
> > > -     evlist__disable(&pevlist->evlist);
> > > +     evlist__disable(pevlist->evlist);
> > >       Py_INCREF(Py_None);
> > >       return Py_None;
> > >  }
> > >
> > >  static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
> > >  {
> > > -     evlist__enable(&pevlist->evlist);
> > > +     evlist__enable(pevlist->evlist);
> > >       Py_INCREF(Py_None);
> > >       return Py_None;
> > >  }
> > > @@ -1760,7 +1766,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
> > >  {
> > >       struct pyrf_evlist *pevlist = (void *)obj;
> > >
> > > -     return pevlist->evlist.core.nr_entries;
> > > +     return pevlist->evlist->core.nr_entries;
> > > +}
> > > +
> > > +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > > +{
> > > +     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > > +
> > > +     if (!pevsel)
> > > +             return NULL;
> > > +
> > > +     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > > +     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > > +
> > > +     evsel__clone(&pevsel->evsel, evsel);
> > > +     if (evsel__is_group_leader(evsel))
> > > +             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > > +     return (PyObject *)pevsel;
> > >  }
> > >
> > >  static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> > > @@ -1768,17 +1790,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> > >       struct pyrf_evlist *pevlist = (void *)obj;
> > >       struct evsel *pos;
> > >
> > > -     if (i >= pevlist->evlist.core.nr_entries) {
> > > +     if (i >= pevlist->evlist->core.nr_entries) {
> > >               PyErr_SetString(PyExc_IndexError, "Index out of range");
> > >               return NULL;
> > >       }
> > >
> > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > +     evlist__for_each_entry(pevlist->evlist, pos) {
> > >               if (i-- == 0)
> > >                       break;
> > >       }
> > > -
> > > -     return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
> > > +     return pyrf_evsel__from_evsel(pos);
> > >  }
> > >
> > >  static PyObject *pyrf_evlist__str(PyObject *self)
> > > @@ -1790,7 +1811,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
> > >       PyObject *result;
> > >
> > >       strbuf_addstr(&sb, "evlist([");
> > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > +     evlist__for_each_entry(pevlist->evlist, pos) {
> > >               if (!first)
> > >                       strbuf_addch(&sb, ',');
> > >               if (!pos->pmu)
> > > @@ -1931,110 +1952,30 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
> > >       return PyLong_FromLong(tp_pmu__id(sys, name));
> > >  }
> > >
> > > -static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > > -{
> > > -     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > > -
> > > -     if (!pevsel)
> > > -             return NULL;
> > > -
> > > -     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > > -     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > > -
> > > -     evsel__clone(&pevsel->evsel, evsel);
> > > -     if (evsel__is_group_leader(evsel))
> > > -             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > > -     return (PyObject *)pevsel;
> > > -}
> > > -
> > > -static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
> > > -{
> > > -     struct evsel *pos;
> > > -     int idx = 0;
> > > -
> > > -     evlist__for_each_entry(evlist, pos) {
> > > -             if (evsel == pos)
> > > -                     return idx;
> > > -             idx++;
> > > -     }
> > > -     return -1;
> > > -}
> > > -
> > > -static struct evsel *evlist__at(struct evlist *evlist, int idx)
> > > -{
> > > -     struct evsel *pos;
> > > -     int idx2 = 0;
> > > -
> > > -     evlist__for_each_entry(evlist, pos) {
> > > -             if (idx == idx2)
> > > -                     return pos;
> > > -             idx2++;
> > > -     }
> > > -     return NULL;
> > > -}
> > > -
> > >  static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
> > >  {
> > >       struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
> > > -     struct evsel *pos;
> > > -     struct rb_node *node;
> > >
> > >       if (!pevlist)
> > >               return NULL;
> > >
> > > -     memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
> > > -     evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
> > > -     evlist__for_each_entry(evlist, pos) {
> > > -             struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
> > > -
> > > -             evlist__add(&pevlist->evlist, &pevsel->evsel);
> > > -     }
> > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > -             struct evsel *leader = evsel__leader(pos);
> > > -
> > > -             if (pos != leader) {
> > > -                     int idx = evlist__pos(evlist, leader);
> > > -
> > > -                     if (idx >= 0)
> > > -                             evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
> > > -                     else if (leader == NULL)
> > > -                             evsel__set_leader(pos, pos);
> > > -             }
> > > -     }
> > > -     metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
> > > -                                     &pevlist->evlist.metric_events,
> > > -                                     &evlist->metric_events);
> > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > > -          node = rb_next(node)) {
> > > -             struct metric_event *me = container_of(node, struct metric_event, nd);
> > > -             struct list_head *mpos;
> > > -             int idx = evlist__pos(evlist, me->evsel);
> > > -
> > > -             if (idx >= 0)
> > > -                     me->evsel = evlist__at(&pevlist->evlist, idx);
> > > -             list_for_each(mpos, &me->head) {
> > > -                     struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
> > > -
> > > -                     for (int j = 0; e->metric_events[j]; j++) {
> > > -                             idx = evlist__pos(evlist, e->metric_events[j]);
> > > -                             if (idx >= 0)
> > > -                                     e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
> > > -                     }
> > > -             }
> > > -     }
> > > +     pevlist->evlist = evlist__get(evlist);
> > >       return (PyObject *)pevlist;
> > >  }
> > >
> > >  static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> > >  {
> > >       const char *input;
> > > -     struct evlist evlist = {};
> > > +     struct evlist *evlist = evlist__new();
> > >       struct parse_events_error err;
> > >       PyObject *result;
> > >       PyObject *pcpus = NULL, *pthreads = NULL;
> > >       struct perf_cpu_map *cpus;
> > >       struct perf_thread_map *threads;
> > >
> > > +     if (!evlist)
> > > +             return PyErr_NoMemory();
> > > +
> > >       if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
> > >               return NULL;
> > >
> > > @@ -2042,35 +1983,38 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> > >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> > >
> > >       parse_events_error__init(&err);
> > > -     evlist__init(&evlist, cpus, threads);
> > > -     if (parse_events(&evlist, input, &err)) {
> > > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > +     if (parse_events(evlist, input, &err)) {
> > >               parse_events_error__print(&err, input);
> > >               PyErr_SetFromErrno(PyExc_OSError);
> > >               return NULL;
> > >       }
> > > -     result = pyrf_evlist__from_evlist(&evlist);
> > > -     evlist__exit(&evlist);
> > > +     result = pyrf_evlist__from_evlist(evlist);
> > > +     evlist__put(evlist);
> > >       return result;
> > >  }
> > >
> > >  static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> > >  {
> > >       const char *input, *pmu = NULL;
> > > -     struct evlist evlist = {};
> > > +     struct evlist *evlist = evlist__new();
> > >       PyObject *result;
> > >       PyObject *pcpus = NULL, *pthreads = NULL;
> > >       struct perf_cpu_map *cpus;
> > >       struct perf_thread_map *threads;
> > >       int ret;
> > >
> > > +     if (!evlist)
> > > +             return PyErr_NoMemory();
> > > +
> > >       if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
> > >               return NULL;
> > >
> > >       threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
> > >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> > >
> > > -     evlist__init(&evlist, cpus, threads);
> > > -     ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
> > > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > +     ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
> > >                                       /*metric_no_group=*/ false,
> > >                                       /*metric_no_merge=*/ false,
> > >                                       /*metric_no_threshold=*/ true,
> > > @@ -2082,8 +2026,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> > >               PyErr_SetFromErrno(PyExc_OSError);
> > >               return NULL;
> > >       }
> > > -     result = pyrf_evlist__from_evlist(&evlist);
> > > -     evlist__exit(&evlist);
> > > +     result = pyrf_evlist__from_evlist(evlist);
> > > +     evlist__put(evlist);
> > >       return result;
> > >  }
> > >
> > > diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
> > > index e867de8ddaaa..8a5fc7d5e43c 100644
> > > --- a/tools/perf/util/record.c
> > > +++ b/tools/perf/util/record.c
> > > @@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
> > >       ret = true;
> > >
> > >  out_delete:
> > > -     evlist__delete(temp_evlist);
> > > +     evlist__put(temp_evlist);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> > > index 081e68c72c30..f241d91221d7 100644
> > > --- a/tools/perf/util/session.c
> > > +++ b/tools/perf/util/session.c
> > > @@ -256,7 +256,7 @@ void perf_session__delete(struct perf_session *session)
> > >       machines__exit(&session->machines);
> > >       if (session->data) {
> > >               if (perf_data__is_read(session->data))
> > > -                     evlist__delete(session->evlist);
> > > +                     evlist__put(session->evlist);
> > >               perf_data__close(session->data);
> > >       }
> > >  #ifdef HAVE_LIBTRACEEVENT
> > > diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
> > > index 388846f17bc1..b84a5463e039 100644
> > > --- a/tools/perf/util/sideband_evlist.c
> > > +++ b/tools/perf/util/sideband_evlist.c
> > > @@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> > >               return 0;
> > >
> > >       if (evlist__create_maps(evlist, target))
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       if (evlist->core.nr_entries > 1) {
> > >               bool can_sample_identifier = perf_can_sample_identifier();
> > > @@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> > >       evlist__for_each_entry(evlist, counter) {
> > >               if (evsel__open(counter, evlist->core.user_requested_cpus,
> > >                               evlist->core.threads) < 0)
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >
> > >       if (evlist__mmap(evlist, UINT_MAX))
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       evlist__for_each_entry(evlist, counter) {
> > >               if (evsel__enable(counter))
> > > -                     goto out_delete_evlist;
> > > +                     goto out_put_evlist;
> > >       }
> > >
> > >       evlist->thread.done = 0;
> > >       if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
> > > -             goto out_delete_evlist;
> > > +             goto out_put_evlist;
> > >
> > >       return 0;
> > >
> > > -out_delete_evlist:
> > > -     evlist__delete(evlist);
> > > +out_put_evlist:
> > > +     evlist__put(evlist);
> > >       evlist = NULL;
> > >       return -1;
> > >  }
> > > @@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
> > >               return;
> > >       evlist->thread.done = 1;
> > >       pthread_join(evlist->thread.th, NULL);
> > > -     evlist__delete(evlist);
> > > +     evlist__put(evlist);
> > >  }
> > > --
> > > 2.51.1.851.g4ebd6896fd-goog

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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29 18:33       ` Arnaldo Carvalho de Melo
@ 2025-10-29 21:12         ` Ian Rogers
  2025-10-30 13:09           ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 22+ messages in thread
From: Ian Rogers @ 2025-10-29 21:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Wed, Oct 29, 2025 at 11:33 AM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Wed, Oct 29, 2025 at 09:56:50AM -0700, Ian Rogers wrote:
> > On Wed, Oct 29, 2025 at 9:22 AM Arnaldo Carvalho de Melo
> > <acme@kernel.org> wrote:
> > >
> > > On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> > > > This a no-op for most of the perf tool. The reference count is set to
> > > > 1 at allocation, the put will see the 1, decrement it and perform the
> > > > delete. The purpose for adding the reference count is for the python
> > > > code. Prior to this change the python code would clone evlists, but
> > > > this has issues if events are opened, etc. This change adds a
> > > > reference count for the evlists and a later change will add it to
> > > > evsels. The combination is needed for the python code to operate
> > > > correctly (not hit asserts in the evsel clone), but the changes are
> > > > broken apart for the sake of smaller patches.
> > >
> > > Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
> > > are not using the RC_CHK_ACCESS stuff from the get go, why not?
> >
> > So if I did RC_CHK_ACCESS then every evsel access would need updating,
>
> Fair enough, I think it would be informative to have a comment
> mentioning this near the refcount_t to avoid this question popping up
> again.

Sgtm. I think we can also add the RC_CHK_ACCESS to evlist as that is a
boring blob of a thing to pass around.

How are things outside of this? The python changes, how to do the
process_events callbacks, etc. Any thoughts on the tool API vs the
script API (stat vs stat_round) ?

Thanks,
Ian

> - Arnaldo
>
> > accessor functions, and a lot of lines of code. As the reference count
> > checking doesn't work with invasive lists, you need to interpose prev
> > and next, I think we'd need to specially handle the case probably with
> > an extra variable in evsel for reference count checking like:
> > ```
> > RC_STRUCT(evsel) {
> > ...
> >    struct evsel *evlist_ptr;
> > ...
> > }
> > ```
> > and things like evlist__for_each_entry need changes like:
> > ```
> > #define evlist__for_each_entry(evlist, evsel) \
> >        __evlist__for_each_entry(&(evlist)->core.entries, orig_evsel) {
> >            evsel = orig_evsel->evlist_ptr
> > ```
> > but it may be simpler to change evlist to use an array of evsel* as
> > was done in places like `struct maps`.
> >
> > Anyway, those changes I think would have taken away from what the
> > series was trying to do and so weren't done here.
> >
> > Thanks,
> > Ian
> >
> > > All the prep patches looks ok, assuming they build in succession.
> > >
> > > - Arnaldo
> > >
> > > > Signed-off-by: Ian Rogers <irogers@google.com>
> > > > ---
> > > >  tools/perf/arch/x86/tests/hybrid.c          |   2 +-
> > > >  tools/perf/arch/x86/tests/topdown.c         |   2 +-
> > > >  tools/perf/arch/x86/util/iostat.c           |   2 +-
> > > >  tools/perf/bench/evlist-open-close.c        |  18 +-
> > > >  tools/perf/builtin-ftrace.c                 |   8 +-
> > > >  tools/perf/builtin-kvm.c                    |   4 +-
> > > >  tools/perf/builtin-lock.c                   |   2 +-
> > > >  tools/perf/builtin-record.c                 |   4 +-
> > > >  tools/perf/builtin-stat.c                   |   8 +-
> > > >  tools/perf/builtin-top.c                    |  52 +++---
> > > >  tools/perf/builtin-trace.c                  |  26 +--
> > > >  tools/perf/tests/backward-ring-buffer.c     |  18 +-
> > > >  tools/perf/tests/code-reading.c             |   4 +-
> > > >  tools/perf/tests/event-times.c              |   4 +-
> > > >  tools/perf/tests/event_update.c             |   2 +-
> > > >  tools/perf/tests/evsel-roundtrip-name.c     |   8 +-
> > > >  tools/perf/tests/expand-cgroup.c            |   8 +-
> > > >  tools/perf/tests/hists_cumulate.c           |   2 +-
> > > >  tools/perf/tests/hists_filter.c             |   2 +-
> > > >  tools/perf/tests/hists_link.c               |   2 +-
> > > >  tools/perf/tests/hists_output.c             |   2 +-
> > > >  tools/perf/tests/hwmon_pmu.c                |   2 +-
> > > >  tools/perf/tests/keep-tracking.c            |   2 +-
> > > >  tools/perf/tests/mmap-basic.c               |  18 +-
> > > >  tools/perf/tests/openat-syscall-tp-fields.c |  18 +-
> > > >  tools/perf/tests/parse-events.c             |   4 +-
> > > >  tools/perf/tests/parse-metric.c             |   4 +-
> > > >  tools/perf/tests/parse-no-sample-id-all.c   |   2 +-
> > > >  tools/perf/tests/perf-record.c              |  18 +-
> > > >  tools/perf/tests/perf-time-to-tsc.c         |   2 +-
> > > >  tools/perf/tests/pfm.c                      |   4 +-
> > > >  tools/perf/tests/pmu-events.c               |   6 +-
> > > >  tools/perf/tests/pmu.c                      |   2 +-
> > > >  tools/perf/tests/sw-clock.c                 |  14 +-
> > > >  tools/perf/tests/switch-tracking.c          |   2 +-
> > > >  tools/perf/tests/task-exit.c                |  14 +-
> > > >  tools/perf/tests/tool_pmu.c                 |   2 +-
> > > >  tools/perf/tests/topology.c                 |   2 +-
> > > >  tools/perf/util/cgroup.c                    |   4 +-
> > > >  tools/perf/util/data-convert-bt.c           |   2 +-
> > > >  tools/perf/util/evlist.c                    |  20 ++-
> > > >  tools/perf/util/evlist.h                    |   7 +-
> > > >  tools/perf/util/expr.c                      |   2 +-
> > > >  tools/perf/util/header.c                    |  12 +-
> > > >  tools/perf/util/metricgroup.c               |   6 +-
> > > >  tools/perf/util/parse-events.c              |   4 +-
> > > >  tools/perf/util/perf_api_probe.c            |   2 +-
> > > >  tools/perf/util/python.c                    | 176 +++++++-------------
> > > >  tools/perf/util/record.c                    |   2 +-
> > > >  tools/perf/util/session.c                   |   2 +-
> > > >  tools/perf/util/sideband_evlist.c           |  16 +-
> > > >  51 files changed, 252 insertions(+), 299 deletions(-)
> > > >
> > > > diff --git a/tools/perf/arch/x86/tests/hybrid.c b/tools/perf/arch/x86/tests/hybrid.c
> > > > index e221ea104174..dfb0ffc0d030 100644
> > > > --- a/tools/perf/arch/x86/tests/hybrid.c
> > > > +++ b/tools/perf/arch/x86/tests/hybrid.c
> > > > @@ -268,7 +268,7 @@ static int test_event(const struct evlist_test *e)
> > > >               ret = e->check(evlist);
> > > >       }
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >
> > > >       return ret;
> > > >  }
> > > > diff --git a/tools/perf/arch/x86/tests/topdown.c b/tools/perf/arch/x86/tests/topdown.c
> > > > index 1eba3b4594ef..b31aef4ef28b 100644
> > > > --- a/tools/perf/arch/x86/tests/topdown.c
> > > > +++ b/tools/perf/arch/x86/tests/topdown.c
> > > > @@ -55,7 +55,7 @@ static int event_cb(void *state, struct pmu_event_info *info)
> > > >                       *ret = TEST_FAIL;
> > > >               }
> > > >       }
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return 0;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c
> > > > index 7442a2cd87ed..e0417552b0cb 100644
> > > > --- a/tools/perf/arch/x86/util/iostat.c
> > > > +++ b/tools/perf/arch/x86/util/iostat.c
> > > > @@ -337,7 +337,7 @@ int iostat_prepare(struct evlist *evlist, struct perf_stat_config *config)
> > > >       if (evlist->core.nr_entries > 0) {
> > > >               pr_warning("The -e and -M options are not supported."
> > > >                          "All chosen events/metrics will be dropped\n");
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               evlist = evlist__new();
> > > >               if (!evlist)
> > > >                       return -ENOMEM;
> > > > diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c
> > > > index bfaf50e4e519..a802fb005ee3 100644
> > > > --- a/tools/perf/bench/evlist-open-close.c
> > > > +++ b/tools/perf/bench/evlist-open-close.c
> > > > @@ -75,7 +75,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> > > >               parse_events_error__exit(&err);
> > > >               pr_err("Run 'perf list' for a list of valid events\n");
> > > >               ret = 1;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >       parse_events_error__exit(&err);
> > > >       if (uid_str) {
> > > > @@ -84,24 +84,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
> > > >               if (uid == UINT_MAX) {
> > > >                       pr_err("Invalid User: %s", uid_str);
> > > >                       ret = -EINVAL;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >               ret = parse_uid_filter(evlist, uid);
> > > >               if (ret)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >       ret = evlist__create_maps(evlist, &opts.target);
> > > >       if (ret < 0) {
> > > >               pr_err("Not enough memory to create thread/cpu maps\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__config(evlist, &opts, NULL);
> > > >
> > > >       return evlist;
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(evlist);
> > > >       return NULL;
> > > >  }
> > > >
> > > > @@ -150,7 +150,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > > >               evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
> > > >       printf("  Number of iterations:\t%d\n", iterations);
> > > >
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >
> > > >       for (i = 0; i < iterations; i++) {
> > > >               pr_debug("Started iteration %d\n", i);
> > > > @@ -161,7 +161,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > > >               gettimeofday(&start, NULL);
> > > >               err = bench__do_evlist_open_close(evlist);
> > > >               if (err) {
> > > > -                     evlist__delete(evlist);
> > > > +                     evlist__put(evlist);
> > > >                       return err;
> > > >               }
> > > >
> > > > @@ -170,7 +170,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
> > > >               runtime_us = timeval2usec(&diff);
> > > >               update_stats(&time_stats, runtime_us);
> > > >
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
> > > >       }
> > > >
> > > > diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
> > > > index 6b6eec65f93f..4a2fe05e9786 100644
> > > > --- a/tools/perf/builtin-ftrace.c
> > > > +++ b/tools/perf/builtin-ftrace.c
> > > > @@ -1993,20 +1993,20 @@ int cmd_ftrace(int argc, const char **argv)
> > > >
> > > >       ret = evlist__create_maps(ftrace.evlist, &ftrace.target);
> > > >       if (ret < 0)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if (argc) {
> > > >               ret = evlist__prepare_workload(ftrace.evlist, &ftrace.target,
> > > >                                              argv, false,
> > > >                                              ftrace__workload_exec_failed_signal);
> > > >               if (ret < 0)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >
> > > >       ret = cmd_func(&ftrace);
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(ftrace.evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(ftrace.evlist);
> > > >
> > > >  out_delete_filters:
> > > >       delete_filter_func(&ftrace.filters);
> > > > diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> > > > index f0f285763f19..b07cbe051e33 100644
> > > > --- a/tools/perf/builtin-kvm.c
> > > > +++ b/tools/perf/builtin-kvm.c
> > > > @@ -1806,7 +1806,7 @@ static struct evlist *kvm_live_event_list(void)
> > > >
> > > >  out:
> > > >       if (err) {
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               evlist = NULL;
> > > >       }
> > > >
> > > > @@ -1937,7 +1937,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
> > > >  out:
> > > >       perf_session__delete(kvm->session);
> > > >       kvm->session = NULL;
> > > > -     evlist__delete(kvm->evlist);
> > > > +     evlist__put(kvm->evlist);
> > > >
> > > >       return err;
> > > >  }
> > > > diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
> > > > index 078634461df2..2a57767f03a9 100644
> > > > --- a/tools/perf/builtin-lock.c
> > > > +++ b/tools/perf/builtin-lock.c
> > > > @@ -2143,7 +2143,7 @@ static int __cmd_contention(int argc, const char **argv)
> > > >
> > > >  out_delete:
> > > >       lock_filter_finish();
> > > > -     evlist__delete(con.evlist);
> > > > +     evlist__put(con.evlist);
> > > >       lock_contention_finish(&con);
> > > >       perf_session__delete(session);
> > > >       perf_env__exit(&host_env);
> > > > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> > > > index 3d8cf4090a92..738dbae80eac 100644
> > > > --- a/tools/perf/builtin-record.c
> > > > +++ b/tools/perf/builtin-record.c
> > > > @@ -4349,7 +4349,7 @@ int cmd_record(int argc, const char **argv)
> > > >                       goto out;
> > > >
> > > >               evlist__splice_list_tail(rec->evlist, &def_evlist->core.entries);
> > > > -             evlist__delete(def_evlist);
> > > > +             evlist__put(def_evlist);
> > > >       }
> > > >
> > > >       if (rec->opts.target.tid && !rec->opts.no_inherit_set)
> > > > @@ -4460,7 +4460,7 @@ int cmd_record(int argc, const char **argv)
> > > >       auxtrace_record__free(rec->itr);
> > > >  out_opts:
> > > >       evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.ctl_fd_close);
> > > > -     evlist__delete(rec->evlist);
> > > > +     evlist__put(rec->evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> > > > index 886727ae8529..282926c6abd4 100644
> > > > --- a/tools/perf/builtin-stat.c
> > > > +++ b/tools/perf/builtin-stat.c
> > > > @@ -2067,7 +2067,7 @@ static int add_default_events(void)
> > > >                       metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
> > > >                                                       &evlist->metric_events,
> > > >                                                       &metric_evlist->metric_events);
> > > > -                     evlist__delete(metric_evlist);
> > > > +                     evlist__put(metric_evlist);
> > > >               }
> > > >       }
> > > >
> > > > @@ -2142,7 +2142,7 @@ static int add_default_events(void)
> > > >       metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
> > > >                                       &evsel_list->metric_events,
> > > >                                       &evlist->metric_events);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > @@ -2373,7 +2373,7 @@ static int __cmd_report(int argc, const char **argv)
> > > >
> > > >       perf_stat.session  = session;
> > > >       stat_config.output = stderr;
> > > > -     evlist__delete(evsel_list);
> > > > +     evlist__put(evsel_list);
> > > >       evsel_list         = session->evlist;
> > > >
> > > >       ret = perf_session__process_events(session);
> > > > @@ -3042,7 +3042,7 @@ int cmd_stat(int argc, const char **argv)
> > > >       if (smi_cost && smi_reset)
> > > >               sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
> > > >
> > > > -     evlist__delete(evsel_list);
> > > > +     evlist__put(evsel_list);
> > > >
> > > >       evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
> > > >
> > > > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> > > > index 710604c4f6f6..45d5dae54dcd 100644
> > > > --- a/tools/perf/builtin-top.c
> > > > +++ b/tools/perf/builtin-top.c
> > > > @@ -1641,14 +1641,14 @@ int cmd_top(int argc, const char **argv)
> > > >       perf_env__init(&host_env);
> > > >       status = perf_config(perf_top_config, &top);
> > > >       if (status)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       /*
> > > >        * Since the per arch annotation init routine may need the cpuid, read
> > > >        * it here, since we are not getting this from the perf.data header.
> > > >        */
> > > >       status = perf_env__set_cmdline(&host_env, argc, argv);
> > > >       if (status)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       status = perf_env__read_cpuid(&host_env);
> > > >       if (status) {
> > > > @@ -1669,44 +1669,44 @@ int cmd_top(int argc, const char **argv)
> > > >               annotate_opts.disassembler_style = strdup(disassembler_style);
> > > >               if (!annotate_opts.disassembler_style) {
> > > >                       status = -ENOMEM;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >       if (objdump_path) {
> > > >               annotate_opts.objdump_path = strdup(objdump_path);
> > > >               if (!annotate_opts.objdump_path) {
> > > >                       status = -ENOMEM;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >       if (addr2line_path) {
> > > >               symbol_conf.addr2line_path = strdup(addr2line_path);
> > > >               if (!symbol_conf.addr2line_path) {
> > > >                       status = -ENOMEM;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >
> > > >       status = symbol__validate_sym_arguments();
> > > >       if (status)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if (annotate_check_args() < 0)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if (!top.evlist->core.nr_entries) {
> > > >               struct evlist *def_evlist = evlist__new_default();
> > > >
> > > >               if (!def_evlist)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >
> > > >               evlist__splice_list_tail(top.evlist, &def_evlist->core.entries);
> > > > -             evlist__delete(def_evlist);
> > > > +             evlist__put(def_evlist);
> > > >       }
> > > >
> > > >       status = evswitch__init(&top.evswitch, top.evlist, stderr);
> > > >       if (status)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if (symbol_conf.report_hierarchy) {
> > > >               /* disable incompatible options */
> > > > @@ -1717,18 +1717,18 @@ int cmd_top(int argc, const char **argv)
> > > >                       pr_err("Error: --hierarchy and --fields options cannot be used together\n");
> > > >                       parse_options_usage(top_usage, options, "fields", 0);
> > > >                       parse_options_usage(NULL, options, "hierarchy", 0);
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >
> > > >       if (top.stitch_lbr && !(callchain_param.record_mode == CALLCHAIN_LBR)) {
> > > >               pr_err("Error: --stitch-lbr must be used with --call-graph lbr\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (nr_cgroups > 0 && opts->record_cgroup) {
> > > >               pr_err("--cgroup and --all-cgroups cannot be used together\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (branch_call_mode) {
> > > > @@ -1752,7 +1752,7 @@ int cmd_top(int argc, const char **argv)
> > > >               status = perf_env__read_core_pmu_caps(&host_env);
> > > >               if (status) {
> > > >                       pr_err("PMU capability data is not available\n");
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >
> > > > @@ -1775,7 +1775,7 @@ int cmd_top(int argc, const char **argv)
> > > >       if (IS_ERR(top.session)) {
> > > >               status = PTR_ERR(top.session);
> > > >               top.session = NULL;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >       top.evlist->session = top.session;
> > > >
> > > > @@ -1785,7 +1785,7 @@ int cmd_top(int argc, const char **argv)
> > > >               if (field_order)
> > > >                       parse_options_usage(sort_order ? NULL : top_usage,
> > > >                                           options, "fields", 0);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       status = target__validate(target);
> > > > @@ -1800,11 +1800,11 @@ int cmd_top(int argc, const char **argv)
> > > >               if (uid == UINT_MAX) {
> > > >                       ui__error("Invalid User: %s", top.uid_str);
> > > >                       status = -EINVAL;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >               status = parse_uid_filter(top.evlist, uid);
> > > >               if (status)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (target__none(target))
> > > > @@ -1814,7 +1814,7 @@ int cmd_top(int argc, const char **argv)
> > > >               ui__error("Couldn't create thread/CPU maps: %s\n",
> > > >                         errno == ENOENT ? "No such process" : str_error_r(errno, errbuf, sizeof(errbuf)));
> > > >               status = -errno;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (top.delay_secs < 1)
> > > > @@ -1822,7 +1822,7 @@ int cmd_top(int argc, const char **argv)
> > > >
> > > >       if (record_opts__config(opts)) {
> > > >               status = -EINVAL;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       top.sym_evsel = evlist__first(top.evlist);
> > > > @@ -1837,14 +1837,14 @@ int cmd_top(int argc, const char **argv)
> > > >
> > > >       status = symbol__annotation_init();
> > > >       if (status < 0)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       annotation_config__init();
> > > >
> > > >       symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
> > > >       status = symbol__init(NULL);
> > > >       if (status < 0)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       sort__setup_elide(stdout);
> > > >
> > > > @@ -1864,13 +1864,13 @@ int cmd_top(int argc, const char **argv)
> > > >               if (top.sb_evlist == NULL) {
> > > >                       pr_err("Couldn't create side band evlist.\n.");
> > > >                       status = -EINVAL;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               if (evlist__add_bpf_sb_event(top.sb_evlist, &host_env)) {
> > > >                       pr_err("Couldn't ask for PERF_RECORD_BPF_EVENT side band events.\n.");
> > > >                       status = -EINVAL;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >  #endif
> > > > @@ -1885,8 +1885,8 @@ int cmd_top(int argc, const char **argv)
> > > >       if (!opts->no_bpf_event)
> > > >               evlist__stop_sb_thread(top.sb_evlist);
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(top.evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(top.evlist);
> > > >       perf_session__delete(top.session);
> > > >       annotation_options__exit();
> > > >       perf_env__exit(&host_env);
> > > > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > > > index a743bda294bd..c056df42a78f 100644
> > > > --- a/tools/perf/builtin-trace.c
> > > > +++ b/tools/perf/builtin-trace.c
> > > > @@ -4364,7 +4364,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >
> > > >       if (trace->summary_bpf) {
> > > >               if (trace_prepare_bpf_summary(trace->summary_mode) < 0)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >
> > > >               if (trace->summary_only)
> > > >                       goto create_maps;
> > > > @@ -4432,19 +4432,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >       err = evlist__create_maps(evlist, &trace->opts.target);
> > > >       if (err < 0) {
> > > >               fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       err = trace__symbols_init(trace, argc, argv, evlist);
> > > >       if (err < 0) {
> > > >               fprintf(trace->output, "Problems initializing symbol libraries!\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) {
> > > >               trace->syscall_stats = alloc_syscall_stats();
> > > >               if (IS_ERR(trace->syscall_stats))
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__config(evlist, &trace->opts, &callchain_param);
> > > > @@ -4453,7 +4453,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >               err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL);
> > > >               if (err < 0) {
> > > >                       fprintf(trace->output, "Couldn't run the workload!\n");
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >               workload_pid = evlist->workload.pid;
> > > >       }
> > > > @@ -4501,7 +4501,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >
> > > >       err = trace__expand_filters(trace, &evsel);
> > > >       if (err)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       err = evlist__apply_filters(evlist, &evsel, &trace->opts.target);
> > > >       if (err < 0)
> > > >               goto out_error_apply_filters;
> > > > @@ -4618,12 +4618,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >               }
> > > >       }
> > > >
> > > > -out_delete_evlist:
> > > > +out_put_evlist:
> > > >       trace_cleanup_bpf_summary();
> > > >       delete_syscall_stats(trace->syscall_stats);
> > > >       trace__symbols__exit(trace);
> > > >       evlist__free_syscall_tp_fields(evlist);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       cgroup__put(trace->cgroup);
> > > >       trace->evlist = NULL;
> > > >       trace->live = false;
> > > > @@ -4648,22 +4648,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > > >
> > > >  out_error:
> > > >       fprintf(trace->output, "%s\n", errbuf);
> > > > -     goto out_delete_evlist;
> > > > +     goto out_put_evlist;
> > > >
> > > >  out_error_apply_filters:
> > > >       fprintf(trace->output,
> > > >               "Failed to set filter \"%s\" on event %s with %d (%s)\n",
> > > >               evsel->filter, evsel__name(evsel), errno,
> > > >               str_error_r(errno, errbuf, sizeof(errbuf)));
> > > > -     goto out_delete_evlist;
> > > > +     goto out_put_evlist;
> > > >  }
> > > >  out_error_mem:
> > > >       fprintf(trace->output, "Not enough memory to run!\n");
> > > > -     goto out_delete_evlist;
> > > > +     goto out_put_evlist;
> > > >
> > > >  out_errno:
> > > >       fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
> > > > -     goto out_delete_evlist;
> > > > +     goto out_put_evlist;
> > > >  }
> > > >
> > > >  static int trace__replay(struct trace *trace)
> > > > @@ -5331,7 +5331,7 @@ static void trace__exit(struct trace *trace)
> > > >               zfree(&trace->syscalls.table);
> > > >       }
> > > >       zfree(&trace->perfconfig_events);
> > > > -     evlist__delete(trace->evlist);
> > > > +     evlist__put(trace->evlist);
> > > >       trace->evlist = NULL;
> > > >       ordered_events__free(&trace->oe.data);
> > > >  #ifdef HAVE_LIBBPF_SUPPORT
> > > > diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
> > > > index c5e7999f2817..2b49b002d749 100644
> > > > --- a/tools/perf/tests/backward-ring-buffer.c
> > > > +++ b/tools/perf/tests/backward-ring-buffer.c
> > > > @@ -111,7 +111,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > > >       err = evlist__create_maps(evlist, &opts.target);
> > > >       if (err < 0) {
> > > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       parse_events_error__init(&parse_error);
> > > > @@ -124,7 +124,7 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > > >       if (err) {
> > > >               pr_debug("Failed to parse tracepoint event, try use root\n");
> > > >               ret = TEST_SKIP;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__config(evlist, &opts, NULL);
> > > > @@ -133,19 +133,19 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > > >       if (err < 0) {
> > > >               pr_debug("perf_evlist__open: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       ret = TEST_FAIL;
> > > >       err = do_test(evlist, opts.mmap_pages, &sample_count,
> > > >                     &comm_count);
> > > >       if (err != TEST_OK)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
> > > >               pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
> > > >                      sample_count, comm_count);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__close(evlist);
> > > > @@ -154,16 +154,16 @@ static int test__backward_ring_buffer(struct test_suite *test __maybe_unused, in
> > > >       if (err < 0) {
> > > >               pr_debug("perf_evlist__open: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       err = do_test(evlist, 1, &sample_count, &comm_count);
> > > >       if (err != TEST_OK)
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       ret = TEST_OK;
> > > > -out_delete_evlist:
> > > > -     evlist__delete(evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
> > > > index 5927d1ea20e2..8da8951154d8 100644
> > > > --- a/tools/perf/tests/code-reading.c
> > > > +++ b/tools/perf/tests/code-reading.c
> > > > @@ -806,7 +806,7 @@ static int do_test_code_reading(bool try_kcore)
> > > >                       }
> > > >
> > > >                       perf_evlist__set_maps(&evlist->core, NULL, NULL);
> > > > -                     evlist__delete(evlist);
> > > > +                     evlist__put(evlist);
> > > >                       evlist = NULL;
> > > >                       continue;
> > > >               }
> > > > @@ -843,7 +843,7 @@ static int do_test_code_reading(bool try_kcore)
> > > >  out_put:
> > > >       thread__put(thread);
> > > >  out_err:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > >       machine__delete(machine);
> > > > diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
> > > > index ae3b98bb42cf..94ab54ecd3f9 100644
> > > > --- a/tools/perf/tests/event-times.c
> > > > +++ b/tools/perf/tests/event-times.c
> > > > @@ -186,7 +186,7 @@ static int test_times(int (attach)(struct evlist *),
> > > >       err = attach(evlist);
> > > >       if (err == TEST_SKIP) {
> > > >               pr_debug("  SKIP  : not enough rights\n");
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               return err;
> > > >       }
> > > >
> > > > @@ -205,7 +205,7 @@ static int test_times(int (attach)(struct evlist *),
> > > >                count.ena, count.run);
> > > >
> > > >  out_err:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return !err ? TEST_OK : TEST_FAIL;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
> > > > index cb9e6de2e033..8de66dac52b0 100644
> > > > --- a/tools/perf/tests/event_update.c
> > > > +++ b/tools/perf/tests/event_update.c
> > > > @@ -115,7 +115,7 @@ static int test__event_update(struct test_suite *test __maybe_unused, int subtes
> > > >       TEST_ASSERT_VAL("failed to synthesize attr update cpus",
> > > >                       !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
> > > >
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return 0;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
> > > > index 1922cac13a24..6a220634c52f 100644
> > > > --- a/tools/perf/tests/evsel-roundtrip-name.c
> > > > +++ b/tools/perf/tests/evsel-roundtrip-name.c
> > > > @@ -33,7 +33,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> > > >                               if (err) {
> > > >                                       pr_debug("Failure to parse cache event '%s' possibly as PMUs don't support it",
> > > >                                               name);
> > > > -                                     evlist__delete(evlist);
> > > > +                                     evlist__put(evlist);
> > > >                                       continue;
> > > >                               }
> > > >                               evlist__for_each_entry(evlist, evsel) {
> > > > @@ -42,7 +42,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
> > > >                                               ret = TEST_FAIL;
> > > >                                       }
> > > >                               }
> > > > -                             evlist__delete(evlist);
> > > > +                             evlist__put(evlist);
> > > >                       }
> > > >               }
> > > >       }
> > > > @@ -66,7 +66,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> > > >               if (err) {
> > > >                       pr_debug("failed to parse event '%s', err %d\n",
> > > >                                names[i], err);
> > > > -                     evlist__delete(evlist);
> > > > +                     evlist__put(evlist);
> > > >                       ret = TEST_FAIL;
> > > >                       continue;
> > > >               }
> > > > @@ -76,7 +76,7 @@ static int perf_evsel__name_array_test(const char *const names[], int nr_names)
> > > >                               ret = TEST_FAIL;
> > > >                       }
> > > >               }
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >       }
> > > >       return ret;
> > > >  }
> > > > diff --git a/tools/perf/tests/expand-cgroup.c b/tools/perf/tests/expand-cgroup.c
> > > > index c7b32a220ca1..9060b085e3de 100644
> > > > --- a/tools/perf/tests/expand-cgroup.c
> > > > +++ b/tools/perf/tests/expand-cgroup.c
> > > > @@ -104,7 +104,7 @@ static int expand_default_events(void)
> > > >       TEST_ASSERT_VAL("failed to get evlist", evlist);
> > > >
> > > >       ret = test_expand_events(evlist);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > @@ -131,7 +131,7 @@ static int expand_group_events(void)
> > > >       ret = test_expand_events(evlist);
> > > >  out:
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > @@ -162,7 +162,7 @@ static int expand_libpfm_events(void)
> > > >
> > > >       ret = test_expand_events(evlist);
> > > >  out:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > @@ -186,7 +186,7 @@ static int expand_metric_events(void)
> > > >       ret = test_expand_events(evlist);
> > > >
> > > >  out:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
> > > > index 3eb9ef8d7ec6..8f7cce7b5085 100644
> > > > --- a/tools/perf/tests/hists_cumulate.c
> > > > +++ b/tools/perf/tests/hists_cumulate.c
> > > > @@ -744,7 +744,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
> > > >
> > > >  out:
> > > >       /* tear down everything */
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       machines__exit(&machines);
> > > >       put_fake_samples();
> > > >
> > > > diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
> > > > index 1cebd20cc91c..447fb2b5947c 100644
> > > > --- a/tools/perf/tests/hists_filter.c
> > > > +++ b/tools/perf/tests/hists_filter.c
> > > > @@ -331,7 +331,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
> > > >
> > > >  out:
> > > >       /* tear down everything */
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       reset_output_field();
> > > >       machines__exit(&machines);
> > > >       put_fake_samples();
> > > > diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
> > > > index 996f5f0b3bd1..9646c3b7b4de 100644
> > > > --- a/tools/perf/tests/hists_link.c
> > > > +++ b/tools/perf/tests/hists_link.c
> > > > @@ -352,7 +352,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
> > > >
> > > >  out:
> > > >       /* tear down everything */
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       reset_output_field();
> > > >       machines__exit(&machines);
> > > >       put_fake_samples();
> > > > diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
> > > > index ee5ec8bda60e..aa8565fbaf90 100644
> > > > --- a/tools/perf/tests/hists_output.c
> > > > +++ b/tools/perf/tests/hists_output.c
> > > > @@ -631,7 +631,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
> > > >
> > > >  out:
> > > >       /* tear down everything */
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       machines__exit(&machines);
> > > >       put_fake_samples();
> > > >
> > > > diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c
> > > > index 97ea036ebae6..7d1040619575 100644
> > > > --- a/tools/perf/tests/hwmon_pmu.c
> > > > +++ b/tools/perf/tests/hwmon_pmu.c
> > > > @@ -211,7 +211,7 @@ static int do_test(size_t i, bool with_pmu, bool with_alias)
> > > >
> > > >  out:
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
> > > > index 729cc9cc1cb7..51cfd6522867 100644
> > > > --- a/tools/perf/tests/keep-tracking.c
> > > > +++ b/tools/perf/tests/keep-tracking.c
> > > > @@ -153,7 +153,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte
> > > >  out_err:
> > > >       if (evlist) {
> > > >               evlist__disable(evlist);
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >       }
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > > diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
> > > > index a622bb8d4cc8..2591b6fbec3f 100644
> > > > --- a/tools/perf/tests/mmap-basic.c
> > > > +++ b/tools/perf/tests/mmap-basic.c
> > > > @@ -93,7 +93,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >                               /* Permissions failure, flag the failure as a skip. */
> > > >                               err = TEST_SKIP;
> > > >                       }
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               evsels[i]->core.attr.wakeup_events = 1;
> > > > @@ -105,7 +105,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >                       pr_debug("failed to open counter: %s, "
> > > >                                "tweak /proc/sys/kernel/perf_event_paranoid?\n",
> > > >                                str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               nr_events[i] = 0;
> > > > @@ -115,7 +115,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >       if (evlist__mmap(evlist, 128) < 0) {
> > > >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       for (i = 0; i < nsyscalls; ++i)
> > > > @@ -133,7 +133,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >               if (event->header.type != PERF_RECORD_SAMPLE) {
> > > >                       pr_debug("unexpected %s event\n",
> > > >                                perf_event__name(event->header.type));
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               perf_sample__init(&sample, /*all=*/false);
> > > > @@ -141,7 +141,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >               if (err) {
> > > >                       pr_err("Can't parse sample, err = %d\n", err);
> > > >                       perf_sample__exit(&sample);
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               err = -1;
> > > > @@ -150,7 +150,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >               if (evsel == NULL) {
> > > >                       pr_debug("event with id %" PRIu64
> > > >                                " doesn't map to an evsel\n", sample.id);
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >               nr_events[evsel->core.idx]++;
> > > >               perf_mmap__consume(&md->core);
> > > > @@ -165,12 +165,12 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
> > > >                                expected_nr_events[evsel->core.idx],
> > > >                                evsel__name(evsel), nr_events[evsel->core.idx]);
> > > >                       err = -1;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(evlist);
> > > >  out_free_cpus:
> > > >       perf_cpu_map__put(cpus);
> > > >  out_free_threads:
> > > > diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
> > > > index 2a139d2781a8..3ff595c7a86a 100644
> > > > --- a/tools/perf/tests/openat-syscall-tp-fields.c
> > > > +++ b/tools/perf/tests/openat-syscall-tp-fields.c
> > > > @@ -51,7 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >       if (IS_ERR(evsel)) {
> > > >               pr_debug("%s: evsel__newtp\n", __func__);
> > > >               ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__add(evlist, evsel);
> > > > @@ -59,7 +59,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >       err = evlist__create_maps(evlist, &opts.target);
> > > >       if (err < 0) {
> > > >               pr_debug("%s: evlist__create_maps\n", __func__);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evsel__config(evsel, &opts, NULL);
> > > > @@ -70,14 +70,14 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >       if (err < 0) {
> > > >               pr_debug("perf_evlist__open: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       err = evlist__mmap(evlist, UINT_MAX);
> > > >       if (err < 0) {
> > > >               pr_debug("evlist__mmap: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__enable(evlist);
> > > > @@ -115,7 +115,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >                               if (err) {
> > > >                                       pr_debug("Can't parse sample, err = %d\n", err);
> > > >                                       perf_sample__exit(&sample);
> > > > -                                     goto out_delete_evlist;
> > > > +                                     goto out_put_evlist;
> > > >                               }
> > > >
> > > >                               tp_flags = evsel__intval(evsel, &sample, "flags");
> > > > @@ -123,7 +123,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >                               if (flags != tp_flags) {
> > > >                                       pr_debug("%s: Expected flags=%#x, got %#x\n",
> > > >                                                __func__, flags, tp_flags);
> > > > -                                     goto out_delete_evlist;
> > > > +                                     goto out_put_evlist;
> > > >                               }
> > > >
> > > >                               goto out_ok;
> > > > @@ -136,13 +136,13 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused
> > > >
> > > >               if (++nr_polls > 5) {
> > > >                       pr_debug("%s: no events!\n", __func__);
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >       }
> > > >  out_ok:
> > > >       ret = TEST_OK;
> > > > -out_delete_evlist:
> > > > -     evlist__delete(evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(evlist);
> > > >  out:
> > > >       return ret;
> > > >  }
> > > > diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
> > > > index e4cdb517c10e..0778462016f7 100644
> > > > --- a/tools/perf/tests/parse-events.c
> > > > +++ b/tools/perf/tests/parse-events.c
> > > > @@ -2550,7 +2550,7 @@ static int test_event(const struct evlist_test *e)
> > > >               ret = e->check(evlist);
> > > >       }
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >
> > > >       return ret;
> > > >  }
> > > > @@ -2576,7 +2576,7 @@ static int test_event_fake_pmu(const char *str)
> > > >       }
> > > >
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >
> > > >       return ret;
> > > >  }
> > > > diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> > > > index 66a5275917e2..b343628c7a7e 100644
> > > > --- a/tools/perf/tests/parse-metric.c
> > > > +++ b/tools/perf/tests/parse-metric.c
> > > > @@ -83,7 +83,7 @@ static int __compute_metric(const char *name, struct value *vals,
> > > >
> > > >       cpus = perf_cpu_map__new("0");
> > > >       if (!cpus) {
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               return -ENOMEM;
> > > >       }
> > > >
> > > > @@ -112,7 +112,7 @@ static int __compute_metric(const char *name, struct value *vals,
> > > >       /* ... cleanup. */
> > > >       evlist__free_stats(evlist);
> > > >       perf_cpu_map__put(cpus);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
> > > > index 50e68b7d43aa..d5a8d065809e 100644
> > > > --- a/tools/perf/tests/parse-no-sample-id-all.c
> > > > +++ b/tools/perf/tests/parse-no-sample-id-all.c
> > > > @@ -49,7 +49,7 @@ static int process_events(union perf_event **events, size_t count)
> > > >       for (i = 0; i < count && !err; i++)
> > > >               err = process_event(&evlist, events[i]);
> > > >
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >
> > > >       return err;
> > > >  }
> > > > diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
> > > > index efbd9cd60c63..babec674b83c 100644
> > > > --- a/tools/perf/tests/perf-record.c
> > > > +++ b/tools/perf/tests/perf-record.c
> > > > @@ -102,7 +102,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >       err = evlist__create_maps(evlist, &opts.target);
> > > >       if (err < 0) {
> > > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       /*
> > > > @@ -114,7 +114,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >       err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
> > > >       if (err < 0) {
> > > >               pr_debug("Couldn't run the workload!\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       /*
> > > > @@ -131,7 +131,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >               pr_debug("sched__get_first_possible_cpu: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > >               evlist__cancel_workload(evlist);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       cpu = err;
> > > > @@ -143,7 +143,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >               pr_debug("sched_setaffinity: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > >               evlist__cancel_workload(evlist);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       /*
> > > > @@ -155,7 +155,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >               pr_debug("perf_evlist__open: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > >               evlist__cancel_workload(evlist);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       /*
> > > > @@ -168,7 +168,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >               pr_debug("evlist__mmap: %s\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > >               evlist__cancel_workload(evlist);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       /*
> > > > @@ -206,7 +206,7 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >                                       if (verbose > 0)
> > > >                                               perf_event__fprintf(event, NULL, stderr);
> > > >                                       pr_debug("Couldn't parse sample\n");
> > > > -                                     goto out_delete_evlist;
> > > > +                                     goto out_put_evlist;
> > > >                               }
> > > >
> > > >                               if (verbose > 0) {
> > > > @@ -346,9 +346,9 @@ static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest
> > > >               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
> > > >               ++errs;
> > > >       }
> > > > -out_delete_evlist:
> > > > +out_put_evlist:
> > > >       CPU_FREE(cpu_mask);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >  out:
> > > >       perf_sample__exit(&sample);
> > > >       if (err == -EACCES)
> > > > diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
> > > > index cca41bd37ae3..d3538fa20af3 100644
> > > > --- a/tools/perf/tests/perf-time-to-tsc.c
> > > > +++ b/tools/perf/tests/perf-time-to-tsc.c
> > > > @@ -201,7 +201,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su
> > > >       err = TEST_OK;
> > > >
> > > >  out_err:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > >       return err;
> > > > diff --git a/tools/perf/tests/pfm.c b/tools/perf/tests/pfm.c
> > > > index 2e38dfa34b6c..099a50dec37e 100644
> > > > --- a/tools/perf/tests/pfm.c
> > > > +++ b/tools/perf/tests/pfm.c
> > > > @@ -79,7 +79,7 @@ static int test__pfm_events(struct test_suite *test __maybe_unused,
> > > >                               evlist__nr_groups(evlist),
> > > >                               0);
> > > >
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >       }
> > > >       return 0;
> > > >  }
> > > > @@ -164,7 +164,7 @@ static int test__pfm_group(struct test_suite *test __maybe_unused,
> > > >                               evlist__nr_groups(evlist),
> > > >                               table[i].nr_groups);
> > > >
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >       }
> > > >       return 0;
> > > >  }
> > > > diff --git a/tools/perf/tests/pmu-events.c b/tools/perf/tests/pmu-events.c
> > > > index f40a828c9861..ab547f301c61 100644
> > > > --- a/tools/perf/tests/pmu-events.c
> > > > +++ b/tools/perf/tests/pmu-events.c
> > > > @@ -797,7 +797,7 @@ static int check_parse_id(const char *id, struct parse_events_error *error)
> > > >                            /*warn_if_reordered=*/true, /*fake_tp=*/false);
> > > >       free(dup);
> > > >
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > @@ -844,7 +844,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> > > >
> > > >       cpus = perf_cpu_map__new("0");
> > > >       if (!cpus) {
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               return -ENOMEM;
> > > >       }
> > > >
> > > > @@ -901,7 +901,7 @@ static int test__parsing_callback(const struct pmu_metric *pm,
> > > >       /* ... cleanup. */
> > > >       evlist__free_stats(evlist);
> > > >       perf_cpu_map__put(cpus);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
> > > > index cbded2c6faa4..bd3f4a2806ed 100644
> > > > --- a/tools/perf/tests/pmu.c
> > > > +++ b/tools/perf/tests/pmu.c
> > > > @@ -249,7 +249,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest
> > > >       ret = TEST_OK;
> > > >  err_out:
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       test_pmu_put(dir, pmu);
> > > >       return ret;
> > > >  }
> > > > diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
> > > > index 4a2ad7176fa0..f7f1f16638b4 100644
> > > > --- a/tools/perf/tests/sw-clock.c
> > > > +++ b/tools/perf/tests/sw-clock.c
> > > > @@ -58,7 +58,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > > >       evsel = evsel__new(&attr);
> > > >       if (evsel == NULL) {
> > > >               pr_debug("evsel__new\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >       evlist__add(evlist, evsel);
> > > >
> > > > @@ -67,7 +67,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > > >       if (!cpus || !threads) {
> > > >               err = -ENOMEM;
> > > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > > @@ -79,14 +79,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > > >               pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)),
> > > >                        knob, (u64)attr.sample_freq);
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       err = evlist__mmap(evlist, 128);
> > > >       if (err < 0) {
> > > >               pr_debug("failed to mmap event: %d (%s)\n", errno,
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__enable(evlist);
> > > > @@ -112,7 +112,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > > >               if (err < 0) {
> > > >                       pr_debug("Error during parse sample\n");
> > > >                       perf_sample__exit(&sample);
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               total_periods += sample.period;
> > > > @@ -130,10 +130,10 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
> > > >               err = -1;
> > > >       }
> > > >
> > > > -out_delete_evlist:
> > > > +out_put_evlist:
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
> > > > index 15791fcb76b2..c3d5825df0a8 100644
> > > > --- a/tools/perf/tests/switch-tracking.c
> > > > +++ b/tools/perf/tests/switch-tracking.c
> > > > @@ -577,7 +577,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub
> > > >  out:
> > > >       if (evlist) {
> > > >               evlist__disable(evlist);
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >       }
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > > diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
> > > > index 4053ff2813bb..a46650b10689 100644
> > > > --- a/tools/perf/tests/task-exit.c
> > > > +++ b/tools/perf/tests/task-exit.c
> > > > @@ -74,7 +74,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > > >       if (!cpus || !threads) {
> > > >               err = -ENOMEM;
> > > >               pr_debug("Not enough memory to create thread/cpu maps\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > > @@ -82,7 +82,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > > >       err = evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal);
> > > >       if (err < 0) {
> > > >               pr_debug("Couldn't run the workload!\n");
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evsel = evlist__first(evlist);
> > > > @@ -101,14 +101,14 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > > >       if (err < 0) {
> > > >               pr_debug("Couldn't open the evlist: %s\n",
> > > >                        str_error_r(-err, sbuf, sizeof(sbuf)));
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (evlist__mmap(evlist, 128) < 0) {
> > > >               pr_debug("failed to mmap events: %d (%s)\n", errno,
> > > >                        str_error_r(errno, sbuf, sizeof(sbuf)));
> > > >               err = -1;
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist__start_workload(evlist);
> > > > @@ -133,7 +133,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > > >               if (retry_count++ > 1000) {
> > > >                       pr_debug("Failed after retrying 1000 times\n");
> > > >                       err = -1;
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >               }
> > > >
> > > >               goto retry;
> > > > @@ -144,10 +144,10 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _
> > > >               err = -1;
> > > >       }
> > > >
> > > > -out_delete_evlist:
> > > > +out_put_evlist:
> > > >       perf_cpu_map__put(cpus);
> > > >       perf_thread_map__put(threads);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c
> > > > index 1e900ef92e37..e78ff9dcea97 100644
> > > > --- a/tools/perf/tests/tool_pmu.c
> > > > +++ b/tools/perf/tests/tool_pmu.c
> > > > @@ -67,7 +67,7 @@ static int do_test(enum tool_pmu_event ev, bool with_pmu)
> > > >
> > > >  out:
> > > >       parse_events_error__exit(&err);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
> > > > index af4618c3124a..b88447899021 100644
> > > > --- a/tools/perf/tests/topology.c
> > > > +++ b/tools/perf/tests/topology.c
> > > > @@ -55,7 +55,7 @@ static int session_write_header(char *path)
> > > >                       !perf_session__write_header(session, session->evlist,
> > > >                                                   perf_data__fd(&data), true));
> > > >
> > > > -     evlist__delete(session->evlist);
> > > > +     evlist__put(session->evlist);
> > > >       perf_session__delete(session);
> > > >
> > > >       return 0;
> > > > diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
> > > > index 25e2769b5e74..ed230cd44ba7 100644
> > > > --- a/tools/perf/util/cgroup.c
> > > > +++ b/tools/perf/util/cgroup.c
> > > > @@ -503,8 +503,8 @@ int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgro
> > > >       cgrp_event_expanded = true;
> > > >
> > > >  out_err:
> > > > -     evlist__delete(orig_list);
> > > > -     evlist__delete(tmp_list);
> > > > +     evlist__put(orig_list);
> > > > +     evlist__put(tmp_list);
> > > >       metricgroup__rblist_exit(&orig_metric_events);
> > > >       release_cgroup_list();
> > > >
> > > > diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
> > > > index 3d2e437e1354..1166cdb00aca 100644
> > > > --- a/tools/perf/util/data-convert-bt.c
> > > > +++ b/tools/perf/util/data-convert-bt.c
> > > > @@ -1331,7 +1331,7 @@ static void cleanup_events(struct perf_session *session)
> > > >               zfree(&evsel->priv);
> > > >       }
> > > >
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       session->evlist = NULL;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > > > index d99a3f12606f..ea1f398c14e3 100644
> > > > --- a/tools/perf/util/evlist.c
> > > > +++ b/tools/perf/util/evlist.c
> > > > @@ -73,7 +73,7 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
> > > >  #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
> > > >  #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
> > > >
> > > > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > > +static void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > >                 struct perf_thread_map *threads)
> > > >  {
> > > >       perf_evlist__init(&evlist->core);
> > > > @@ -85,6 +85,7 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > >       evlist->ctl_fd.pos = -1;
> > > >       evlist->nr_br_cntr = -1;
> > > >       metricgroup__rblist_init(&evlist->metric_events);
> > > > +     refcount_set(&evlist->refcnt, 1);
> > > >  }
> > > >
> > > >  struct evlist *evlist__new(void)
> > > > @@ -116,7 +117,7 @@ struct evlist *evlist__new_default(void)
> > > >                        can_profile_kernel ? "P" : "Pu");
> > > >               err = parse_event(evlist, buf);
> > > >               if (err) {
> > > > -                     evlist__delete(evlist);
> > > > +                     evlist__put(evlist);
> > > >                       return NULL;
> > > >               }
> > > >       }
> > > > @@ -136,13 +137,19 @@ struct evlist *evlist__new_dummy(void)
> > > >       struct evlist *evlist = evlist__new();
> > > >
> > > >       if (evlist && evlist__add_dummy(evlist)) {
> > > > -             evlist__delete(evlist);
> > > > +             evlist__put(evlist);
> > > >               evlist = NULL;
> > > >       }
> > > >
> > > >       return evlist;
> > > >  }
> > > >
> > > > +struct evlist *evlist__get(struct evlist *evlist)
> > > > +{
> > > > +     refcount_inc(&evlist->refcnt);
> > > > +     return evlist;
> > > > +}
> > > > +
> > > >  /**
> > > >   * evlist__set_id_pos - set the positions of event ids.
> > > >   * @evlist: selected event list
> > > > @@ -181,7 +188,7 @@ static void evlist__purge(struct evlist *evlist)
> > > >       evlist->core.nr_entries = 0;
> > > >  }
> > > >
> > > > -void evlist__exit(struct evlist *evlist)
> > > > +static void evlist__exit(struct evlist *evlist)
> > > >  {
> > > >       metricgroup__rblist_exit(&evlist->metric_events);
> > > >       event_enable_timer__exit(&evlist->eet);
> > > > @@ -190,11 +197,14 @@ void evlist__exit(struct evlist *evlist)
> > > >       perf_evlist__exit(&evlist->core);
> > > >  }
> > > >
> > > > -void evlist__delete(struct evlist *evlist)
> > > > +void evlist__put(struct evlist *evlist)
> > > >  {
> > > >       if (evlist == NULL)
> > > >               return;
> > > >
> > > > +     if (!refcount_dec_and_test(&evlist->refcnt))
> > > > +             return;
> > > > +
> > > >       evlist__free_stats(evlist);
> > > >       evlist__munmap(evlist);
> > > >       evlist__close(evlist);
> > > > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > > > index 61acbb10d9a5..66fb5da08160 100644
> > > > --- a/tools/perf/util/evlist.h
> > > > +++ b/tools/perf/util/evlist.h
> > > > @@ -59,6 +59,7 @@ struct event_enable_timer;
> > > >
> > > >  struct evlist {
> > > >       struct perf_evlist core;
> > > > +     refcount_t       refcnt;
> > > >       bool             enabled;
> > > >       int              id_pos;
> > > >       int              is_pos;
> > > > @@ -104,10 +105,8 @@ struct evsel_str_handler {
> > > >  struct evlist *evlist__new(void);
> > > >  struct evlist *evlist__new_default(void);
> > > >  struct evlist *evlist__new_dummy(void);
> > > > -void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
> > > > -               struct perf_thread_map *threads);
> > > > -void evlist__exit(struct evlist *evlist);
> > > > -void evlist__delete(struct evlist *evlist);
> > > > +struct evlist *evlist__get(struct evlist *evlist);
> > > > +void evlist__put(struct evlist *evlist);
> > > >
> > > >  void evlist__add(struct evlist *evlist, struct evsel *entry);
> > > >  void evlist__remove(struct evlist *evlist, struct evsel *evsel);
> > > > diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
> > > > index 7fda0ff89c16..4304b53b5a37 100644
> > > > --- a/tools/perf/util/expr.c
> > > > +++ b/tools/perf/util/expr.c
> > > > @@ -451,7 +451,7 @@ double expr__has_event(const struct expr_parse_ctx *ctx, bool compute_ids, const
> > > >               ret = parse_event(tmp, id) ? 0 : 1;
> > > >       }
> > > >  out:
> > > > -     evlist__delete(tmp);
> > > > +     evlist__put(tmp);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> > > > index 4f2a6e10ed5c..e959ddb12dc8 100644
> > > > --- a/tools/perf/util/header.c
> > > > +++ b/tools/perf/util/header.c
> > > > @@ -4307,12 +4307,12 @@ int perf_session__read_header(struct perf_session *session)
> > > >               evsel = evsel__new(&f_attr.attr);
> > > >
> > > >               if (evsel == NULL)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >
> > > >               evsel->needs_swap = header->needs_swap;
> > > >               /*
> > > >                * Do it before so that if perf_evsel__alloc_id fails, this
> > > > -              * entry gets purged too at evlist__delete().
> > > > +              * entry gets purged too at evlist__put().
> > > >                */
> > > >               evlist__add(session->evlist, evsel);
> > > >
> > > > @@ -4323,7 +4323,7 @@ int perf_session__read_header(struct perf_session *session)
> > > >                * hattr->ids threads.
> > > >                */
> > > >               if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >
> > > >               lseek(fd, f_attr.ids.offset, SEEK_SET);
> > > >
> > > > @@ -4342,7 +4342,7 @@ int perf_session__read_header(struct perf_session *session)
> > > >                                     perf_file_section__process);
> > > >
> > > >       if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >  #else
> > > >       perf_header__process_sections(header, fd, NULL, perf_file_section__process);
> > > >  #endif
> > > > @@ -4351,8 +4351,8 @@ int perf_session__read_header(struct perf_session *session)
> > > >  out_errno:
> > > >       return -errno;
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(session->evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(session->evlist);
> > > >       session->evlist = NULL;
> > > >       return -ENOMEM;
> > > >  }
> > > > diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
> > > > index 595b83142d2c..64c64dff7424 100644
> > > > --- a/tools/perf/util/metricgroup.c
> > > > +++ b/tools/perf/util/metricgroup.c
> > > > @@ -212,7 +212,7 @@ static void metric__free(struct metric *m)
> > > >       zfree(&m->metric_refs);
> > > >       expr__ctx_free(m->pctx);
> > > >       zfree(&m->modifier);
> > > > -     evlist__delete(m->evlist);
> > > > +     evlist__put(m->evlist);
> > > >       free(m);
> > > >  }
> > > >
> > > > @@ -1318,7 +1318,7 @@ static int parse_ids(bool metric_no_merge, bool fake_pmu,
> > > >       parsed_evlist = NULL;
> > > >  err_out:
> > > >       parse_events_error__exit(&parse_error);
> > > > -     evlist__delete(parsed_evlist);
> > > > +     evlist__put(parsed_evlist);
> > > >       strbuf_release(&events);
> > > >       return ret;
> > > >  }
> > > > @@ -1470,7 +1470,7 @@ static int parse_groups(struct evlist *perf_evlist,
> > > >
> > > >       if (combined_evlist) {
> > > >               evlist__splice_list_tail(perf_evlist, &combined_evlist->core.entries);
> > > > -             evlist__delete(combined_evlist);
> > > > +             evlist__put(combined_evlist);
> > > >       }
> > > >
> > > >       list_for_each_entry(m, &metric_list, nd) {
> > > > diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> > > > index 0c0dc20b1c13..607ab7b82486 100644
> > > > --- a/tools/perf/util/parse-events.c
> > > > +++ b/tools/perf/util/parse-events.c
> > > > @@ -2223,7 +2223,7 @@ int __parse_events(struct evlist *evlist, const char *str, const char *pmu_filte
> > > >
> > > >       /*
> > > >        * There are 2 users - builtin-record and builtin-test objects.
> > > > -      * Both call evlist__delete in case of error, so we dont
> > > > +      * Both call evlist__put in case of error, so we dont
> > > >        * need to bother.
> > > >        */
> > > >       return ret;
> > > > @@ -2424,7 +2424,7 @@ int parse_events_option_new_evlist(const struct option *opt, const char *str, in
> > > >       }
> > > >       ret = parse_events_option(opt, str, unset);
> > > >       if (ret) {
> > > > -             evlist__delete(*args->evlistp);
> > > > +             evlist__put(*args->evlistp);
> > > >               *args->evlistp = NULL;
> > > >       }
> > > >
> > > > diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
> > > > index 3345145a9307..8cd254d36220 100644
> > > > --- a/tools/perf/util/perf_api_probe.c
> > > > +++ b/tools/perf/util/perf_api_probe.c
> > > > @@ -56,7 +56,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const cha
> > > >       err = 0;
> > > >
> > > >  out_delete:
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >       return err;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> > > > index dfc6e9299af9..4149a51e9878 100644
> > > > --- a/tools/perf/util/python.c
> > > > +++ b/tools/perf/util/python.c
> > > > @@ -1273,7 +1273,7 @@ static int pyrf_evsel__setup_types(void)
> > > >  struct pyrf_evlist {
> > > >       PyObject_HEAD
> > > >
> > > > -     struct evlist evlist;
> > > > +     struct evlist *evlist;
> > > >  };
> > > >
> > > >  static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> > > > @@ -1286,15 +1286,21 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
> > > >       if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
> > > >               return -1;
> > > >
> > > > +     pevlist->evlist = evlist__new();
> > > > +     if (!pevlist->evlist) {
> > > > +             PyErr_NoMemory();
> > > > +             return -1;
> > > > +     }
> > > >       threads = ((struct pyrf_thread_map *)pthreads)->threads;
> > > >       cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
> > > > -     evlist__init(&pevlist->evlist, cpus, threads);
> > > > +     perf_evlist__set_maps(&pevlist->evlist->core, cpus, threads);
> > > > +
> > > >       return 0;
> > > >  }
> > > >
> > > >  static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
> > > >  {
> > > > -     evlist__exit(&pevlist->evlist);
> > > > +     evlist__put(pevlist->evlist);
> > > >       Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
> > > >  }
> > > >
> > > > @@ -1303,7 +1309,7 @@ static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
> > > >       struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
> > > >
> > > >       if (pcpu_map)
> > > > -             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
> > > > +             pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist->core.all_cpus);
> > > >
> > > >       return (PyObject *)pcpu_map;
> > > >  }
> > > > @@ -1316,7 +1322,7 @@ static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
> > > >       if (!list)
> > > >               return NULL;
> > > >
> > > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > > > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries); node;
> > > >            node = rb_next(node)) {
> > > >               struct metric_event *me = container_of(node, struct metric_event, nd);
> > > >               struct list_head *pos;
> > > > @@ -1400,7 +1406,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> > > >       if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
> > > >               return NULL;
> > > >
> > > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
> > > > +     for (node = rb_first_cached(&pevlist->evlist->metric_events.entries);
> > > >            mexp == NULL && node;
> > > >            node = rb_next(node)) {
> > > >               struct metric_event *me = container_of(node, struct metric_event, nd);
> > > > @@ -1456,7 +1462,7 @@ static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
> > > >  static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> > > >                                  PyObject *args, PyObject *kwargs)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >       static char *kwlist[] = { "pages", "overwrite", NULL };
> > > >       int pages = 128, overwrite = false;
> > > >
> > > > @@ -1476,7 +1482,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
> > > >  static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
> > > >                                  PyObject *args, PyObject *kwargs)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >       static char *kwlist[] = { "timeout", NULL };
> > > >       int timeout = -1, n;
> > > >
> > > > @@ -1496,7 +1502,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
> > > >                                        PyObject *args __maybe_unused,
> > > >                                        PyObject *kwargs __maybe_unused)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >          PyObject *list = PyList_New(0);
> > > >       int i;
> > > >
> > > > @@ -1525,7 +1531,7 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
> > > >                                 PyObject *args,
> > > >                                 PyObject *kwargs __maybe_unused)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >       PyObject *pevsel;
> > > >       struct evsel *evsel;
> > > >
> > > > @@ -1557,7 +1563,7 @@ static struct mmap *get_md(struct evlist *evlist, int cpu)
> > > >  static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> > > >                                         PyObject *args, PyObject *kwargs)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >       union perf_event *event;
> > > >       int sample_id_all = 1, cpu;
> > > >       static char *kwlist[] = { "cpu", "sample_id_all", NULL };
> > > > @@ -1614,7 +1620,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
> > > >  static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> > > >                                  PyObject *args, PyObject *kwargs)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >
> > > >       if (evlist__open(evlist) < 0) {
> > > >               PyErr_SetFromErrno(PyExc_OSError);
> > > > @@ -1627,7 +1633,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
> > > >
> > > >  static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
> > > >  {
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >
> > > >       evlist__close(evlist);
> > > >
> > > > @@ -1653,7 +1659,7 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> > > >               .no_buffering        = true,
> > > >               .no_inherit          = true,
> > > >       };
> > > > -     struct evlist *evlist = &pevlist->evlist;
> > > > +     struct evlist *evlist = pevlist->evlist;
> > > >
> > > >       evlist__config(evlist, &opts, &callchain_param);
> > > >       Py_INCREF(Py_None);
> > > > @@ -1662,14 +1668,14 @@ static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
> > > >
> > > >  static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
> > > >  {
> > > > -     evlist__disable(&pevlist->evlist);
> > > > +     evlist__disable(pevlist->evlist);
> > > >       Py_INCREF(Py_None);
> > > >       return Py_None;
> > > >  }
> > > >
> > > >  static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
> > > >  {
> > > > -     evlist__enable(&pevlist->evlist);
> > > > +     evlist__enable(pevlist->evlist);
> > > >       Py_INCREF(Py_None);
> > > >       return Py_None;
> > > >  }
> > > > @@ -1760,7 +1766,23 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj)
> > > >  {
> > > >       struct pyrf_evlist *pevlist = (void *)obj;
> > > >
> > > > -     return pevlist->evlist.core.nr_entries;
> > > > +     return pevlist->evlist->core.nr_entries;
> > > > +}
> > > > +
> > > > +static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > > > +{
> > > > +     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > > > +
> > > > +     if (!pevsel)
> > > > +             return NULL;
> > > > +
> > > > +     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > > > +     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > > > +
> > > > +     evsel__clone(&pevsel->evsel, evsel);
> > > > +     if (evsel__is_group_leader(evsel))
> > > > +             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > > > +     return (PyObject *)pevsel;
> > > >  }
> > > >
> > > >  static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> > > > @@ -1768,17 +1790,16 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
> > > >       struct pyrf_evlist *pevlist = (void *)obj;
> > > >       struct evsel *pos;
> > > >
> > > > -     if (i >= pevlist->evlist.core.nr_entries) {
> > > > +     if (i >= pevlist->evlist->core.nr_entries) {
> > > >               PyErr_SetString(PyExc_IndexError, "Index out of range");
> > > >               return NULL;
> > > >       }
> > > >
> > > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > > +     evlist__for_each_entry(pevlist->evlist, pos) {
> > > >               if (i-- == 0)
> > > >                       break;
> > > >       }
> > > > -
> > > > -     return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
> > > > +     return pyrf_evsel__from_evsel(pos);
> > > >  }
> > > >
> > > >  static PyObject *pyrf_evlist__str(PyObject *self)
> > > > @@ -1790,7 +1811,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
> > > >       PyObject *result;
> > > >
> > > >       strbuf_addstr(&sb, "evlist([");
> > > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > > +     evlist__for_each_entry(pevlist->evlist, pos) {
> > > >               if (!first)
> > > >                       strbuf_addch(&sb, ',');
> > > >               if (!pos->pmu)
> > > > @@ -1931,110 +1952,30 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
> > > >       return PyLong_FromLong(tp_pmu__id(sys, name));
> > > >  }
> > > >
> > > > -static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
> > > > -{
> > > > -     struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
> > > > -
> > > > -     if (!pevsel)
> > > > -             return NULL;
> > > > -
> > > > -     memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
> > > > -     evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
> > > > -
> > > > -     evsel__clone(&pevsel->evsel, evsel);
> > > > -     if (evsel__is_group_leader(evsel))
> > > > -             evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
> > > > -     return (PyObject *)pevsel;
> > > > -}
> > > > -
> > > > -static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
> > > > -{
> > > > -     struct evsel *pos;
> > > > -     int idx = 0;
> > > > -
> > > > -     evlist__for_each_entry(evlist, pos) {
> > > > -             if (evsel == pos)
> > > > -                     return idx;
> > > > -             idx++;
> > > > -     }
> > > > -     return -1;
> > > > -}
> > > > -
> > > > -static struct evsel *evlist__at(struct evlist *evlist, int idx)
> > > > -{
> > > > -     struct evsel *pos;
> > > > -     int idx2 = 0;
> > > > -
> > > > -     evlist__for_each_entry(evlist, pos) {
> > > > -             if (idx == idx2)
> > > > -                     return pos;
> > > > -             idx2++;
> > > > -     }
> > > > -     return NULL;
> > > > -}
> > > > -
> > > >  static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
> > > >  {
> > > >       struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
> > > > -     struct evsel *pos;
> > > > -     struct rb_node *node;
> > > >
> > > >       if (!pevlist)
> > > >               return NULL;
> > > >
> > > > -     memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
> > > > -     evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
> > > > -     evlist__for_each_entry(evlist, pos) {
> > > > -             struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
> > > > -
> > > > -             evlist__add(&pevlist->evlist, &pevsel->evsel);
> > > > -     }
> > > > -     evlist__for_each_entry(&pevlist->evlist, pos) {
> > > > -             struct evsel *leader = evsel__leader(pos);
> > > > -
> > > > -             if (pos != leader) {
> > > > -                     int idx = evlist__pos(evlist, leader);
> > > > -
> > > > -                     if (idx >= 0)
> > > > -                             evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
> > > > -                     else if (leader == NULL)
> > > > -                             evsel__set_leader(pos, pos);
> > > > -             }
> > > > -     }
> > > > -     metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
> > > > -                                     &pevlist->evlist.metric_events,
> > > > -                                     &evlist->metric_events);
> > > > -     for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
> > > > -          node = rb_next(node)) {
> > > > -             struct metric_event *me = container_of(node, struct metric_event, nd);
> > > > -             struct list_head *mpos;
> > > > -             int idx = evlist__pos(evlist, me->evsel);
> > > > -
> > > > -             if (idx >= 0)
> > > > -                     me->evsel = evlist__at(&pevlist->evlist, idx);
> > > > -             list_for_each(mpos, &me->head) {
> > > > -                     struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
> > > > -
> > > > -                     for (int j = 0; e->metric_events[j]; j++) {
> > > > -                             idx = evlist__pos(evlist, e->metric_events[j]);
> > > > -                             if (idx >= 0)
> > > > -                                     e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
> > > > -                     }
> > > > -             }
> > > > -     }
> > > > +     pevlist->evlist = evlist__get(evlist);
> > > >       return (PyObject *)pevlist;
> > > >  }
> > > >
> > > >  static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> > > >  {
> > > >       const char *input;
> > > > -     struct evlist evlist = {};
> > > > +     struct evlist *evlist = evlist__new();
> > > >       struct parse_events_error err;
> > > >       PyObject *result;
> > > >       PyObject *pcpus = NULL, *pthreads = NULL;
> > > >       struct perf_cpu_map *cpus;
> > > >       struct perf_thread_map *threads;
> > > >
> > > > +     if (!evlist)
> > > > +             return PyErr_NoMemory();
> > > > +
> > > >       if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
> > > >               return NULL;
> > > >
> > > > @@ -2042,35 +1983,38 @@ static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
> > > >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> > > >
> > > >       parse_events_error__init(&err);
> > > > -     evlist__init(&evlist, cpus, threads);
> > > > -     if (parse_events(&evlist, input, &err)) {
> > > > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > > +     if (parse_events(evlist, input, &err)) {
> > > >               parse_events_error__print(&err, input);
> > > >               PyErr_SetFromErrno(PyExc_OSError);
> > > >               return NULL;
> > > >       }
> > > > -     result = pyrf_evlist__from_evlist(&evlist);
> > > > -     evlist__exit(&evlist);
> > > > +     result = pyrf_evlist__from_evlist(evlist);
> > > > +     evlist__put(evlist);
> > > >       return result;
> > > >  }
> > > >
> > > >  static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> > > >  {
> > > >       const char *input, *pmu = NULL;
> > > > -     struct evlist evlist = {};
> > > > +     struct evlist *evlist = evlist__new();
> > > >       PyObject *result;
> > > >       PyObject *pcpus = NULL, *pthreads = NULL;
> > > >       struct perf_cpu_map *cpus;
> > > >       struct perf_thread_map *threads;
> > > >       int ret;
> > > >
> > > > +     if (!evlist)
> > > > +             return PyErr_NoMemory();
> > > > +
> > > >       if (!PyArg_ParseTuple(args, "s|sOO", &input, &pmu, &pcpus, &pthreads))
> > > >               return NULL;
> > > >
> > > >       threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
> > > >       cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
> > > >
> > > > -     evlist__init(&evlist, cpus, threads);
> > > > -     ret = metricgroup__parse_groups(&evlist, pmu ?: "all", input,
> > > > +     perf_evlist__set_maps(&evlist->core, cpus, threads);
> > > > +     ret = metricgroup__parse_groups(evlist, pmu ?: "all", input,
> > > >                                       /*metric_no_group=*/ false,
> > > >                                       /*metric_no_merge=*/ false,
> > > >                                       /*metric_no_threshold=*/ true,
> > > > @@ -2082,8 +2026,8 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
> > > >               PyErr_SetFromErrno(PyExc_OSError);
> > > >               return NULL;
> > > >       }
> > > > -     result = pyrf_evlist__from_evlist(&evlist);
> > > > -     evlist__exit(&evlist);
> > > > +     result = pyrf_evlist__from_evlist(evlist);
> > > > +     evlist__put(evlist);
> > > >       return result;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
> > > > index e867de8ddaaa..8a5fc7d5e43c 100644
> > > > --- a/tools/perf/util/record.c
> > > > +++ b/tools/perf/util/record.c
> > > > @@ -264,7 +264,7 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str)
> > > >       ret = true;
> > > >
> > > >  out_delete:
> > > > -     evlist__delete(temp_evlist);
> > > > +     evlist__put(temp_evlist);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> > > > index 081e68c72c30..f241d91221d7 100644
> > > > --- a/tools/perf/util/session.c
> > > > +++ b/tools/perf/util/session.c
> > > > @@ -256,7 +256,7 @@ void perf_session__delete(struct perf_session *session)
> > > >       machines__exit(&session->machines);
> > > >       if (session->data) {
> > > >               if (perf_data__is_read(session->data))
> > > > -                     evlist__delete(session->evlist);
> > > > +                     evlist__put(session->evlist);
> > > >               perf_data__close(session->data);
> > > >       }
> > > >  #ifdef HAVE_LIBTRACEEVENT
> > > > diff --git a/tools/perf/util/sideband_evlist.c b/tools/perf/util/sideband_evlist.c
> > > > index 388846f17bc1..b84a5463e039 100644
> > > > --- a/tools/perf/util/sideband_evlist.c
> > > > +++ b/tools/perf/util/sideband_evlist.c
> > > > @@ -102,7 +102,7 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> > > >               return 0;
> > > >
> > > >       if (evlist__create_maps(evlist, target))
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       if (evlist->core.nr_entries > 1) {
> > > >               bool can_sample_identifier = perf_can_sample_identifier();
> > > > @@ -116,25 +116,25 @@ int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
> > > >       evlist__for_each_entry(evlist, counter) {
> > > >               if (evsel__open(counter, evlist->core.user_requested_cpus,
> > > >                               evlist->core.threads) < 0)
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >
> > > >       if (evlist__mmap(evlist, UINT_MAX))
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       evlist__for_each_entry(evlist, counter) {
> > > >               if (evsel__enable(counter))
> > > > -                     goto out_delete_evlist;
> > > > +                     goto out_put_evlist;
> > > >       }
> > > >
> > > >       evlist->thread.done = 0;
> > > >       if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
> > > > -             goto out_delete_evlist;
> > > > +             goto out_put_evlist;
> > > >
> > > >       return 0;
> > > >
> > > > -out_delete_evlist:
> > > > -     evlist__delete(evlist);
> > > > +out_put_evlist:
> > > > +     evlist__put(evlist);
> > > >       evlist = NULL;
> > > >       return -1;
> > > >  }
> > > > @@ -145,5 +145,5 @@ void evlist__stop_sb_thread(struct evlist *evlist)
> > > >               return;
> > > >       evlist->thread.done = 1;
> > > >       pthread_join(evlist->thread.th, NULL);
> > > > -     evlist__delete(evlist);
> > > > +     evlist__put(evlist);
> > > >  }
> > > > --
> > > > 2.51.1.851.g4ebd6896fd-goog

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

* Re: [RFC PATCH v1 12/15] perf evlist: Add reference count
  2025-10-29 21:12         ` Ian Rogers
@ 2025-10-30 13:09           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 22+ messages in thread
From: Arnaldo Carvalho de Melo @ 2025-10-30 13:09 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Suzuki K Poulose, Mike Leach, James Clark, John Garry,
	Will Deacon, Leo Yan, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, Greg Kroah-Hartman,
	Charlie Jenkins, Thomas Falcon, Yicong Yang, Thomas Richter,
	Athira Rajeev, Howard Chu, Song Liu, Dapeng Mi, Levi Yun,
	Zhongqiu Han, Blake Jones, Anubhav Shelat, Chun-Tse Shao,
	Christophe Leroy, Jean-Philippe Romain, Gautam Menghani,
	Dmitry Vyukov, Yang Li, linux-kernel, linux-perf-users,
	Andi Kleen, Weilin Wang

On Wed, Oct 29, 2025 at 02:12:11PM -0700, Ian Rogers wrote:
> On Wed, Oct 29, 2025 at 11:33 AM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> > On Wed, Oct 29, 2025 at 09:56:50AM -0700, Ian Rogers wrote:
> > > On Wed, Oct 29, 2025 at 9:22 AM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:

> > > > On Tue, Oct 28, 2025 at 10:34:10PM -0700, Ian Rogers wrote:
> > > > > This a no-op for most of the perf tool. The reference count is set to
> > > > > 1 at allocation, the put will see the 1, decrement it and perform the
> > > > > delete. The purpose for adding the reference count is for the python
> > > > > code. Prior to this change the python code would clone evlists, but
> > > > > this has issues if events are opened, etc. This change adds a
> > > > > reference count for the evlists and a later change will add it to
> > > > > evsels. The combination is needed for the python code to operate
> > > > > correctly (not hit asserts in the evsel clone), but the changes are
> > > > > broken apart for the sake of smaller patches.

> > > > Looks ok, noisy for all the s/delete/put/ but that is ok, but then you
> > > > are not using the RC_CHK_ACCESS stuff from the get go, why not?

> > > So if I did RC_CHK_ACCESS then every evsel access would need updating,

> > Fair enough, I think it would be informative to have a comment
> > mentioning this near the refcount_t to avoid this question popping up
> > again.
 
> Sgtm. I think we can also add the RC_CHK_ACCESS to evlist as that is a
> boring blob of a thing to pass around.
 
> How are things outside of this? The python changes, how to do the
> process_events callbacks, etc. Any thoughts on the tool API vs the
> script API (stat vs stat_round) ?

I'll try and resume reviewing at that point, but I don't antecipate
problems and like the direction of this work.

- Arnaldo

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

end of thread, other threads:[~2025-10-30 13:09 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-29  5:33 [RFC PATCH v1 00/15] Addition of session API to python module Ian Rogers
2025-10-29  5:33 ` [RFC PATCH v1 01/15] perf arch arm: Sort includes and add missed explicit dependencies Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 02/15] perf arch x86: " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 03/15] perf tests: " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 04/15] perf script: " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 05/15] perf util: " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 06/15] perf python: Add " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 07/15] perf evsel/evlist: Avoid unnecessary #includes Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 08/15] perf maps: Move getting debug_file to verbose path Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 09/15] perf data: Clean up use_stdio and structures Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 10/15] perf python: Add wrapper for perf_data file abstraction Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 11/15] perf python: Add python session abstraction wrapping perf's session Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 12/15] perf evlist: Add reference count Ian Rogers
2025-10-29 16:22   ` Arnaldo Carvalho de Melo
2025-10-29 16:25     ` Arnaldo Carvalho de Melo
2025-10-29 16:56     ` Ian Rogers
2025-10-29 18:33       ` Arnaldo Carvalho de Melo
2025-10-29 21:12         ` Ian Rogers
2025-10-30 13:09           ` Arnaldo Carvalho de Melo
2025-10-29  5:34 ` [RFC PATCH v1 13/15] perf evsel: " Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 14/15] perf python: Add access to evsel and phys_addr in event Ian Rogers
2025-10-29  5:34 ` [RFC PATCH v1 15/15] perf mem-phys-addr.py: Port to standalone application from perf script Ian Rogers

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).