[PATCH v2 3/8] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts

From: Charlie Jenkins
Date: Mon Jul 29 2024 - 12:48:09 EST


From: Shunsuke Nakamura <nakamura.shun@xxxxxxxxxxx>

Introduce perf_{evsel, evlist}__open_opt with extensible structure opts.
The mechanism of the extensible structure opts imitates
tools/lib/bpf/libbpf.h. Currently, only open_flags is supported for the
opts structure.

Signed-off-by: Shunsuke Nakamura <nakamura.shun@xxxxxxxxxxx>
Signed-off-by: Charlie Jenkins <charlie@xxxxxxxxxxxx>
---
tools/lib/perf/Documentation/libperf.txt | 10 ++++++++++
tools/lib/perf/evlist.c | 20 ++++++++++++++++++++
tools/lib/perf/evsel.c | 26 +++++++++++++++++++++++++-
tools/lib/perf/include/perf/evlist.h | 3 +++
tools/lib/perf/include/perf/evsel.h | 23 +++++++++++++++++++++++
tools/lib/perf/libperf.map | 2 ++
6 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
index fcfb9499ef9c..83827b94617a 100644
--- a/tools/lib/perf/Documentation/libperf.txt
+++ b/tools/lib/perf/Documentation/libperf.txt
@@ -132,6 +132,16 @@ SYNOPSIS
};
};

+ struct perf_evsel_open_opts {
+ /* size of this struct, for forward/backward compatibility */
+ size_t sz;
+
+ unsigned long open_flags; /* perf_event_open flags */
+ };
+ #define perf_evsel_open_opts__last_field open_flags
+
+ #define LIBPERF_OPTS(TYPE, NAME, ...)
+
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
void perf_evsel__delete(struct perf_evsel *evsel);
int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c
index c6d67fc9e57e..7aa62f90f13b 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -753,3 +753,23 @@ void perf_evlist__go_system_wide(struct perf_evlist *evlist, struct perf_evsel *
__perf_evlist__propagate_maps(evlist, evsel);
}
}
+
+int perf_evlist__open_opts(struct perf_evlist *evlist,
+ struct perf_evsel_open_opts *opts)
+{
+ struct perf_evsel *evsel;
+ int err;
+
+ perf_evlist__for_each_entry(evlist, evsel) {
+ err = perf_evsel__open_opts(evsel, evsel->cpus,
+ evsel->threads, opts);
+ if (err < 0)
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ perf_evlist__close(evlist);
+ return err;
+}
diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
index c07160953224..96ecf3e5c8b4 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -16,8 +16,13 @@
#include <internal/lib.h>
#include <linux/string.h>
#include <sys/ioctl.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
#include <sys/mman.h>
#include <asm/bug.h>
+#include <tools/opts.h>
+#include "internal.h"

void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
int idx)
@@ -26,6 +31,7 @@ void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
evsel->attr = *attr;
evsel->idx = idx;
evsel->leader = evsel;
+ evsel->open_flags = 0;
}

struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
@@ -160,7 +166,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,

fd = sys_perf_event_open(&evsel->attr,
threads->map[thread].pid,
- cpu, group_fd, 0);
+ cpu, group_fd, evsel->open_flags);

if (fd < 0) {
err = -errno;
@@ -555,3 +561,21 @@ void perf_counts_values__scale(struct perf_counts_values *count,
if (pscaled)
*pscaled = scaled;
}
+
+int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
+ struct perf_thread_map *threads,
+ struct perf_evsel_open_opts *opts)
+{
+ int err = 0;
+
+ if (!OPTS_VALID(opts, perf_evsel_open_opts)) {
+ err = -EINVAL;
+ return err;
+ }
+
+ evsel->open_flags = OPTS_GET(opts, open_flags, 0);
+
+ err = perf_evsel__open(evsel, cpus, threads);
+
+ return err;
+}
diff --git a/tools/lib/perf/include/perf/evlist.h b/tools/lib/perf/include/perf/evlist.h
index e894b770779e..37ac44364d22 100644
--- a/tools/lib/perf/include/perf/evlist.h
+++ b/tools/lib/perf/include/perf/evlist.h
@@ -9,6 +9,7 @@ struct perf_evlist;
struct perf_evsel;
struct perf_cpu_map;
struct perf_thread_map;
+struct perf_evsel_open_opts;

LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist,
struct perf_evsel *evsel);
@@ -48,4 +49,6 @@ LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,

LIBPERF_API void perf_evlist__set_leader(struct perf_evlist *evlist);
LIBPERF_API int perf_evlist__nr_groups(struct perf_evlist *evlist);
+LIBPERF_API int perf_evlist__open_opts(struct perf_evlist *evlist,
+ struct perf_evsel_open_opts *opts);
#endif /* __LIBPERF_EVLIST_H */
diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
index 6f92204075c2..8eb3927f3cd0 100644
--- a/tools/lib/perf/include/perf/evsel.h
+++ b/tools/lib/perf/include/perf/evsel.h
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <perf/core.h>
#include <stdbool.h>
+#include <signal.h>
#include <linux/types.h>

struct perf_evsel;
@@ -25,6 +26,24 @@ struct perf_counts_values {
};
};

+struct perf_evsel_open_opts {
+ /* size of this struct, for forward/backward compatibility */
+ size_t sz;
+
+ unsigned long open_flags; /* perf_event_open flags */
+};
+
+#define perf_evsel_open_opts__last_field open_flags
+
+#define LIBPERF_OPTS(TYPE, NAME, ...) \
+ struct TYPE NAME = ({ \
+ memset(&NAME, 0, sizeof(struct TYPE)); \
+ (struct TYPE) { \
+ .sz = sizeof(struct TYPE), \
+ __VA_ARGS__ \
+ }; \
+ })
+
LIBPERF_API struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel);
LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
@@ -46,5 +65,9 @@ LIBPERF_API struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel
LIBPERF_API struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
LIBPERF_API void perf_counts_values__scale(struct perf_counts_values *count,
bool scale, __s8 *pscaled);
+LIBPERF_API int perf_evsel__open_opts(struct perf_evsel *evsel,
+ struct perf_cpu_map *cpus,
+ struct perf_thread_map *threads,
+ struct perf_evsel_open_opts *opts);

#endif /* __LIBPERF_EVSEL_H */
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index 2aa79b696032..84fed76621cb 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -29,6 +29,7 @@ LIBPERF_0.0.1 {
perf_evsel__enable;
perf_evsel__disable;
perf_evsel__open;
+ perf_evsel__open_opts;
perf_evsel__close;
perf_evsel__mmap;
perf_evsel__munmap;
@@ -40,6 +41,7 @@ LIBPERF_0.0.1 {
perf_evlist__new;
perf_evlist__delete;
perf_evlist__open;
+ perf_evlist__open_opts;
perf_evlist__close;
perf_evlist__enable;
perf_evlist__disable;

--
2.44.0