mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] perf test: Add test for events re-armed with PERF_EVENT_IOC_REFRESH
@ 2026-10-21 14:17 Francesco Nigro
  2026-10-21 17:33 ` Ian Rogers
  0 siblings, 1 reply; 3+ messages in thread
From: Francesco Nigro @ 2026-10-21 14:17 UTC (permalink / raw)
  To: peterz, mingo, acme, namhyung
  Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
	james.clark, kan.liang, leo.yan, linux-perf-users, linux-kernel,
	regressions, Francesco Nigro

Open a sampling event with sample_period 1, re-arm it with
PERF_EVENT_IOC_REFRESH from its overflow signal handler, as
self-profilers such as async-profiler do, and check that each of 1000
events delivers a signal. One case uses a software event (page faults),
the other the syscalls:sys_enter_getppid tracepoint. The signal is a
real-time one, so overflows cannot be coalesced, and the page fault
buffer is marked MADV_NOHUGEPAGE so that each touched page faults once.

The tracepoint case fails since
commit 18dbcbfabfff ("perf: Fix the POLL_HUP delivery breakage"):
only the first overflow is delivered. The re-arming ioctl succeeds,
but the event count stays at 1. It passes on the parent commit. The
software case passes on both.

The test was written with an AI coding assistant (Claude) from a
standalone reproducer; I reviewed it and ran it in QEMU on current
mainline, on that commit and on its parent.

Link: https://github.com/async-profiler/async-profiler/issues/1813
Signed-off-by: Francesco Nigro <nigro.fra@gmail.com>
---

Notes:
    v2:
    - Mark the page fault buffer MADV_NOHUGEPAGE: with transparent_hugepage=always
      the software case got 489 of 1000 overflows (reported by Sashiko).
    - Use a real-time signal instead of SIGIO, so overflows cannot be coalesced.
    - Print the event count, POLL_HUP signals and the re-arm ioctl's errno.
    - Skip only on EACCES/EPERM, check the setup calls, accept >= 1000
      overflows, close the event before restoring the signal handler.
    
    v1: https://lore.kernel.org/r/20261021131006.2101248-1-nigro.fra@gmail.com
    
    To run it on any x86_64 box with virtme-ng:
    
      vng --kconfig && make -j$(nproc)
      make -C tools/perf NO_LIBTRACEEVENT=1
      vng -- tools/perf/perf test -vv REFRESH
    
    Tracepoint case, 2 vCPUs:
    
      b320789d6883 (parent)  Ok:     count 1000, 1000 overflows (1000 POLL_HUP)
      18dbcbfabfff           FAILED: count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
      a804c5742bff (master)  FAILED: count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
    
    The software case passes on all three, and on master with
    transparent_hugepage=always.
    
    Leo Yan's series "perf: Revert direct PMU stop for refresh limit"
    reverts 18dbcbfabfff for a different reason; I haven't tested it
    against this:
    https://lore.kernel.org/r/20260512-arm_cs_clean_perf_handle-v1-0-75ff373ecd22@arm.com
    
    #regzbot introduced: 18dbcbfabfff

 tools/perf/tests/Build           |   1 +
 tools/perf/tests/builtin-test.c  |   1 +
 tools/perf/tests/event_refresh.c | 162 +++++++++++++++++++++++++++++++
 tools/perf/tests/tests.h         |   1 +
 4 files changed, 165 insertions(+)
 create mode 100644 tools/perf/tests/event_refresh.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 66944a4f4..199e10c8c 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -23,6 +23,7 @@ perf-test-y += hists_output.o
 perf-test-y += hists_cumulate.o
 perf-test-y += bp_signal.o
 perf-test-y += bp_signal_overflow.o
+perf-test-y += event_refresh.o
 perf-test-y += bp_account.o
 perf-test-y += wp.o
 perf-test-y += task-exit.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 4d0784b16..2b10f4d7f 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -98,6 +98,7 @@ static struct test_suite *generic_tests[] = {
 	&suite__hists_link,
 	&suite__bp_signal,
 	&suite__bp_signal_overflow,
+	&suite__event_refresh,
 	&suite__bp_accounting,
 	&suite__wp,
 	&suite__task_exit,
diff --git a/tools/perf/tests/event_refresh.c b/tools/perf/tests/event_refresh.c
new file mode 100644
index 000000000..726e5de4c
--- /dev/null
+++ b/tools/perf/tests/event_refresh.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Re-arm a sampling event from its overflow signal handler with
+ * PERF_EVENT_IOC_REFRESH and check that every overflow is delivered.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
+
+#include "cloexec.h"
+#include "debug.h"
+#include "tests.h"
+#include "tp_pmu.h"
+#include <internal/lib.h> // page_size
+#include "../perf-sys.h"
+
+#define NR_EVENTS 1000
+/* A real-time signal is queued, so no overflow can be coalesced away. */
+#define REFRESH_SIGNAL (SIGRTMIN + 1)
+
+static volatile sig_atomic_t overflows, hups, refresh_errno;
+
+static void sig_handler(int signum __maybe_unused, siginfo_t *info,
+			void *uc __maybe_unused)
+{
+	int saved_errno = errno;
+
+	overflows++;
+	if (info->si_code == POLL_HUP)
+		hups++;
+	if (ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1) < 0)
+		refresh_errno = errno;
+	errno = saved_errno;
+}
+
+/* Count overflow signals for NR_EVENTS calls of trigger(), period 1. */
+static int count_overflows(struct perf_event_attr *attr, void (*trigger)(int i))
+{
+	struct sigaction sa, old_sa;
+	uint64_t count = 0;
+	int fd, i, err = TEST_FAIL;
+
+	attr->size = sizeof(*attr);
+	attr->sample_period = 1;
+	attr->disabled = 1;
+
+	fd = sys_perf_event_open(attr, 0, -1, -1, perf_event_open_cloexec_flag());
+	if (fd < 0) {
+		int open_errno = errno;
+
+		pr_debug("failed opening event: %s\n", strerror(open_errno));
+		return open_errno == EACCES || open_errno == EPERM ? TEST_SKIP : TEST_FAIL;
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = sig_handler;
+	sa.sa_flags = SA_SIGINFO;
+	if (sigaction(REFRESH_SIGNAL, &sa, &old_sa) < 0) {
+		pr_debug("failed setting up signal handler\n");
+		close(fd);
+		return TEST_FAIL;
+	}
+
+	if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK | O_ASYNC) < 0 ||
+	    fcntl(fd, F_SETSIG, REFRESH_SIGNAL) < 0 ||
+	    fcntl(fd, F_SETOWN, getpid()) < 0) {
+		pr_debug("failed setting up signal delivery: %s\n", strerror(errno));
+		goto out;
+	}
+
+	overflows = 0;
+	hups = 0;
+	refresh_errno = 0;
+	if (ioctl(fd, PERF_EVENT_IOC_REFRESH, 1) < 0) {
+		pr_debug("PERF_EVENT_IOC_REFRESH failed: %s\n", strerror(errno));
+		goto out;
+	}
+	for (i = 0; i < NR_EVENTS; i++)
+		trigger(i);
+	ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
+
+	if (read(fd, &count, sizeof(count)) != sizeof(count))
+		pr_debug("failed to read the event count\n");
+	pr_debug("%d events, count %" PRIu64 ", %d overflows (%d POLL_HUP), re-arm errno %d\n",
+		 NR_EVENTS, count, overflows, hups, refresh_errno);
+	/* Unrelated page faults can only add overflows, never hide one. */
+	if (overflows >= NR_EVENTS)
+		err = TEST_OK;
+out:
+	/* Close first: a late signal must still find our handler. */
+	close(fd);
+	sigaction(REFRESH_SIGNAL, &old_sa, NULL);
+	return err;
+}
+
+static char *pages;
+
+static void touch_page(int i)
+{
+	pages[(long)i * page_size] = 1;
+}
+
+static int test__event_refresh_sw(struct test_suite *test __maybe_unused,
+				  int subtest __maybe_unused)
+{
+	struct perf_event_attr attr = {
+		.type = PERF_TYPE_SOFTWARE,
+		.config = PERF_COUNT_SW_PAGE_FAULTS,
+	};
+	int err;
+
+	pages = mmap(NULL, (long)NR_EVENTS * page_size, PROT_READ | PROT_WRITE,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (pages == MAP_FAILED)
+		return TEST_FAIL;
+	/* One fault per touched page: a huge page would cover many of them. */
+	madvise(pages, (long)NR_EVENTS * page_size, MADV_NOHUGEPAGE);
+
+	err = count_overflows(&attr, touch_page);
+	munmap(pages, (long)NR_EVENTS * page_size);
+	return err;
+}
+
+static void call_getppid(int i __maybe_unused)
+{
+	syscall(SYS_getppid);
+}
+
+static int test__event_refresh_tp(struct test_suite *test __maybe_unused,
+				  int subtest __maybe_unused)
+{
+	struct perf_event_attr attr = {
+		.type = PERF_TYPE_TRACEPOINT,
+	};
+	int id = tp_pmu__id("syscalls", "sys_enter_getppid");
+
+	if (id < 0) {
+		pr_debug("no syscalls:sys_enter_getppid tracepoint\n");
+		return TEST_SKIP;
+	}
+	attr.config = id;
+
+	return count_overflows(&attr, call_getppid);
+}
+
+static struct test_case tests__event_refresh[] = {
+	TEST_CASE_REASON("Software event", event_refresh_sw, "permissions"),
+	TEST_CASE_REASON("Tracepoint event", event_refresh_tp, "permissions"),
+	{	.name = NULL, }
+};
+
+struct test_suite suite__event_refresh = {
+	.desc = "Event re-armed with PERF_EVENT_IOC_REFRESH",
+	.test_cases = tests__event_refresh,
+};
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index cee9e6b62..ecc25b5a3 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -124,6 +124,7 @@ DECLARE_SUITE(parse_events);
 DECLARE_SUITE(hists_link);
 DECLARE_SUITE(bp_signal);
 DECLARE_SUITE(bp_signal_overflow);
+DECLARE_SUITE(event_refresh);
 DECLARE_SUITE(bp_accounting);
 DECLARE_SUITE(wp);
 DECLARE_SUITE(task_exit);
-- 
2.55.0


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

* Re: [PATCH v2] perf test: Add test for events re-armed with PERF_EVENT_IOC_REFRESH
  2026-10-21 14:17 [PATCH v2] perf test: Add test for events re-armed with PERF_EVENT_IOC_REFRESH Francesco Nigro
@ 2026-10-21 17:33 ` Ian Rogers
  2026-10-21 21:58   ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 3+ messages in thread
