All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] libperf: Add interface for overflow check of sampling events
@ 2022-04-22  9:38 Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 1/7] libperf: Move 'open_flags' from tools/perf to evsel::open_flags Shunsuke Nakamura
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

This patch series adds interface for overflow check of sampling events
to libperf.

First patch move 'open_flags' from tools/perf to evsel::open_flags.

Second patch introduce perf_{evsel, evlist}__open_opt() with extensible
structure opts.

Third patch add support for overflow handling of sampling events.

Fourth patch adds a interface to check overflowed events.

Fifth patch adds a interface to perform IOC_REFRESH and IOC_PERIOD.

Sixth and seventh patch adds tests.


---
Previous version at:
https://lore.kernel.org/linux-perf-users/20220325043829.224045-1-nakamura.shun@fujitsu.com/

Changes in v1:
 - Move initialization/reference of evsel->open_flags from the first
   patch to the second patch
 - Move signal-related handling and related fields of the opts
   structure from the second patch to the third patch
 - Move _GNU_SOURCE from test-evlist.c to Makefile
 - Delete *_cpu() function
 - Refactor the fourth patch
 - Fix test to use real-time signals instead of standard signals

Changes in RFC v2:
 - Delete perf_evsel__set_close_on_exec() function
 - Introduce perf_{evsel, evlist}__open_opt() with extensible structure
   opts
 - Fix perf_evsel__set_signal() to a internal function
 - Add bool type argument to perf_evsel__check_{fd, fd_cpu}() to indicate
   overflow results


Shunsuke Nakamura (7):
  libperf: Move 'open_flags' from tools/perf to evsel::open_flags
  libperf: Introduce perf_{evsel, evlist}__open_opt with extensible
    struct opts
  libperf: Add support for overflow handling of sampling events
  libperf: Add perf_evsel__has_fd() functions
  libperf: Add perf_evsel__{refresh, period}() functions
  libperf test: Add test_stat_overflow()
  libperf test: Add test_stat_overflow_event()

 tools/lib/perf/Documentation/libperf.txt |  17 +++
 tools/lib/perf/Makefile                  |   1 +
 tools/lib/perf/evlist.c                  |  20 +++
 tools/lib/perf/evsel.c                   | 166 ++++++++++++++++++++++-
 tools/lib/perf/include/internal/evsel.h  |   2 +
 tools/lib/perf/include/perf/evlist.h     |   3 +
 tools/lib/perf/include/perf/evsel.h      |  29 ++++
 tools/lib/perf/internal.h                |  44 ++++++
 tools/lib/perf/libperf.map               |   5 +
 tools/lib/perf/tests/test-evlist.c       | 112 ++++++++++++++-
 tools/lib/perf/tests/test-evsel.c        | 108 +++++++++++++++
 tools/perf/util/evsel.c                  |  16 ++-
 tools/perf/util/evsel.h                  |   1 -
 13 files changed, 508 insertions(+), 16 deletions(-)

-- 
2.25.1


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

* [PATCH 1/7] libperf: Move 'open_flags' from tools/perf to evsel::open_flags
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts Shunsuke Nakamura
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Move evsel::open_flags to perf_evsel::open_flags, so we can move
the open_flags interface to libperf.

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/include/internal/evsel.h |  2 ++
 tools/perf/util/evsel.c                 | 16 +++++++++-------
 tools/perf/util/evsel.h                 |  1 -
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
index cfc9ebd7968e..37a99cf261b3 100644
--- a/tools/lib/perf/include/internal/evsel.h
+++ b/tools/lib/perf/include/internal/evsel.h
@@ -51,6 +51,8 @@ struct perf_evsel {
 	int			 nr_members;
 	bool			 system_wide;
 	int			 idx;
+
+	unsigned long		 open_flags;
 };
 
 void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2a1729e7aee4..92f7a76ca9d5 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1794,9 +1794,9 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,
 	    perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0)
 		return -ENOMEM;
 
-	evsel->open_flags = PERF_FLAG_FD_CLOEXEC;
+	evsel->core.open_flags = PERF_FLAG_FD_CLOEXEC;
 	if (evsel->cgrp)
-		evsel->open_flags |= PERF_FLAG_PID_CGROUP;
+		evsel->core.open_flags |= PERF_FLAG_PID_CGROUP;
 
 	return 0;
 }
@@ -1814,7 +1814,7 @@ static void evsel__disable_missing_features(struct evsel *evsel)
 		evsel->core.attr.clockid = 0;
 	}
 	if (perf_missing_features.cloexec)
-		evsel->open_flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
+		evsel->core.open_flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
 	if (perf_missing_features.mmap2)
 		evsel->core.attr.mmap2 = 0;
 	if (evsel->pmu && evsel->pmu->missing_features.exclude_guest)
@@ -1902,7 +1902,8 @@ bool evsel__detect_missing_features(struct evsel *evsel)
 		perf_missing_features.clockid = true;
 		pr_debug2_peo("switching off use_clockid\n");
 		return true;
-	} else if (!perf_missing_features.cloexec && (evsel->open_flags & PERF_FLAG_FD_CLOEXEC)) {
+	} else if (!perf_missing_features.cloexec &&
+		   (evsel->core.open_flags & PERF_FLAG_FD_CLOEXEC)) {
 		perf_missing_features.cloexec = true;
 		pr_debug2_peo("switching off cloexec flag\n");
 		return true;
@@ -2029,11 +2030,12 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,
 			test_attr__ready();
 
 			pr_debug2_peo("sys_perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx",
-				pid, perf_cpu_map__cpu(cpus, idx).cpu, group_fd, evsel->open_flags);
+				pid, perf_cpu_map__cpu(cpus, idx).cpu, group_fd,
+				evsel->core.open_flags);
 
 			fd = sys_perf_event_open(&evsel->core.attr, pid,
 						perf_cpu_map__cpu(cpus, idx).cpu,
-						group_fd, evsel->open_flags);
+						group_fd, evsel->core.open_flags);
 
 			FD(evsel, idx, thread) = fd;
 
@@ -2050,7 +2052,7 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,
 			if (unlikely(test_attr__enabled)) {
 				test_attr__open(&evsel->core.attr, pid,
 						perf_cpu_map__cpu(cpus, idx),
-						fd, group_fd, evsel->open_flags);
+						fd, group_fd, evsel->core.open_flags);
 			}
 
 			pr_debug2_peo(" = %d\n", fd);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 041b42d33bf5..8a545954eec7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -152,7 +152,6 @@ struct evsel {
 		struct bperf_leader_bpf *leader_skel;
 		struct bperf_follower_bpf *follower_skel;
 	};
-	unsigned long		open_flags;
 	int			precise_ip_original;
 
 	/* for missing_features */
-- 
2.25.1


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

