From nobody Fri Jun 12 14:06:32 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5B3EB33A6EB; Thu, 14 May 2026 16:21:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778775706; cv=none; b=kFhKhZ+Zq4MDzx7yWSibDiyK/Psle0p8Q2ByHeORMt8xQ1L9IaYTBtBioKk6AdukSduubnFVjXcH/M5CqcvSSGRORsI/LW9eXTvum9KmFD0loXbvCJzA4SRYEUJZuEMOWM70bM8mC2YDzaCspCqbDuGn62Kn7wehgEleQUVt+GI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778775706; c=relaxed/simple; bh=2a0gpR2LbWiiGVQTO6Zhnp1bBsKU4mNG4BJxn2FWJco=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WNQVedllE6nR+PrOwNzUXNjngqzcjK4EGQdOxPAEnGeVv5fHn4zeBy0DIKgLrJrFrk37g3o/Lm3TgjbK1MTBJSbizibk8DYMaU6FinYHjd9wC3Z9QmDX1uaByyQl1BdK81j7V70+3ltD8hv2goBHsOzBt2wveybPFJJRLCA2YtY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=QkVIKRNN; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="QkVIKRNN" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id EE0A42682; Thu, 14 May 2026 09:21:30 -0700 (PDT) Received: from e132581.arm.com (e132581.arm.com [10.1.196.87]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A60B53F7B4; Thu, 14 May 2026 09:21:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1778775696; bh=2a0gpR2LbWiiGVQTO6Zhnp1bBsKU4mNG4BJxn2FWJco=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=QkVIKRNNg+ImYHcXvReCOU8VZjOd2YOvpJ/v+e46bFgviKI+gJ36MqIhmJtKwnCvB 7Dsa5pmSk/9C62RiMq39waLD0lo3DaM4OSUBXUmMYME+oqlNRLvJlyGx7iue8BP+fm J63gqX60YtWavvkUWD/DVMgRNlcu24og4ZM6bsbI= From: Leo Yan Date: Thu, 14 May 2026 17:21:19 +0100 Subject: [PATCH v2 1/2] selftests/perf_events: Add test for refresh limit signals Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260514-arm_cs_clean_perf_handle-v2-1-cbb29c3b3661@arm.com> References: <20260514-arm_cs_clean_perf_handle-v2-0-cbb29c3b3661@arm.com> In-Reply-To: <20260514-arm_cs_clean_perf_handle-v2-0-cbb29c3b3661@arm.com> To: Peter Zijlstra , Ingo Molnar , Shuah Khan , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Sumanth Korikkar Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-perf-users@vger.kernel.org, Leo Yan X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1778775688; l=5909; i=leo.yan@arm.com; s=20250604; h=from:subject:message-id; bh=2a0gpR2LbWiiGVQTO6Zhnp1bBsKU4mNG4BJxn2FWJco=; b=uaBy9NcvV6fV2loqLj+4z1V296PWlNlsfMWVow/AfT/ha+0QMpr1QSQpuwETgzK/TEm2sPyWq ISGptNSsMXwC2m7jWFFjUgQ73dxOKeJ1kxfQk0y2+HKEeZsAn4e+/64 X-Developer-Key: i=leo.yan@arm.com; a=ed25519; pk=k4BaDbvkCXzBFA7Nw184KHGP5thju8lKqJYIrOWxDhI= perf reports POLL_IN for overflows while an event still has refreshes left, and POLL_HUP when the refresh count reaches zero and the event is disabled. Add a test to verify PERF_EVENT_IOC_REFRESH with a task-clock software event. Use a real-time signal so notifications are queued instead of being coalesced. Each iteration sets the refresh count to 5 and waits for a POLL_HUP notification after 5 task-clock overflows at a 1 microsecond interval. The sequence is repeated 100 times, verifying that exactly one POLL_HUP notification is delivered per iteration. The test is bounded by the default selftest timeout (30 seconds). POLL_IN POLL_HUP e1 e2 e3 e4 e5 | | | | | | | --+----+----+----+----+---------+---------------------- <----- Iter 1 -----> <--- Iter2 ... ---> POLL_IN is allowed to be lower than the theoretical maximum because overflow delivery is deferred through irq_work. If timers expire too close to each other, pending irq_work may not run before the next timer expires, so some POLL_IN notifications can be missed. Signed-off-by: Leo Yan --- tools/testing/selftests/perf_events/.gitignore | 1 + tools/testing/selftests/perf_events/Makefile | 3 +- .../testing/selftests/perf_events/refresh_signal.c | 120 +++++++++++++++++= ++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/perf_events/.gitignore b/tools/testing= /selftests/perf_events/.gitignore index 4931b3b6bbd3971145b0e09b1fcdaf6cae9eb10e..e1bcf3ab8ab24bdb742a9cd5938= 10c1c566d4b20 100644 --- a/tools/testing/selftests/perf_events/.gitignore +++ b/tools/testing/selftests/perf_events/.gitignore @@ -3,3 +3,4 @@ sigtrap_threads remove_on_exec watermark_signal mmap +refresh_signal diff --git a/tools/testing/selftests/perf_events/Makefile b/tools/testing/s= elftests/perf_events/Makefile index 2e5d85770dfeadd909196dbf980fd334b9580477..e0591b1045f959476a0c5bb57e4= 71a01006b66ee 100644 --- a/tools/testing/selftests/perf_events/Makefile +++ b/tools/testing/selftests/perf_events/Makefile @@ -2,5 +2,6 @@ CFLAGS +=3D -Wl,-no-as-needed -Wall $(KHDR_INCLUDES) LDFLAGS +=3D -lpthread =20 -TEST_GEN_PROGS :=3D sigtrap_threads remove_on_exec watermark_signal mmap +TEST_GEN_PROGS :=3D sigtrap_threads remove_on_exec watermark_signal mmap \ + refresh_signal include ../lib.mk diff --git a/tools/testing/selftests/perf_events/refresh_signal.c b/tools/t= esting/selftests/perf_events/refresh_signal.c new file mode 100644 index 0000000000000000000000000000000000000000..5519ea7b56f9dc7aea31e53698b= b201bcd76b241 --- /dev/null +++ b/tools/testing/selftests/perf_events/refresh_signal.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" + +#define RT_SIG (SIGRTMIN + 1) + +#define EVENT_LIMIT 5 +#define ITERATIONS 100 + +static struct { + volatile sig_atomic_t in; + volatile sig_atomic_t hup; +} count; + +static void sigio_handler(int signo __maybe_unused, siginfo_t *info, + void *ucontext __maybe_unused) +{ + switch (info->si_code) { + case POLL_IN: + count.in++; + break; + case POLL_HUP: + count.hup++; + break; + } +} + +FIXTURE(refresh_signal) +{ + struct sigaction old_sa; + int fd; +}; + +FIXTURE_SETUP(refresh_signal) +{ + struct sigaction sa =3D { 0 }; + struct perf_event_attr attr =3D { 0 }; + + sa.sa_sigaction =3D sigio_handler; + sa.sa_flags =3D SA_SIGINFO; + sigemptyset(&sa.sa_mask); + + /* Use a real-time signal so notifications are reliably queued */ + EXPECT_EQ(sigaction(RT_SIG, &sa, &self->old_sa), 0); + + attr.size =3D sizeof(attr); + attr.type =3D PERF_TYPE_SOFTWARE; + attr.config =3D PERF_COUNT_SW_TASK_CLOCK; + attr.disabled =3D 1; + attr.sample_period =3D 1000; /* 1 us */ + attr.exclude_kernel =3D 1; + attr.exclude_hv =3D 1; + + self->fd =3D syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); + ASSERT_NE(self->fd, -1); + + /* Enable async notification */ + ASSERT_EQ(fcntl(self->fd, F_SETFL, fcntl(self->fd, F_GETFL) | O_ASYNC), 0= ); + + /* Receive the signal for current process */ + ASSERT_EQ(fcntl(self->fd, F_SETOWN, getpid()), 0); + + /* Use signo instead of the default SIGIO */ + ASSERT_EQ(fcntl(self->fd, F_SETSIG, RT_SIG), 0); +} + +FIXTURE_TEARDOWN(refresh_signal) +{ + EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_DISABLE, 0), 0); + + close(self->fd); + sigaction(RT_SIG, &self->old_sa, NULL); +} + +TEST_F(refresh_signal, refresh_stress) +{ + int i; + + ASSERT_EQ(ioctl(self->fd, PERF_EVENT_IOC_RESET, 0), 0); + + for (i =3D 0; i < ITERATIONS; i++) { + sig_atomic_t old_count =3D count.hup; + + /* Set event limit and the event is enabled */ + ASSERT_EQ(ioctl(self->fd, PERF_EVENT_IOC_REFRESH, EVENT_LIMIT), 0); + + /* + * Wait for new the POLL_HUP notification. The test is bounded + * by the default timeout. + */ + while (old_count =3D=3D count.hup) + ; + } + + /* + * Events before EVENT_LIMIT are reported as POLL_IN. When the limit + * is reached, the final event is reported as POLL_HUP. The total + * number of events is scaled by the number of iterations. + * + * Events are delivered via irq_work. If timers expire too close to + * each other, irq_work may not run before the next timer fires, + * causing some POLL_IN events to be missed. Therefore, use a + * less-or-equal comparison for POLL_IN. + * + * The last event stops the timer, so the POLL_HUP signal must be + * observed once per iteration when the limit is reached. + */ + EXPECT_LE(count.in, (EVENT_LIMIT - 1) * ITERATIONS); + EXPECT_EQ(count.hup, ITERATIONS); +} + +TEST_HARNESS_MAIN --=20 2.34.1 From nobody Fri Jun 12 14:06:32 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 751912ECE86; Thu, 14 May 2026 16:21:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778775703; cv=none; b=SLPQ4qdiTHKa1K/vWtCsKw92GuRC/cfU3k3zka319n9ufFCSzIWNX5MweSfI678tK/hmo5677oQueIV4d0CPMn0KbYPp6BjtcxSuCnq64Jl5E9aKSUW20TAWjmkOqV+HAv9JQBQuuw3crJR4cvDMyCoaPLkwSbx6nE7bN4NF40Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778775703; c=relaxed/simple; bh=Xxgk45qwU+WCmfkeGuB4S+yq9+//OSXkQdw5WDMTR/M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hxxWBZGFDgs6AEjj+yxm34h6ZtrIUnxalnRz4GDsNjYrdM9vS49p3dcbr6zZo+dxqA9DKhZR177rk5t8iRrdZxF+GkGwuh7u9wsIN5dmxz1y/05MY78hM/BGwnBXTqKsj0PRm+R9+8GDZaSKfyJbTUpgxafty2EzTgx1GynnvPc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=okszwaUc; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="okszwaUc" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 29E8C3541; Thu, 14 May 2026 09:21:35 -0700 (PDT) Received: from e132581.arm.com (e132581.arm.com [10.1.196.87]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AF0393F7B4; Thu, 14 May 2026 09:21:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1778775700; bh=Xxgk45qwU+WCmfkeGuB4S+yq9+//OSXkQdw5WDMTR/M=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=okszwaUc3T6zgEsGj7+bX8Jd480YMPxwi9w5rDiLLT7NYp6Lr9Ls8WjTKOujLFyGb vrReqkvNA1QWgTzQ6epN1VyYW8byXbl57pu4CBtbLrBZGfjNaqapd8e+dg3di6WcJV LSsOM0otqeepN36nR25D2n+Y+MtAwsYF/oVfh+Xc= From: Leo Yan Date: Thu, 14 May 2026 17:21:20 +0100 Subject: [PATCH v2 2/2] perf/core: Ignore overflows while disable is pending Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260514-arm_cs_clean_perf_handle-v2-2-cbb29c3b3661@arm.com> References: <20260514-arm_cs_clean_perf_handle-v2-0-cbb29c3b3661@arm.com> In-Reply-To: <20260514-arm_cs_clean_perf_handle-v2-0-cbb29c3b3661@arm.com> To: Peter Zijlstra , Ingo Molnar , Shuah Khan , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Sumanth Korikkar Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-perf-users@vger.kernel.org, Leo Yan X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1778775688; l=2541; i=leo.yan@arm.com; s=20250604; h=from:subject:message-id; bh=Xxgk45qwU+WCmfkeGuB4S+yq9+//OSXkQdw5WDMTR/M=; b=ZwgRkYC3lAPP88th6sRyc1zkSSIvc/9ICW8M0m474ZL2YUsRiue9PE1ZwFwweLH5J4UZGtCWU eypqW1hjJywBqNRqlOdrs+drA6CiQJnro7OjDdAIqNn7hpWhZ/MMa6r X-Developer-Key: i=leo.yan@arm.com; a=ed25519; pk=k4BaDbvkCXzBFA7Nw184KHGP5thju8lKqJYIrOWxDhI= Commit 18dbcbfabfff ("perf: Fix the POLL_HUP delivery breakage") added a direct pmu->stop(event, 0) call when the refresh limit reaches zero. That change was based on a report [1] using SIGIO to receive POLL_HUP. Since SIGIO is a standard signal, multiple notifications can be coalesced and userspace may miss a signal even though the perf core generated. Using a real-time signal avoids that coalescing and shows that POLL_HUP is delivered reliably without directly stopping the PMU from the overflow path. There is still a race to handle. For a high frequency event, another overflow can arrive after perf_event_disable_inatomic() has queued the disable irq_work but before that irq_work has run. If overflow processing continues, pending_kill can be overwritten from POLL_HUP back to POLL_IN and samples can be recorded after the refresh limit has been reached. The direct PMU stop avoids this by stopping the hardware immediately, but the event still relies on perf_event_disable_inatomic() to complete the disable state transition. This is redundant that it might inject unnecessary stop operations in the middle. More importantly, the throttling mechanism already exists for stopping high frequency overflows. Make the overflow path explicitly check pending_disable instead of the PMU stop. Once disable is pending, skip further overflow processing so the pending POLL_HUP is preserved and no samples are recorded for an event that is already waiting to be disabled. [1] https://lore.kernel.org/lkml/aICYAqM5EQUlTqtX@li-2b55cdcc-350b-11b2-a85= c-a78bff51fc11.ibm.com/ Signed-off-by: Leo Yan --- kernel/events/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 7935d5663944ee1cbaf38cf8018c3347635e8d31..0fadb53e5d79cab8cb52a08d765= 6b0064a77ef55 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10745,12 +10745,18 @@ static int __perf_event_overflow(struct perf_even= t *event, * events */ =20 + /* + * Disable is pending, skip further overflow processing so the pending + * POLL_HUP is preserved and no samples are recorded beyond the limit. + */ + if (event->pending_disable) + goto out; + event->pending_kill =3D POLL_IN; if (events && atomic_dec_and_test(&event->event_limit)) { ret =3D 1; event->pending_kill =3D POLL_HUP; perf_event_disable_inatomic(event); - event->pmu->stop(event, 0); } =20 if (event->attr.sigtrap) { --=20 2.34.1