From: Ian Rogers @ 2026-10-21 17:33 UTC (permalink / raw)
  To: Francesco Nigro
  Cc: peterz, mingo, acme, namhyung, mark.rutland, alexander.shishkin,
	jolsa, adrian.hunter, james.clark, kan.liang, leo.yan,
	linux-perf-users, linux-kernel, regressions

On Wed, Oct 21, 2026 at 7:17 AM Francesco Nigro <nigro.fra@gmail.com> wrote:
>
> Open a sampling event with sample_period 1, re-arm it with
> PERF_EVENT_IOC_REFRESH from its overflow signal handler, as
> self-profilers such as async-profiler do, and check that each of 1000
> events delivers a signal. One case uses a software event (page faults),
> the other the syscalls:sys_enter_getppid tracepoint. The signal is a
> real-time one, so overflows cannot be coalesced, and the page fault
> buffer is marked MADV_NOHUGEPAGE so that each touched page faults once.
>
> The tracepoint case fails since
> commit 18dbcbfabfff ("perf: Fix the POLL_HUP delivery breakage"):
> only the first overflow is delivered. The re-arming ioctl succeeds,
> but the event count stays at 1. It passes on the parent commit. The
> software case passes on both.
>
> The test was written with an AI coding assistant (Claude) from a
> standalone reproducer; I reviewed it and ran it in QEMU on current
> mainline, on that commit and on its parent.
>
> Link: https://github.com/async-profiler/async-profiler/issues/1813
> Signed-off-by: Francesco Nigro <nigro.fra@gmail.com>