* [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 1/7] libperf: Move 'open_flags' from tools/perf to evsel::open_flags Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-05-20 18:59   ` Namhyung Kim
  2022-04-22  9:38 ` [PATCH 3/7] libperf: Add support for overflow handling of sampling events Shunsuke Nakamura
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

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@fujitsu.com>
---
 tools/lib/perf/Documentation/libperf.txt | 10 ++++++
 tools/lib/perf/evlist.c                  | 20 +++++++++++
 tools/lib/perf/evsel.c                   | 25 +++++++++++++-
 tools/lib/perf/include/perf/evlist.h     |  3 ++
 tools/lib/perf/include/perf/evsel.h      | 22 ++++++++++++
 tools/lib/perf/internal.h                | 44 ++++++++++++++++++++++++
 tools/lib/perf/libperf.map               |  2 ++
 7 files changed, 125 insertions(+), 1 deletion(-)

diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
index a8f1a237931b..6ca91ca94e01 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 a09315538a30..bf9343acb799 100644
--- a/tools/lib/perf/evlist.c
+++ b/tools/lib/perf/evlist.c
@@ -665,3 +665,23 @@ void perf_evlist__set_leader(struct perf_evlist *evlist)
 		__perf_evlist__set_leader(&evlist->entries, first);
 	}
 }
+
+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 210ea7c06ce8..00c0cea43b52 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -16,8 +16,12 @@
 #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 "internal.h"
 
 void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
 		      int idx)
@@ -26,6 +30,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)
@@ -158,7 +163,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)
 				return -errno;
