Re: [PATCH 2/2] perf test: Test FASYNC with watermark wakeups.

From: Ian Rogers
Date: Wed Feb 21 2024 - 13:39:07 EST


On Wed, Feb 21, 2024 at 9:52 AM Kyle Huey <me@xxxxxxxxxxxx> wrote:
>
> The test uses PERF_RECORD_SWITCH records to fill the ring buffer and
> trigger the watermark wakeup, which in turn should trigger an IO
> signal.
>
> Signed-off-by: Kyle Huey <khuey@xxxxxxxxxxxx>
> ---
> tools/perf/tests/Build | 1 +
> tools/perf/tests/builtin-test.c | 1 +
> tools/perf/tests/tests.h | 1 +
> tools/perf/tests/watermark_signal.c | 123 ++++++++++++++++++++++++++++
> 4 files changed, 126 insertions(+)
> create mode 100644 tools/perf/tests/watermark_signal.c
>
> diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
> index 53ba9c3e20e0..de43eb60b280 100644
> --- a/tools/perf/tests/Build
> +++ b/tools/perf/tests/Build
> @@ -67,6 +67,7 @@ perf-y += sigtrap.o
> perf-y += event_groups.o
> perf-y += symbols.o
> perf-y += util.o
> +perf-y += watermark_signal.o
>
> ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc))
> perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
> diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
> index 4a5973f9bb9b..715c01a2172a 100644
> --- a/tools/perf/tests/builtin-test.c
> +++ b/tools/perf/tests/builtin-test.c
> @@ -124,6 +124,7 @@ static struct test_suite *generic_tests[] = {
> &suite__event_groups,
> &suite__symbols,
> &suite__util,
> + &suite__watermark_signal,
> NULL,
> };
>
> diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
> index dad3d7414142..7ef4e0d0a77b 100644
> --- a/tools/perf/tests/tests.h
> +++ b/tools/perf/tests/tests.h
> @@ -146,6 +146,7 @@ DECLARE_SUITE(sigtrap);
> DECLARE_SUITE(event_groups);
> DECLARE_SUITE(symbols);
> DECLARE_SUITE(util);
> +DECLARE_SUITE(watermark_signal);
>
> /*
> * PowerPC and S390 do not support creation of instruction breakpoints using the
> diff --git a/tools/perf/tests/watermark_signal.c b/tools/perf/tests/watermark_signal.c
> new file mode 100644
> index 000000000000..ae4abedc4b7c
> --- /dev/null
> +++ b/tools/perf/tests/watermark_signal.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stddef.h>
> +#include <signal.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +
> +#include "tests.h"
> +#include "debug.h"
> +#include "event.h"
> +#include "../perf-sys.h"
> +#include "cloexec.h"
> +#include <internal/lib.h> // page_size
> +
> +static int sigio_count;
> +
> +static void handle_sigio(int sig __always_unused)
> +{
> + ++sigio_count;
> +}
> +
> +static void do_child(void)
> +{
> + for (int i = 0; i < 20; ++i)
> + sleep(1);
> +
> + exit(0);
> +}
> +
> +static int test__watermark_signal(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
> +{
> + struct perf_event_attr attr;
> + struct perf_event_mmap_page *p = NULL;
> + sighandler_t previous_sigio = SIG_ERR;
> + pid_t child = -1;
> + int fd = -1;
> + int ret = TEST_FAIL;
> +
> + previous_sigio = signal(SIGIO, handle_sigio);
> + if (previous_sigio == SIG_ERR) {
> + pr_debug("failed setting SIGIO handler\n");
> + goto cleanup;
> + }
> +
> + memset(&attr, 0, sizeof(attr));
> + attr.size = sizeof(attr);
> + attr.type = PERF_TYPE_SOFTWARE;
> + attr.config = PERF_COUNT_SW_DUMMY;
> + attr.sample_period = 1;
> + attr.disabled = 1;
> + attr.watermark = 1;
> + attr.context_switch = 1;
> + attr.wakeup_watermark = 1;
> +
> + child = fork();
> + if (child == 0)
> + do_child();
> + else if (child < 0) {
> + pr_debug("failed fork() %d\n", errno);
> + goto cleanup;
> + }
> +
> + fd = sys_perf_event_open(&attr, child, -1, -1,
> + perf_event_open_cloexec_flag());
> + if (fd < 0) {
> + pr_debug("failed opening event %llx\n", attr.config);
> + goto cleanup;
> + }
> +
> + if (fcntl(fd, F_SETFL, FASYNC)) {
> + pr_debug("failed F_SETFL FASYNC %d\n", errno);
> + goto cleanup;
> + }

Thanks for the work! The perf tool and perf test should run on older
kernels ideally without failure. I'm assuming this would fail on an
older kernel. Could we make the return value skip in that case?

> +
> + if (fcntl(fd, F_SETOWN, getpid())) {
> + pr_debug("failed F_SETOWN getpid() %d\n", errno);
> + goto cleanup;
> + }
> +
> + if (fcntl(fd, F_SETSIG, SIGIO)) {
> + pr_debug("failed F_SETSIG SIGIO %d\n", errno);
> + goto cleanup;
> + }
> +
> + p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
> + if (p == NULL) {
> + pr_debug("failed to mmap\n");
> + goto cleanup;
> + }
> +
> + if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {
> + pr_debug("failed PERF_EVENT_IOC_ENABLE %d\n", errno);
> + goto cleanup;
> + }
> +
> + sleep(30);

This is kind of a painful wait, could it be less? No sleeps would be best :-)

Thanks,
Ian

> +
> + ret = (sigio_count == 1) ? TEST_OK : TEST_FAIL;
> +
> +cleanup:
> + if (p != NULL)
> + munmap(p, 2 * page_size);
> +
> + if (fd >= 0)
> + close(fd);
> +
> + if (child > 0) {
> + kill(child, SIGTERM);
> + waitpid(child, NULL, 0);
> + }
> +
> + if (previous_sigio != SIG_ERR)
> + signal(SIGIO, previous_sigio);
> +
> + return ret;
> +}
> +
> +DEFINE_SUITE("Watermark signal handler", watermark_signal);
> --
> 2.34.1
>