Thanks Francesco, testing locally I see a failure on  7.1.6:
```
$ sudo /tmp/perf/perf test -v IOC_REFRESH
Not taking turns using the perf mlock budget: nothing can exhaust it
20: Event re-armed with PERF_EVENT_IOC_REFRESH                        :
20.1: Software event                                                  : Ok
---- start ----
test child forked, pid 187381
1000 events, count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
---- end(-1) ----
20.2: Tracepoint event                                                : FAILED!

=== Test Summary ===
Passed main tests : 0
Passed subtests   : 1
Skipped tests     : 0
Failed tests      : 1
List of failed tests:
  20.2: Tracepoint event
```
I believe this is currently expected until the kernel is fixed, which
is somewhat unfortunate. The code looks okay and the build isn't
regressed.

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

Thanks!
Ian



> ---
>
> Notes:
>     v2:
>     - Mark the page fault buffer MADV_NOHUGEPAGE: with transparent_hugepage=always
>       the software case got 489 of 1000 overflows (reported by Sashiko).
>     - Use a real-time signal instead of SIGIO, so overflows cannot be coalesced.
>     - Print the event count, POLL_HUP signals and the re-arm ioctl's errno.
>     - Skip only on EACCES/EPERM, check the setup calls, accept >= 1000
>       overflows, close the event before restoring the signal handler.
>
>     v1: https://lore.kernel.org/r/20261021131006.2101248-1-nigro.fra@gmail.com
>
>     To run it on any x86_64 box with virtme-ng:
>
>       vng --kconfig && make -j$(nproc)
>       make -C tools/perf NO_LIBTRACEEVENT=1
>       vng -- tools/perf/perf test -vv REFRESH
>
>     Tracepoint case, 2 vCPUs:
>
>       b320789d6883 (parent)  Ok:     count 1000, 1000 overflows (1000 POLL_HUP)
>       18dbcbfabfff           FAILED: count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
>       a804c5742bff (master)  FAILED: count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
>
>     The software case passes on all three, and on master with
>     transparent_hugepage=always.
>
>     Leo Yan's series "perf: Revert direct PMU stop for refresh limit"
>     reverts 18dbcbfabfff for a different reason; I haven't tested it
>     against this:
>     https://lore.kernel.org/r/20260512-arm_cs_clean_perf_handle-v1-0-75ff373ecd22@arm.com
>
>     #regzbot introduced: 18dbcbfabfff
>
>  tools/perf/tests/Build           |   1 +
>  tools/perf/tests/builtin-test.c  |   1 +
>  tools/perf/tests/event_refresh.c | 162 +++++++++++++++++++++++++++++++
>  tools/perf/tests/tests.h         |   1 +
>  4 files changed, 165 insertions(+)
>  create mode 100644 tools/perf/tests/event_refresh.c
>
> diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
> index 66944a4f4..199e10c8c 100644
> --- a/tools/perf/tests/Build
> +++ b/tools/perf/tests/Build
> @@ -23,6 +23,7 @@ perf-test-y += hists_output.o
>  perf-test-y += hists_cumulate.o
>  perf-test-y += bp_signal.o
>  perf-test-y += bp_signal_overflow.o
> +perf-test-y += event_refresh.o
>  perf-test-y += bp_account.o
>  perf-test-y += wp.o
>  perf-test-y += task-exit.o
> diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
> index 4d0784b16..2b10f4d7f 100644
> --- a/tools/perf/tests/builtin-test.c
> +++ b/tools/perf/tests/builtin-test.c
> @@ -98,6 +98,7 @@ static struct test_suite *generic_tests[] = {
>         &suite__hists_link,
>         &suite__bp_signal,
>         &suite__bp_signal_overflow,
> +       &suite__event_refresh,
>         &suite__bp_accounting,
>         &suite__wp,
>         &suite__task_exit,
> diff --git a/tools/perf/tests/event_refresh.c b/tools/perf/tests/event_refresh.c
> new file mode 100644
> index 000000000..726e5de4c
> --- /dev/null
> +++ b/tools/perf/tests/event_refresh.c
> @@ -0,0 +1,162 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Re-arm a sampling event from its overflow signal handler with
> + * PERF_EVENT_IOC_REFRESH and check that every overflow is delivered.
> + */
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <sys/syscall.h>
> +#include <linux/perf_event.h>
> +
> +#include "cloexec.h"
> +#include "debug.h"
> +#include "tests.h"
> +#include "tp_pmu.h"
> +#include <internal/lib.h> // page_size
> +#include "../perf-sys.h"
> +
> +#define NR_EVENTS 1000
> +/* A real-time signal is queued, so no overflow can be coalesced away. */
> +#define REFRESH_SIGNAL (SIGRTMIN + 1)
> +
> +static volatile sig_atomic_t overflows, hups, refresh_errno;
> +
> +static void sig_handler(int signum __maybe_unused, siginfo_t *info,
> +                       void *uc __maybe_unused)
> +{
> +       int saved_errno = errno;
> +
> +       overflows++;
> +       if (info->si_code == POLL_HUP)
> +               hups++;
> +       if (ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1) < 0)
> +               refresh_errno = errno;
> +       errno = saved_errno;
> +}
> +
> +/* Count overflow signals for NR_EVENTS calls of trigger(), period 1. */
> +static int count_overflows(struct perf_event_attr *attr, void (*trigger)(int i))
> +{
> +       struct sigaction sa, old_sa;
> +       uint64_t count = 0;
> +       int fd, i, err = TEST_FAIL;
> +
> +       attr->size = sizeof(*attr);
> +       attr->sample_period = 1;
> +       attr->disabled = 1;
> +
> +       fd = sys_perf_event_open(attr, 0, -1, -1, perf_event_open_cloexec_flag());
> +       if (fd < 0) {
> +               int open_errno = errno;
> +
> +               pr_debug("failed opening event: %s\n", strerror(open_errno));
> +               return open_errno == EACCES || open_errno == EPERM ? TEST_SKIP : TEST_FAIL;
> +       }
> +
> +       memset(&sa, 0, sizeof(sa));
> +       sa.sa_sigaction = sig_handler;
> +       sa.sa_flags = SA_SIGINFO;
> +       if (sigaction(REFRESH_SIGNAL, &sa, &old_sa) < 0) {
> +               pr_debug("failed setting up signal handler\n");
> +               close(fd);
> +               return TEST_FAIL;
> +       }
> +
> +       if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK | O_ASYNC) < 0 ||
> +           fcntl(fd, F_SETSIG, REFRESH_SIGNAL) < 0 ||
> +           fcntl(fd, F_SETOWN, getpid()) < 0) {
> +               pr_debug("failed setting up signal delivery: %s\n", strerror(errno));
> +               goto out;
> +       }
> +
> +       overflows = 0;
> +       hups = 0;
> +       refresh_errno = 0;
> +       if (ioctl(fd, PERF_EVENT_IOC_REFRESH, 1) < 0) {
> +               pr_debug("PERF_EVENT_IOC_REFRESH failed: %s\n", strerror(errno));
> +               goto out;
> +       }
> +       for (i = 0; i < NR_EVENTS; i++)
> +               trigger(i);
> +       ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
> +
> +       if (read(fd, &count, sizeof(count)) != sizeof(count))
> +               pr_debug("failed to read the event count\n");
> +       pr_debug("%d events, count %" PRIu64 ", %d overflows (%d POLL_HUP), re-arm errno %d\n",
> +                NR_EVENTS, count, overflows, hups, refresh_errno);
> +       /* Unrelated page faults can only add overflows, never hide one. */
> +       if (overflows >= NR_EVENTS)
> +               err = TEST_OK;
> +out:
> +       /* Close first: a late signal must still find our handler. */
> +       close(fd);
> +       sigaction(REFRESH_SIGNAL, &old_sa, NULL);
> +       return err;
> +}
> +
> +static char *pages;
> +
> +static void touch_page(int i)
> +{
> +       pages[(long)i * page_size] = 1;
> +}
> +
> +static int test__event_refresh_sw(struct test_suite *test __maybe_unused,
> +                                 int subtest __maybe_unused)
> +{
> +       struct perf_event_attr attr = {
> +               .type = PERF_TYPE_SOFTWARE,
> +               .config = PERF_COUNT_SW_PAGE_FAULTS,
> +       };
> +       int err;
> +
> +       pages = mmap(NULL, (long)NR_EVENTS * page_size, PROT_READ | PROT_WRITE,
> +                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +       if (pages == MAP_FAILED)
> +               return TEST_FAIL;
> +       /* One fault per touched page: a huge page would cover many of them. */
> +       madvise(pages, (long)NR_EVENTS * page_size, MADV_NOHUGEPAGE);
> +
> +       err = count_overflows(&attr, touch_page);
> +       munmap(pages, (long)NR_EVENTS * page_size);
> +       return err;
> +}
> +
> +static void call_getppid(int i __maybe_unused)
> +{
> +       syscall(SYS_getppid);
> +}
> +
> +static int test__event_refresh_tp(struct test_suite *test __maybe_unused,
> +                                 int subtest __maybe_unused)
> +{
> +       struct perf_event_attr attr = {
> +               .type = PERF_TYPE_TRACEPOINT,
> +       };
> +       int id = tp_pmu__id("syscalls", "sys_enter_getppid");
> +
> +       if (id < 0) {
> +               pr_debug("no syscalls:sys_enter_getppid tracepoint\n");
> +               return TEST_SKIP;
> +       }
> +       attr.config = id;
> +
> +       return count_overflows(&attr, call_getppid);
> +}
> +
> +static struct test_case tests__event_refresh[] = {
> +       TEST_CASE_REASON("Software event", event_refresh_sw, "permissions"),
> +       TEST_CASE_REASON("Tracepoint event", event_refresh_tp, "permissions"),
> +       {       .name = NULL, }
> +};
> +
> +struct test_suite suite__event_refresh = {
> +       .desc = "Event re-armed with PERF_EVENT_IOC_REFRESH",
> +       .test_cases = tests__event_refresh,
> +};
> diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
> index cee9e6b62..ecc25b5a3 100644
> --- a/tools/perf/tests/tests.h
> +++ b/tools/perf/tests/tests.h
> @@ -124,6 +124,7 @@ DECLARE_SUITE(parse_events);
>  DECLARE_SUITE(hists_link);
>  DECLARE_SUITE(bp_signal);
>  DECLARE_SUITE(bp_signal_overflow);
> +DECLARE_SUITE(event_refresh);
>  DECLARE_SUITE(bp_accounting);
>  DECLARE_SUITE(wp);
>  DECLARE_SUITE(task_exit);
> --
> 2.55.0
>

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

* Re: [PATCH v2] perf test: Add test for events re-armed with PERF_EVENT_IOC_REFRESH
  2026-10-21 17:33 ` Ian Rogers
@ 2026-10-21 21:58   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 3+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-10-21 21:58 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Francesco Nigro, peterz, mingo, namhyung, mark.rutland,
	alexander.shishkin, jolsa, adrian.hunter, james.clark, kan.liang,
	leo.yan, linux-perf-users, linux-kernel, regressions

On Wed, Oct 21, 2026 at 10:33:42AM -0700, Ian Rogers wrote:
> On Wed, Oct 21, 2026 at 7:17 AM Francesco Nigro <nigro.fra@gmail.com> wrote:
> >
> > Open a sampling event with sample_period 1, re-arm it with
> > PERF_EVENT_IOC_REFRESH from its overflow signal handler, as
> > self-profilers such as async-profiler do, and check that each of 1000
> > events delivers a signal. One case uses a software event (page faults),
> > the other the syscalls:sys_enter_getppid tracepoint. The signal is a
> > real-time one, so overflows cannot be coalesced, and the page fault
> > buffer is marked MADV_NOHUGEPAGE so that each touched page faults once.
> >
> > The tracepoint case fails since
> > commit 18dbcbfabfff ("perf: Fix the POLL_HUP delivery breakage"):
> > only the first overflow is delivered. The re-arming ioctl succeeds,
> > but the event count stays at 1. It passes on the parent commit. The
> > software case passes on both.
> >
> > The test was written with an AI coding assistant (Claude) from a
> > standalone reproducer; I reviewed it and ran it in QEMU on current
> > mainline, on that commit and on its parent.
> >
> > Link: https://github.com/async-profiler/async-profiler/issues/1813
> > Signed-off-by: Francesco Nigro <nigro.fra@gmail.com>
> 
> Thanks Francesco, testing locally I see a failure on  7.1.6:
> ```
> $ sudo /tmp/perf/perf test -v IOC_REFRESH
> Not taking turns using the perf mlock budget: nothing can exhaust it
> 20: Event re-armed with PERF_EVENT_IOC_REFRESH                        :
> 20.1: Software event                                                  : Ok
> ---- start ----
> test child forked, pid 187381
> 1000 events, count 1, 1 overflows (1 POLL_HUP), re-arm errno 0
> ---- end(-1) ----
> 20.2: Tracepoint event                                                : FAILED!
> 
> === Test Summary ===
> Passed main tests : 0
> Passed subtests   : 1
> Skipped tests     : 0
> Failed tests      : 1
> List of failed tests:
>   20.2: Tracepoint event
> ```
> I believe this is currently expected until the kernel is fixed, which
> is somewhat unfortunate. The code looks okay and the build isn't
> regressed.
> 
> Reviewed-by: Ian Rogers <irogers@google.com>

Thanks Francesco for writing the test!

Applied to perf-tools-next, for v7.4.

- Arnaldo

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

end of thread, other threads:[~2026-10-21 21:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-21 14:17 [PATCH v2] perf test: Add test for events re-armed with PERF_EVENT_IOC_REFRESH Francesco Nigro
2026-10-21 17:33 ` Ian Rogers
2026-10-21 21:58   ` Arnaldo Carvalho de Melo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®