@@ -454,3 +459,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 9ca399d49bb4..6eff1e9b3481 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);
@@ -47,4 +48,6 @@ LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,
 	     (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite))
 
 LIBPERF_API void perf_evlist__set_leader(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 2a9516b42d15..1140df4d2578 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;
@@ -23,6 +24,23 @@ 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,
@@ -43,5 +61,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/internal.h b/tools/lib/perf/internal.h
index 2c27e158de6b..4b91a087ed62 100644
--- a/tools/lib/perf/internal.h
+++ b/tools/lib/perf/internal.h
@@ -20,4 +20,48 @@ do {                            \
 #define pr_debug2(fmt, ...)     __pr(LIBPERF_DEBUG2, fmt, ##__VA_ARGS__)
 #define pr_debug3(fmt, ...)     __pr(LIBPERF_DEBUG3, fmt, ##__VA_ARGS__)
 
+static inline bool libperf_is_mem_zeroed(const char *p, ssize_t len)
+{
+	while (len > 0) {
+		if (*p)
+			return false;
+		p++;
+		len--;
+	}
+	return true;
+}
+
+static inline bool libperf_validate_opts(const char *opts,
+					 size_t opts_sz, size_t user_sz,
+					 const char *type_name)
+{
+	if (user_sz < sizeof(size_t)) {
+		pr_warning("%s size (%zu) is too small\n", type_name, user_sz);
+		return false;
+	}
+	if (!libperf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {
+		pr_warning("%s has non-zero extra bytes\n", type_name);
+		return false;
+	}
+	return true;
+}
+
+#define offsetofend(TYPE, FIELD) \
+	(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
+
+#define OPTS_VALID(opts, type)							\
+	(!(opts) || libperf_validate_opts((const char *)opts,			\
+					  offsetofend(struct type,		\
+						      type##__last_field),	\
+						(opts)->sz, #type))
+#define OPTS_HAS(opts, field) \
+	((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
+#define OPTS_GET(opts, field, fallback_value) \
+	(OPTS_HAS(opts, field) ? (opts)->field : fallback_value)
+#define OPTS_SET(opts, field, value)		\
+	do {					\
+		if (OPTS_HAS(opts, field))	\
+			(opts)->field = value;	\
+	} while (0)
+
 #endif /* __LIBPERF_INTERNAL_H */
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index 190b56ae923a..eeeb3075e092 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -25,6 +25,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;
@@ -36,6 +37,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.25.1


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

* [PATCH 3/7] libperf: Add support for overflow handling of sampling events
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 1/7] libperf: Move 'open_flags' from tools/perf to evsel::open_flags Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-05-20 19:28   ` Namhyung Kim
  2022-04-22  9:38 ` [PATCH 4/7] libperf: Add perf_evsel__has_fd() functions Shunsuke Nakamura
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Extend the fields of the opts structure to set up overflow handling
for sampling events. Also, add processing to set signal handlers in
perf_evsel__open_opts.

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/Documentation/libperf.txt |  6 +-
 tools/lib/perf/Makefile                  |  1 +
 tools/lib/perf/evsel.c                   | 79 ++++++++++++++++++++++++
 tools/lib/perf/include/perf/evsel.h      |  6 +-
 tools/lib/perf/tests/test-evlist.c       |  1 -
 5 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
index 6ca91ca94e01..ec93b1c75ebe 100644
--- a/tools/lib/perf/Documentation/libperf.txt
+++ b/tools/lib/perf/Documentation/libperf.txt
@@ -137,8 +137,12 @@ SYNOPSIS
           size_t sz;
 
           unsigned long open_flags;       /* perf_event_open flags */
+          int flags;                      /* fcntl flags */
+          unsigned int signal;
+          int owner_type;
+          struct sigaction *sig;
   };
-  #define perf_evsel_open_opts__last_field open_flags
+  #define perf_evsel_open_opts__last_field sig
 
   #define LIBPERF_OPTS(TYPE, NAME, ...)
 
diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile
index 21df023a2103..4c8fae193cf5 100644
--- a/tools/lib/perf/Makefile
+++ b/tools/lib/perf/Makefile
@@ -75,6 +75,7 @@ override CFLAGS += -Werror -Wall
 override CFLAGS += -fPIC
 override CFLAGS += $(INCLUDES)
 override CFLAGS += -fvisibility=hidden
+override CFLAGS += -D_GNU_SOURCE
 
 all:
 
diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
index 00c0cea43b52..a289f6c44d7c 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -460,6 +460,79 @@ void perf_counts_values__scale(struct perf_counts_values *count,
 		*pscaled = scaled;
 }
 
+static int perf_evsel__run_fcntl(struct perf_evsel *evsel,
+				 unsigned int cmd, unsigned long arg,
+				 int cpu_map_idx)
+{
+	int thread;
+
+	for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
+		int err;
+		int *fd = FD(evsel, cpu_map_idx, thread);
+
+		if (!fd || *fd < 0)
+			return -1;
+
+		err = fcntl(*fd, cmd, arg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int perf_evsel__set_signal_handler(struct perf_evsel *evsel,
+					  struct perf_evsel_open_opts *opts)
+{
+	unsigned int flags;
+	unsigned int signal;
+	struct f_owner_ex owner;
+	struct sigaction *sig;
+	int cpu_map_idx;
+	int err = 0;
+
+	flags = OPTS_GET(opts, flags, (O_RDWR | O_NONBLOCK | O_ASYNC));
+	signal = OPTS_GET(opts, signal, SIGIO);
+	owner.type = OPTS_GET(opts, owner_type, F_OWNER_PID);
+	sig = OPTS_GET(opts, sig, NULL);
+
+	if (flags == 0 && signal == 0 && !owner.type == 0 && sig == 0)
+		return err;
+
+	err = sigaction(signal, sig, NULL);
+	if (err)
+		return err;
+
+	switch (owner.type) {
+	case F_OWNER_PID:
+		owner.pid = getpid();
+		break;
+	case F_OWNER_TID:
+		owner.pid = syscall(SYS_gettid);
+		break;
+	case F_OWNER_PGRP:
+	default:
+		return -1;
+	}
+
+	for (cpu_map_idx = 0; cpu_map_idx < xyarray__max_x(evsel->fd); cpu_map_idx++) {
+		err = perf_evsel__run_fcntl(evsel, F_SETFL, flags, cpu_map_idx);
+		if (err)
+			return err;
+
+		err = perf_evsel__run_fcntl(evsel, F_SETSIG, signal, cpu_map_idx);
+		if (err)
+			return err;
+
+		err = perf_evsel__run_fcntl(evsel, F_SETOWN_EX,
+					    (unsigned long)&owner, cpu_map_idx);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
 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)
@@ -474,6 +547,12 @@ int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
 	evsel->open_flags = OPTS_GET(opts, open_flags, 0);
 
 	err = perf_evsel__open(evsel, cpus, threads);
+	if (err)
+		return err;
+
+	err = perf_evsel__set_signal_handler(evsel, opts);
+	if (err)
+		return err;
 
 	return err;
 }
diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
index 1140df4d2578..50662babfe97 100644
--- a/tools/lib/perf/include/perf/evsel.h
+++ b/tools/lib/perf/include/perf/evsel.h
@@ -29,8 +29,12 @@ struct perf_evsel_open_opts {
 	size_t sz;
 
 	unsigned long open_flags;	/* perf_event_open flags */
+	int flags;			/* fcntl flags */
+	unsigned int signal;
+	int owner_type;
+	struct sigaction *sig;
 };
-#define perf_evsel_open_opts__last_field open_flags
+#define perf_evsel_open_opts__last_field sig
 
 #define LIBPERF_OPTS(TYPE, NAME, ...)			\
 	struct TYPE NAME = ({				\
diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c
index ed616fc19b4f..d8f9493cd4d1 100644
--- a/tools/lib/perf/tests/test-evlist.c
+++ b/tools/lib/perf/tests/test-evlist.c
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: GPL-2.0
-#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
 #include <inttypes.h>
 #include <sched.h>
 #include <stdio.h>
-- 
2.25.1


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

* [PATCH 4/7] libperf: Add perf_evsel__has_fd() functions
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
                   ` (2 preceding siblings ...)
  2022-04-22  9:38 ` [PATCH 3/7] libperf: Add support for overflow handling of sampling events Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions Shunsuke Nakamura
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Add the following functions:

  perf_evsel__has_fd

to check for perf events with the file descriptor specified in the
argument.
This function can be used in signal handlers to check overflow.

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/Documentation/libperf.txt |  1 +
 tools/lib/perf/evsel.c                   | 18 ++++++++++++++++++
 tools/lib/perf/include/perf/evsel.h      |  1 +
 tools/lib/perf/libperf.map               |  1 +
 4 files changed, 21 insertions(+)

diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
index ec93b1c75ebe..bc7881348c76 100644
--- a/tools/lib/perf/Documentation/libperf.txt
+++ b/tools/lib/perf/Documentation/libperf.txt
@@ -161,6 +161,7 @@ SYNOPSIS
   int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
   int perf_evsel__disable(struct perf_evsel *evsel);
   int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
+  bool perf_evsel__has_fd(struct perf_evsel *evsel, int fd);
   struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
   struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel);
   struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
index a289f6c44d7c..446934c0e5e5 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -556,3 +556,21 @@ int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
 
 	return err;
 }
+
+bool perf_evsel__has_fd(struct perf_evsel *evsel, int fd)
+{
+	int cpu_map_idx;
+	int thread;
+	int *evsel_fd;
+
+	for (cpu_map_idx = 0; cpu_map_idx < xyarray__max_x(evsel->fd); ++cpu_map_idx) {
+		for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
+			evsel_fd = FD(evsel, cpu_map_idx, thread);
+
+			if (fd == *evsel_fd)
+				return true;
+		}
+	}
+
+	return false;
+}
diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
index 50662babfe97..19a7993d9021 100644
--- a/tools/lib/perf/include/perf/evsel.h
+++ b/tools/lib/perf/include/perf/evsel.h
@@ -69,5 +69,6 @@ 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);
+LIBPERF_API bool perf_evsel__has_fd(struct perf_evsel *evsel, int fd);
 
 #endif /* __LIBPERF_EVSEL_H */
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index eeeb3075e092..b2ace16bbc32 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -34,6 +34,7 @@ LIBPERF_0.0.1 {
 		perf_evsel__cpus;
 		perf_evsel__threads;
 		perf_evsel__attr;
+		perf_evsel__has_fd;
 		perf_evlist__new;
 		perf_evlist__delete;
 		perf_evlist__open;
-- 
2.25.1


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

* [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
                   ` (3 preceding siblings ...)
  2022-04-22  9:38 ` [PATCH 4/7] libperf: Add perf_evsel__has_fd() functions Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-05-20 19:38   ` Namhyung Kim
  2022-04-22  9:38 ` [PATCH 6/7] libperf test: Add test_stat_overflow() Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 7/7] libperf test: Add test_stat_overflow_event() Shunsuke Nakamura
  6 siblings, 1 reply; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Add the following functions:

  perf_evsel__refresh()
  perf_evsel__period()

to set the over flow limit and period.

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/Documentation/libperf.txt |  2 ++
 tools/lib/perf/evsel.c                   | 44 ++++++++++++++++++++----
 tools/lib/perf/include/perf/evsel.h      |  2 ++
 tools/lib/perf/libperf.map               |  2 ++
 4 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
index bc7881348c76..773224a96bd3 100644
--- a/tools/lib/perf/Documentation/libperf.txt
+++ b/tools/lib/perf/Documentation/libperf.txt
@@ -162,6 +162,8 @@ SYNOPSIS
   int perf_evsel__disable(struct perf_evsel *evsel);
   int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
   bool perf_evsel__has_fd(struct perf_evsel *evsel, int fd);
+  int perf_evsel__refresh(struct perf_evsel *evsel, int refresh);
+  int perf_evsel__period(struct perf_evsel *evsel, int period);
   struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
   struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel);
   struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
index 446934c0e5e5..578ae0050036 100644
--- a/tools/lib/perf/evsel.c
+++ b/tools/lib/perf/evsel.c
@@ -334,7 +334,7 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
 }
 
 static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
-				 int ioc,  void *arg,
+				 int ioc, unsigned long arg,
 				 int cpu_map_idx)
 {
 	int thread;
@@ -357,7 +357,7 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
 
 int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
 {
-	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
+	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0, cpu_map_idx);
 }
 
 int perf_evsel__enable(struct perf_evsel *evsel)
@@ -366,13 +366,13 @@ int perf_evsel__enable(struct perf_evsel *evsel)
 	int err = 0;
 
 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
-		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
+		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0, i);
 	return err;
 }
 
 int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
 {
-	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
+	return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0, cpu_map_idx);
 }
 
 int perf_evsel__disable(struct perf_evsel *evsel)
@@ -381,7 +381,39 @@ int perf_evsel__disable(struct perf_evsel *evsel)
 	int err = 0;
 
 	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
-		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
+		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0, i);
+	return err;
+}
+
+int perf_evsel__refresh(struct perf_evsel *evsel, int refresh)
+{
+	int i;
+	int err = 0;
+
+	for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
+		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_REFRESH, refresh, i);
+	return err;
+}
+
+int perf_evsel__period(struct perf_evsel *evsel, __u64 period)
+{
+	struct perf_event_attr *attr;
+	int i;
+	int err = 0;
+
+	attr = perf_evsel__attr(evsel);
+	if (!attr)
+		return -EINVAL;
+
+	for (i = 0; i < xyarray__max_x(evsel->fd); i++) {
+		err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_PERIOD,
+					    (unsigned long)&period, i);
+		if (err)
+			return err;
+	}
+
+	attr->sample_period = period;
+
 	return err;
 }
 
@@ -392,7 +424,7 @@ int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
 	for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
 		err = perf_evsel__run_ioctl(evsel,
 				     PERF_EVENT_IOC_SET_FILTER,
-				     (void *)filter, i);
+				     (unsigned long)filter, i);
 	return err;
 }
 
diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
index 19a7993d9021..2c5e52c17d28 100644
--- a/tools/lib/perf/include/perf/evsel.h
+++ b/tools/lib/perf/include/perf/evsel.h
@@ -60,6 +60,8 @@ LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel);
 LIBPERF_API int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
 LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel);
 LIBPERF_API int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
+LIBPERF_API int perf_evsel__refresh(struct perf_evsel *evsel, int refresh);
+LIBPERF_API int perf_evsel__period(struct perf_evsel *evsel, __u64 period);
 LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
 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);
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index b2ace16bbc32..d97e208c5be8 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -31,6 +31,8 @@ LIBPERF_0.0.1 {
 		perf_evsel__munmap;
 		perf_evsel__mmap_base;
 		perf_evsel__read;
+		perf_evsel__refresh;
+		perf_evsel__period;
 		perf_evsel__cpus;
 		perf_evsel__threads;
 		perf_evsel__attr;
-- 
2.25.1


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

* [PATCH 6/7] libperf test: Add test_stat_overflow()
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
                   ` (4 preceding siblings ...)
  2022-04-22  9:38 ` [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  2022-04-22  9:38 ` [PATCH 7/7] libperf test: Add test_stat_overflow_event() Shunsuke Nakamura
  6 siblings, 0 replies; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Added overflow test using refresh and period.

Confirmation
 - That the overflow occurs the number of times specified by
   perf_evse__refresh()
 - That the period can be updated by perf_evsel__period()

Committer testing:

  $ sudo make tests -C ./tools/lib/perf V=1
  make: Entering directory '/home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/perf'
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=. obj=libperf
  make -C /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/api/ O= libapi.a
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./fd obj=libapi
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./fs obj=libapi
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=. obj=tests
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./tests obj=tests
  running static:
  - running tests/test-cpumap.c...OK
  - running tests/test-threadmap.c...OK
  - running tests/test-evlist.c...

  <SNIP>

  OK
  - running tests/test-evsel.c...

  <SNIP>

          period = 1000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 2000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 1000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 2000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
  OK
  running dynamic:
  - running tests/test-cpumap.c...OK
  - running tests/test-threadmap.c...OK
  - running tests/test-evlist.c...

  <SNIP>

  OK
  - running tests/test-evsel.c...

  <SNIP>

          period = 1000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 2000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 1000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
          period = 2000000
          overflow limit = 3, overflow count = 3, POLL_IN = 2, POLL_UP = 1, other signal event = 0
  OK
  make: Leaving directory '/home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/perf'

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/tests/test-evsel.c | 108 ++++++++++++++++++++++++++++++
 1 file changed, 108 insertions(+)

diff --git a/tools/lib/perf/tests/test-evsel.c b/tools/lib/perf/tests/test-evsel.c
index 89be89afb24d..4de5d5554836 100644
--- a/tools/lib/perf/tests/test-evsel.c
+++ b/tools/lib/perf/tests/test-evsel.c
@@ -1,6 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <inttypes.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <linux/perf_event.h>
 #include <perf/cpumap.h>
 #include <perf/threadmap.h>
@@ -8,6 +13,15 @@
 #include <internal/tests.h>
 #include "tests.h"
 
+#define WAIT_COUNT 10000000UL
+static struct signal_counts {
+	int in;
+	int hup;
+	int others;
+	int overflow;
+} sig_count;
+static struct perf_evsel *s_evsel;
+
 static int libperf_print(enum libperf_print_level level,
 			 const char *fmt, va_list ap)
 {
@@ -189,6 +203,98 @@ static int test_stat_user_read(int event)
 	return 0;
 }
 
+static void sig_handler(int signo, siginfo_t *info, void *uc)
+{
+	switch (info->si_code) {
+	case POLL_IN:
+		sig_count.in++;
+		break;
+	case POLL_HUP:
+		sig_count.hup++;
+		break;
+	default:
+		sig_count.others++;
+	}
+
+	sig_count.overflow++;
+}
+
+static int test_stat_overflow(int owner)
+{
+	static struct sigaction sig;
+	u64 period = 1000000;
+	int overflow_limit = 3;
+
+	struct perf_thread_map *threads;
+	struct perf_event_attr attr = {
+		.type           = PERF_TYPE_SOFTWARE,
+		.config         = PERF_COUNT_SW_TASK_CLOCK,
+		.sample_type    = PERF_SAMPLE_PERIOD,
+		.sample_period  = period,
+		.disabled       = 1,
+	};
+	struct perf_event_attr *tmp_attr;
+	int err = 0, i;
+
+	LIBPERF_OPTS(perf_evsel_open_opts, opts,
+		     .open_flags = PERF_FLAG_FD_CLOEXEC,
+		     .flags	 = (O_RDWR | O_NONBLOCK | O_ASYNC),
+		     .signal	 = SIGRTMIN + 1,
+		     .owner_type = owner,
+		     .sig	 = &sig);
+
+	/* setup signal handler */
+	memset(&sig, 0, sizeof(struct sigaction));
+	sig.sa_sigaction = (void *)sig_handler;
+	sig.sa_flags = SA_SIGINFO;
+
+	threads = perf_thread_map__new_dummy();
+	__T("failed to create threads", threads);
+
+	perf_thread_map__set_pid(threads, 0, 0);
+
+	s_evsel = perf_evsel__new(&attr);
+	__T("failed to create evsel", s_evsel);
+
+	err = perf_evsel__open_opts(s_evsel, NULL, threads, &opts);
+	__T("failed to open evsel", err == 0);
+
+	for (i = 0; i < 2; i++) {
+		volatile unsigned int wait_count = WAIT_COUNT;
+
+		sig_count.in = 0;
+		sig_count.hup = 0;
+		sig_count.others = 0;
+		sig_count.overflow = 0;
+
+		period = period << i;
+		err = perf_evsel__period(s_evsel, period);
+		__T("failed to period evsel", err == 0);
+
+		tmp_attr = perf_evsel__attr(s_evsel);
+		__T_VERBOSE("\tperiod = %llu\n", tmp_attr->sample_period);
+
+		err = perf_evsel__refresh(s_evsel, overflow_limit);
+		__T("failed to refresh evsel", err == 0);
+
+		while (wait_count--)
+			;
+
+		__T_VERBOSE("\toverflow limit = %d, overflow count = %d, ",
+			    overflow_limit, sig_count.overflow);
+		__T_VERBOSE("POLL_IN = %d, POLL_HUP = %d, other signal event = %d\n",
+			    sig_count.in, sig_count.hup, sig_count.others);
+
+		__T("failed to overflow count", overflow_limit == sig_count.overflow);
+	}
+
+	perf_evsel__close(s_evsel);
+	perf_evsel__delete(s_evsel);
+	perf_thread_map__put(threads);
+
+	return 0;
+}
+
 int test_evsel(int argc, char **argv)
 {
 	__T_START;
@@ -200,6 +306,8 @@ int test_evsel(int argc, char **argv)
 	test_stat_thread_enable();
 	test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
 	test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
+	test_stat_overflow(F_OWNER_PID);
+	test_stat_overflow(F_OWNER_TID);
 
 	__T_END;
 	return tests_failed == 0 ? 0 : -1;
-- 
2.25.1


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

* [PATCH 7/7] libperf test: Add test_stat_overflow_event()
  2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
                   ` (5 preceding siblings ...)
  2022-04-22  9:38 ` [PATCH 6/7] libperf test: Add test_stat_overflow() Shunsuke Nakamura
@ 2022-04-22  9:38 ` Shunsuke Nakamura
  6 siblings, 0 replies; 12+ messages in thread
From: Shunsuke Nakamura @ 2022-04-22  9:38 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa, namhyung
  Cc: linux-kernel, linux-perf-users

Add a test to check overflowed events.

Committer testing:

  $ sudo make tests -C ./tools/lib/perf V=1
  make: Entering directory '/home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/perf'
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=. obj=libperf
  make -C /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/api/ O= libapi.a
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./fd obj=libapi
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./fs obj=libapi
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=. obj=tests
  make -f /home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/build/Makefile.build dir=./tests obj=tests
  running static:
  - running tests/test-cpumap.c...OK
  - running tests/test-threadmap.c...OK
  - running tests/test-evlist.c...

  <SNIP>

  Event  0 -- overflow flag = 0x1, POLL_UP = 1, other signal event = 0
  Event  1 -- overflow flag = 0x2, POLL_UP = 1, other signal event = 0
  Event  2 -- overflow flag = 0x4, POLL_UP = 1, other signal event = 0
  Event  3 -- overflow flag = 0x8, POLL_UP = 1, other signal event = 0
  OK
  - running tests/test-evsel.c...

  <SNIP>

  OK
  running dynamic:
  - running tests/test-cpumap.c...OK
  - running tests/test-threadmap.c...OK
  - running tests/test-evlist.c...

  <SNIP>

  Event  0 -- overflow flag = 0x1, POLL_UP = 1, other signal event = 0
  Event  1 -- overflow flag = 0x2, POLL_UP = 1, other signal event = 0
  Event  2 -- overflow flag = 0x4, POLL_UP = 1, other signal event = 0
  Event  3 -- overflow flag = 0x8, POLL_UP = 1, other signal event = 0
  OK
  - running tests/test-evsel.c...

  <SNIP>

  OK
  make: Leaving directory '/home/nakamura/build_work/build_kernel/linux-kernel/linux/tools/lib/perf'

Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
---
 tools/lib/perf/tests/test-evlist.c | 111 +++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c
index d8f9493cd4d1..587364851432 100644
--- a/tools/lib/perf/tests/test-evlist.c
+++ b/tools/lib/perf/tests/test-evlist.c
@@ -5,6 +5,8 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
 #include <linux/perf_event.h>
 #include <linux/limits.h>
 #include <sys/types.h>
@@ -24,6 +26,13 @@
 #define EVENT_NUM 15
 #define WAIT_COUNT 100000000UL
 
+static unsigned int overflow_flag;
+static struct signal_counts {
+	int hup;
+	int others;
+} sig_count;
+static struct perf_evlist *s_evlist;
+
 static int libperf_print(enum libperf_print_level level,
 			 const char *fmt, va_list ap)
 {
@@ -570,6 +579,107 @@ static int test_stat_multiplexing(void)
 	return 0;
 }
 
+static void sig_handler(int signo, siginfo_t *info, void *uc)
+{
+	struct perf_evsel *evsel;
+	int i = 0;
+
+	perf_evlist__for_each_evsel(s_evlist, evsel) {
+		if (perf_evsel__has_fd(evsel, info->si_fd)) {
+			if (info->si_code == POLL_HUP)
+				sig_count.hup++;
+			else
+				sig_count.others++;
+
+			overflow_flag = (1U << i);
+			return;
+		}
+		i++;
+	}
+
+	__T_VERBOSE("Failed to get fd of overflowed event");
+}
+
+static int test_stat_overflow_event(void)
+{
+	static struct sigaction sig;
+
+	struct perf_thread_map *threads;
+	struct perf_evsel *evsel;
+	struct perf_event_attr attr = {
+		.type		= PERF_TYPE_SOFTWARE,
+		.config		= PERF_COUNT_SW_CPU_CLOCK,
+		.sample_type	= PERF_SAMPLE_PERIOD,
+		.sample_period	= 100000,
+		.disabled	= 1,
+	};
+	int err, i, event_num = 4;
+
+	LIBPERF_OPTS(perf_evsel_open_opts, opts,
+		     .open_flags = PERF_FLAG_FD_CLOEXEC,
+		     .flags	 = (O_RDWR | O_NONBLOCK | O_ASYNC),
+		     .signal	 = SIGRTMIN + 1,
+		     .owner_type = F_OWNER_PID,
+		     .sig	 = &sig);
+
+	/* setup signal handler */
+	memset(&sig, 0, sizeof(struct sigaction));
+	sig.sa_sigaction = (void *)sig_handler;
+	sig.sa_flags = SA_SIGINFO;
+
+	threads = perf_thread_map__new_dummy();
+	__T("failed to create threads", threads);
+
+	perf_thread_map__set_pid(threads, 0, 0);
+
+	s_evlist = perf_evlist__new();
+	__T("failed to create evlist", s_evlist);
+
+	for (i = 0; i < event_num; i++) {
+		evsel = perf_evsel__new(&attr);
+		__T("failed to create evsel", evsel);
+
+		perf_evlist__add(s_evlist, evsel);
+	}
+
+	perf_evlist__set_maps(s_evlist, NULL, threads);
+
+	err = perf_evlist__open_opts(s_evlist, &opts);
+	__T("failed to open evlist", err == 0);
+
+	i = 0;
+	perf_evlist__for_each_evsel(s_evlist, evsel) {
+		volatile unsigned int wait_count = WAIT_COUNT;
+
+		overflow_flag = 0;
+		sig_count.hup = 0;
+		sig_count.others = 0;
+
+		err = perf_evsel__refresh(evsel, 1);
+		__T("failed to refresh evsel", err == 0);
+
+		while (wait_count--)
+			;
+
+		__T_VERBOSE("Event %2d -- overflow flag = %#x, ",
+			    i, overflow_flag);
+		__T_VERBOSE("POLL_HUP = %d, other signal event = %d\n",
+			    sig_count.hup, sig_count.others);
+
+		__T("unexpected event overflow detected", overflow_flag && (1U << i));
+		__T("unexpected signal event detected",
+		    sig_count.hup == 1 && sig_count.others == 0);
+
+		i++;
+	}
+
+	perf_evlist__close(s_evlist);
+	perf_evlist__delete(s_evlist);
+	perf_thread_map__put(threads);
+
+	return 0;
+}
+
 int test_evlist(int argc, char **argv)
 {
 	__T_START;
@@ -582,6 +692,7 @@ int test_evlist(int argc, char **argv)
 	test_mmap_thread();
 	test_mmap_cpus();
 	test_stat_multiplexing();
+	test_stat_overflow_event();
 
 	__T_END;
 	return tests_failed == 0 ? 0 : -1;
-- 
2.25.1


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

* Re: [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts
  2022-04-22  9:38 ` [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts Shunsuke Nakamura
@ 2022-05-20 18:59   ` Namhyung Kim
  0 siblings, 0 replies; 12+ messages in thread
From: Namhyung Kim @ 2022-05-20 18:59 UTC (permalink / raw)
  To: Shunsuke Nakamura
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, linux-kernel,
	linux-perf-users

Hello,

On Fri, Apr 22, 2022 at 2:44 AM Shunsuke Nakamura
<nakamura.shun@fujitsu.com> wrote:
>
> 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@fujitsu.com>
> ---
[SNIP]
> diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
> index 210ea7c06ce8..00c0cea43b52 100644
> --- a/tools/lib/perf/evsel.c
> +++ b/tools/lib/perf/evsel.c
> @@ -16,8 +16,12 @@
>  #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 "internal.h"
>
>  void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
>                       int idx)
> @@ -26,6 +30,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;

In general, you don't need to reset it to zero as it's allocated with
zalloc().

>  }
>
[SNIP]
> diff --git a/tools/lib/perf/internal.h b/tools/lib/perf/internal.h
> index 2c27e158de6b..4b91a087ed62 100644
> --- a/tools/lib/perf/internal.h
> +++ b/tools/lib/perf/internal.h
> @@ -20,4 +20,48 @@ do {                            \
>  #define pr_debug2(fmt, ...)     __pr(LIBPERF_DEBUG2, fmt, ##__VA_ARGS__)
>  #define pr_debug3(fmt, ...)     __pr(LIBPERF_DEBUG3, fmt, ##__VA_ARGS__)
>
> +static inline bool libperf_is_mem_zeroed(const char *p, ssize_t len)
> +{
> +       while (len > 0) {
> +               if (*p)
> +                       return false;
> +               p++;
> +               len--;
> +       }
> +       return true;
> +}
> +
> +static inline bool libperf_validate_opts(const char *opts,
> +                                        size_t opts_sz, size_t user_sz,
> +                                        const char *type_name)
> +{
> +       if (user_sz < sizeof(size_t)) {
> +               pr_warning("%s size (%zu) is too small\n", type_name, user_sz);
> +               return false;
> +       }
> +       if (!libperf_is_mem_zeroed(opts + opts_sz, (ssize_t)user_sz - opts_sz)) {

I don't think the cast is necessary since it'll be promoted again
to size_t due to opts_sz.  Instead, we can check if user_sz is
greater than opts_sz explicitly and call the function.

> +               pr_warning("%s has non-zero extra bytes\n", type_name);
> +               return false;
> +       }
> +       return true;
> +}
> +
> +#define offsetofend(TYPE, FIELD) \
> +       (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD))
> +
> +#define OPTS_VALID(opts, type)                                                 \
> +       (!(opts) || libperf_validate_opts((const char *)opts,                   \
> +                                         offsetofend(struct type,              \
> +                                                     type##__last_field),      \
> +                                               (opts)->sz, #type))
> +#define OPTS_HAS(opts, field) \
> +       ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field))
> +#define OPTS_GET(opts, field, fallback_value) \
> +       (OPTS_HAS(opts, field) ? (opts)->field : fallback_value)

It'd be nice if you add a blank line between the macros.

Thanks,
Namhyung


> +#define OPTS_SET(opts, field, value)           \
> +       do {                                    \
> +               if (OPTS_HAS(opts, field))      \
> +                       (opts)->field = value;  \
> +       } while (0)
> +
>  #endif /* __LIBPERF_INTERNAL_H */
> diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
> index 190b56ae923a..eeeb3075e092 100644
> --- a/tools/lib/perf/libperf.map
> +++ b/tools/lib/perf/libperf.map
> @@ -25,6 +25,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;
> @@ -36,6 +37,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.25.1
>

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

* Re: [PATCH 3/7] libperf: Add support for overflow handling of sampling events
  2022-04-22  9:38 ` [PATCH 3/7] libperf: Add support for overflow handling of sampling events Shunsuke Nakamura
@ 2022-05-20 19:28   ` Namhyung Kim
  0 siblings, 0 replies; 12+ messages in thread
From: Namhyung Kim @ 2022-05-20 19:28 UTC (permalink / raw)
  To: Shunsuke Nakamura
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, linux-kernel,
	linux-perf-users

On Fri, Apr 22, 2022 at 2:44 AM Shunsuke Nakamura
<nakamura.shun@fujitsu.com> wrote:
>
> Extend the fields of the opts structure to set up overflow handling
> for sampling events. Also, add processing to set signal handlers in
> perf_evsel__open_opts.
>
> Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
> ---
>  tools/lib/perf/Documentation/libperf.txt |  6 +-
>  tools/lib/perf/Makefile                  |  1 +
>  tools/lib/perf/evsel.c                   | 79 ++++++++++++++++++++++++
>  tools/lib/perf/include/perf/evsel.h      |  6 +-
>  tools/lib/perf/tests/test-evlist.c       |  1 -
>  5 files changed, 90 insertions(+), 3 deletions(-)
>
> diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
> index 6ca91ca94e01..ec93b1c75ebe 100644
> --- a/tools/lib/perf/Documentation/libperf.txt
> +++ b/tools/lib/perf/Documentation/libperf.txt
> @@ -137,8 +137,12 @@ SYNOPSIS
>            size_t sz;
>
>            unsigned long open_flags;       /* perf_event_open flags */
> +          int flags;                      /* fcntl flags */

What about just rename it to fcntl_flags ?

> +          unsigned int signal;

int ?

> +          int owner_type;

Please add a comment that it's for F_SETOWN_EX.

> +          struct sigaction *sig;
>    };
> -  #define perf_evsel_open_opts__last_field open_flags
> +  #define perf_evsel_open_opts__last_field sig
>
>    #define LIBPERF_OPTS(TYPE, NAME, ...)
>
> diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile
> index 21df023a2103..4c8fae193cf5 100644
> --- a/tools/lib/perf/Makefile
> +++ b/tools/lib/perf/Makefile
> @@ -75,6 +75,7 @@ override CFLAGS += -Werror -Wall
>  override CFLAGS += -fPIC
>  override CFLAGS += $(INCLUDES)
>  override CFLAGS += -fvisibility=hidden
> +override CFLAGS += -D_GNU_SOURCE
>
>  all:
>
> diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
> index 00c0cea43b52..a289f6c44d7c 100644
> --- a/tools/lib/perf/evsel.c
> +++ b/tools/lib/perf/evsel.c
> @@ -460,6 +460,79 @@ void perf_counts_values__scale(struct perf_counts_values *count,
>                 *pscaled = scaled;
>  }
>
> +static int perf_evsel__run_fcntl(struct perf_evsel *evsel,
> +                                unsigned int cmd, unsigned long arg,
> +                                int cpu_map_idx)

I think it'd be better to have _cpu suffix in the function name
as it handles on the specific cpu.

> +{
> +       int thread;
> +
> +       for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
> +               int err;
> +               int *fd = FD(evsel, cpu_map_idx, thread);
> +
> +               if (!fd || *fd < 0)
> +                       return -1;
> +
> +               err = fcntl(*fd, cmd, arg);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return 0;
> +}
> +
> +static int perf_evsel__set_signal_handler(struct perf_evsel *evsel,
> +                                         struct perf_evsel_open_opts *opts)
> +{
> +       unsigned int flags;
> +       unsigned int signal;
> +       struct f_owner_ex owner;
> +       struct sigaction *sig;

It can be confused with the signal number, how about sigact?


> +       int cpu_map_idx;
> +       int err = 0;
> +
> +       flags = OPTS_GET(opts, flags, (O_RDWR | O_NONBLOCK | O_ASYNC));
> +       signal = OPTS_GET(opts, signal, SIGIO);
> +       owner.type = OPTS_GET(opts, owner_type, F_OWNER_PID);
> +       sig = OPTS_GET(opts, sig, NULL);
> +
> +       if (flags == 0 && signal == 0 && !owner.type == 0 && sig == 0)

You man want to check owner.type without "!".

> +               return err;
> +
> +       err = sigaction(signal, sig, NULL);
> +       if (err)
> +               return err;
> +
> +       switch (owner.type) {
> +       case F_OWNER_PID:
> +               owner.pid = getpid();
> +               break;
> +       case F_OWNER_TID:
> +               owner.pid = syscall(SYS_gettid);
> +               break;
> +       case F_OWNER_PGRP:
> +       default:
> +               return -1;
> +       }
> +
> +       for (cpu_map_idx = 0; cpu_map_idx < xyarray__max_x(evsel->fd); cpu_map_idx++) {
> +               err = perf_evsel__run_fcntl(evsel, F_SETFL, flags, cpu_map_idx);
> +               if (err)
> +                       return err;
> +
> +               err = perf_evsel__run_fcntl(evsel, F_SETSIG, signal, cpu_map_idx);
> +               if (err)
> +                       return err;
> +
> +               err = perf_evsel__run_fcntl(evsel, F_SETOWN_EX,
> +                                           (unsigned long)&owner, cpu_map_idx);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return err;
> +}
> +
>  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)
> @@ -474,6 +547,12 @@ int perf_evsel__open_opts(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
>         evsel->open_flags = OPTS_GET(opts, open_flags, 0);
>
>         err = perf_evsel__open(evsel, cpus, threads);
> +       if (err)
> +               return err;
> +
> +       err = perf_evsel__set_signal_handler(evsel, opts);
> +       if (err)
> +               return err;
>
>         return err;
>  }
> diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
> index 1140df4d2578..50662babfe97 100644
> --- a/tools/lib/perf/include/perf/evsel.h
> +++ b/tools/lib/perf/include/perf/evsel.h
> @@ -29,8 +29,12 @@ struct perf_evsel_open_opts {
>         size_t sz;
>
>         unsigned long open_flags;       /* perf_event_open flags */
> +       int flags;                      /* fcntl flags */
> +       unsigned int signal;
> +       int owner_type;
> +       struct sigaction *sig;
>  };
> -#define perf_evsel_open_opts__last_field open_flags
> +#define perf_evsel_open_opts__last_field sig
>
>  #define LIBPERF_OPTS(TYPE, NAME, ...)                  \
>         struct TYPE NAME = ({                           \
> diff --git a/tools/lib/perf/tests/test-evlist.c b/tools/lib/perf/tests/test-evlist.c
> index ed616fc19b4f..d8f9493cd4d1 100644
> --- a/tools/lib/perf/tests/test-evlist.c
> +++ b/tools/lib/perf/tests/test-evlist.c
> @@ -1,5 +1,4 @@
>  // SPDX-License-Identifier: GPL-2.0
> -#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)

Could be in a separate change.

Thanks,
Namhyung


>  #include <inttypes.h>
>  #include <sched.h>
>  #include <stdio.h>
> --
> 2.25.1
>

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

* Re: [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions
  2022-04-22  9:38 ` [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions Shunsuke Nakamura
@ 2022-05-20 19:38   ` Namhyung Kim
  0 siblings, 0 replies; 12+ messages in thread
From: Namhyung Kim @ 2022-05-20 19:38 UTC (permalink / raw)
  To: Shunsuke Nakamura
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, linux-kernel,
	linux-perf-users

On Fri, Apr 22, 2022 at 2:45 AM Shunsuke Nakamura
<nakamura.shun@fujitsu.com> wrote:
>
> Add the following functions:
>
>   perf_evsel__refresh()
>   perf_evsel__period()
>
> to set the over flow limit and period.
>
> Signed-off-by: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
> ---
>  tools/lib/perf/Documentation/libperf.txt |  2 ++
>  tools/lib/perf/evsel.c                   | 44 ++++++++++++++++++++----
>  tools/lib/perf/include/perf/evsel.h      |  2 ++
>  tools/lib/perf/libperf.map               |  2 ++
>  4 files changed, 44 insertions(+), 6 deletions(-)
>
> diff --git a/tools/lib/perf/Documentation/libperf.txt b/tools/lib/perf/Documentation/libperf.txt
> index bc7881348c76..773224a96bd3 100644
> --- a/tools/lib/perf/Documentation/libperf.txt
> +++ b/tools/lib/perf/Documentation/libperf.txt
> @@ -162,6 +162,8 @@ SYNOPSIS
>    int perf_evsel__disable(struct perf_evsel *evsel);
>    int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
>    bool perf_evsel__has_fd(struct perf_evsel *evsel, int fd);
> +  int perf_evsel__refresh(struct perf_evsel *evsel, int refresh);
> +  int perf_evsel__period(struct perf_evsel *evsel, int period);
>    struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
>    struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel);
>    struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel);
> diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c
> index 446934c0e5e5..578ae0050036 100644
> --- a/tools/lib/perf/evsel.c
> +++ b/tools/lib/perf/evsel.c
> @@ -334,7 +334,7 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
>  }
>
>  static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
> -                                int ioc,  void *arg,
> +                                int ioc, unsigned long arg,
>                                  int cpu_map_idx)
>  {
>         int thread;
> @@ -357,7 +357,7 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
>
>  int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
>  {
> -       return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
> +       return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0, cpu_map_idx);
>  }
>
>  int perf_evsel__enable(struct perf_evsel *evsel)
> @@ -366,13 +366,13 @@ int perf_evsel__enable(struct perf_evsel *evsel)
>         int err = 0;
>
>         for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
> -               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
> +               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0, i);
>         return err;
>  }
>
>  int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
>  {
> -       return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
> +       return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0, cpu_map_idx);
>  }
>
>  int perf_evsel__disable(struct perf_evsel *evsel)
> @@ -381,7 +381,39 @@ int perf_evsel__disable(struct perf_evsel *evsel)
>         int err = 0;
>
>         for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
> -               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
> +               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0, i);
> +       return err;
> +}
> +
> +int perf_evsel__refresh(struct perf_evsel *evsel, int refresh)
> +{
> +       int i;
> +       int err = 0;
> +
> +       for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
> +               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_REFRESH, refresh, i);
> +       return err;
> +}
> +
> +int perf_evsel__period(struct perf_evsel *evsel, __u64 period)
> +{
> +       struct perf_event_attr *attr;
> +       int i;
> +       int err = 0;
> +
> +       attr = perf_evsel__attr(evsel);
> +       if (!attr)
> +               return -EINVAL;

I don't think it'd return NULL..

Thanks,
Namhyung


> +
> +       for (i = 0; i < xyarray__max_x(evsel->fd); i++) {
> +               err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_PERIOD,
> +                                           (unsigned long)&period, i);
> +               if (err)
> +                       return err;
> +       }
> +
> +       attr->sample_period = period;
> +
>         return err;
>  }
>
> @@ -392,7 +424,7 @@ int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
>         for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
>                 err = perf_evsel__run_ioctl(evsel,
>                                      PERF_EVENT_IOC_SET_FILTER,
> -                                    (void *)filter, i);
> +                                    (unsigned long)filter, i);
>         return err;
>  }
>
> diff --git a/tools/lib/perf/include/perf/evsel.h b/tools/lib/perf/include/perf/evsel.h
> index 19a7993d9021..2c5e52c17d28 100644
> --- a/tools/lib/perf/include/perf/evsel.h
> +++ b/tools/lib/perf/include/perf/evsel.h
> @@ -60,6 +60,8 @@ LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
>  LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel);
>  LIBPERF_API int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx);
> +LIBPERF_API int perf_evsel__refresh(struct perf_evsel *evsel, int refresh);
> +LIBPERF_API int perf_evsel__period(struct perf_evsel *evsel, __u64 period);
>  LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel);
>  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);
> diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
> index b2ace16bbc32..d97e208c5be8 100644
> --- a/tools/lib/perf/libperf.map
> +++ b/tools/lib/perf/libperf.map
> @@ -31,6 +31,8 @@ LIBPERF_0.0.1 {
>                 perf_evsel__munmap;
>                 perf_evsel__mmap_base;
>                 perf_evsel__read;
> +               perf_evsel__refresh;
> +               perf_evsel__period;
>                 perf_evsel__cpus;
>                 perf_evsel__threads;
>                 perf_evsel__attr;
> --
> 2.25.1
>

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

* Re: [PATCH 0/7] libperf: Add interface for overflow check of sampling events
@ 2022-05-18  9:28 nakamura.shun
  0 siblings, 0 replies; 12+ messages in thread
From: nakamura.shun @ 2022-05-18  9:28 UTC (permalink / raw)
  To: 'Jiri Olsa'
  Cc: 'peterz@infradead.org', 'mingo@redhat.com',
	'acme@kernel.org', 'mark.rutland@arm.com',
	'alexander.shishkin@linux.intel.com',
	'jolsa@redhat.com', 'namhyung@kernel.org',
	'linux-kernel@vger.kernel.org',
	'linux-perf-users@vger.kernel.org'

Hi, Jirka.

>This patch series adds interface for overflow check of sampling events
>to libperf.
>
>First patch move 'open_flags' from tools/perf to evsel::open_flags.
>
>Second patch introduce perf_{evsel, evlist}__open_opt() with extensible
>structure opts.
>
>Third patch add support for overflow handling of sampling events.
>
>Fourth patch adds a interface to check overflowed events.
>
>Fifth patch adds a interface to perform IOC_REFRESH and IOC_PERIOD.
>
>Sixth and seventh patch adds tests.
>
Do you have any comments?
If nothing else, I will rebase the patch to 5.18-rc7 and post the v2 patch.

Best Regards
Shunsuke


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

end of thread, other threads:[~2022-05-20 19:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-22  9:38 [PATCH 0/7] libperf: Add interface for overflow check of sampling events Shunsuke Nakamura
2022-04-22  9:38 ` [PATCH 1/7] libperf: Move 'open_flags' from tools/perf to evsel::open_flags Shunsuke Nakamura
2022-04-22  9:38 ` [PATCH 2/7] libperf: Introduce perf_{evsel, evlist}__open_opt with extensible struct opts Shunsuke Nakamura
2022-05-20 18:59   ` Namhyung Kim
2022-04-22  9:38 ` [PATCH 3/7] libperf: Add support for overflow handling of sampling events Shunsuke Nakamura
2022-05-20 19:28   ` Namhyung Kim
2022-04-22  9:38 ` [PATCH 4/7] libperf: Add perf_evsel__has_fd() functions Shunsuke Nakamura
2022-04-22  9:38 ` [PATCH 5/7] libperf: Add perf_evsel__{refresh, period}() functions Shunsuke Nakamura
2022-05-20 19:38   ` Namhyung Kim
2022-04-22  9:38 ` [PATCH 6/7] libperf test: Add test_stat_overflow() Shunsuke Nakamura
2022-04-22  9:38 ` [PATCH 7/7] libperf test: Add test_stat_overflow_event() Shunsuke Nakamura
2022-05-18  9:28 [PATCH 0/7] libperf: Add interface for overflow check of sampling events nakamura.shun

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.