mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-07 13:53:24 +00:00
selftests/perf_events: Test FASYNC with watermark wakeups
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@kylehuey.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20240413141618.4160-4-khuey@kylehuey.com
This commit is contained in:
parent
fd20bb51ed
commit
e224d1c1fb
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
sigtrap_threads
|
||||
remove_on_exec
|
||||
watermark_signal
|
||||
|
@ -2,5 +2,5 @@
|
||||
CFLAGS += -Wl,-no-as-needed -Wall $(KHDR_INCLUDES)
|
||||
LDFLAGS += -lpthread
|
||||
|
||||
TEST_GEN_PROGS := sigtrap_threads remove_on_exec
|
||||
TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal
|
||||
include ../lib.mk
|
||||
|
146
tools/testing/selftests/perf_events/watermark_signal.c
Normal file
146
tools/testing/selftests/perf_events/watermark_signal.c
Normal file
@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <stddef.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../kselftest_harness.h"
|
||||
|
||||
#define __maybe_unused __attribute__((__unused__))
|
||||
|
||||
static int sigio_count;
|
||||
|
||||
static void handle_sigio(int signum __maybe_unused,
|
||||
siginfo_t *oh __maybe_unused,
|
||||
void *uc __maybe_unused)
|
||||
{
|
||||
++sigio_count;
|
||||
}
|
||||
|
||||
static void do_child(void)
|
||||
{
|
||||
raise(SIGSTOP);
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
sleep(1);
|
||||
|
||||
raise(SIGSTOP);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
TEST(watermark_signal)
|
||||
{
|
||||
struct perf_event_attr attr;
|
||||
struct perf_event_mmap_page *p = NULL;
|
||||
struct sigaction previous_sigio, sigio = { 0 };
|
||||
pid_t child = -1;
|
||||
int child_status;
|
||||
int fd = -1;
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
sigio.sa_sigaction = handle_sigio;
|
||||
EXPECT_EQ(sigaction(SIGIO, &sigio, &previous_sigio), 0);
|
||||
|
||||
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();
|
||||
EXPECT_GE(child, 0);
|
||||
if (child == 0)
|
||||
do_child();
|
||||
else if (child < 0) {
|
||||
perror("fork()");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (waitpid(child, &child_status, WSTOPPED) != child ||
|
||||
!(WIFSTOPPED(child_status) && WSTOPSIG(child_status) == SIGSTOP)) {
|
||||
fprintf(stderr,
|
||||
"failed to sycnhronize with child errno=%d status=%x\n",
|
||||
errno,
|
||||
child_status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fd = syscall(__NR_perf_event_open, &attr, child, -1, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "failed opening event %llx\n", attr.config);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFL, FASYNC)) {
|
||||
perror("F_SETFL FASYNC");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETOWN, getpid())) {
|
||||
perror("F_SETOWN getpid()");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETSIG, SIGIO)) {
|
||||
perror("F_SETSIG SIGIO");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (p == NULL) {
|
||||
perror("mmap");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {
|
||||
perror("PERF_EVENT_IOC_ENABLE");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (kill(child, SIGCONT) < 0) {
|
||||
perror("SIGCONT");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (waitpid(child, &child_status, WSTOPPED) != -1 || errno != EINTR)
|
||||
fprintf(stderr,
|
||||
"expected SIGIO to terminate wait errno=%d status=%x\n%d",
|
||||
errno,
|
||||
child_status,
|
||||
sigio_count);
|
||||
|
||||
EXPECT_GE(sigio_count, 1);
|
||||
|
||||
cleanup:
|
||||
if (p != NULL)
|
||||
munmap(p, 2 * page_size);
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (child > 0) {
|
||||
kill(child, SIGKILL);
|
||||
waitpid(child, NULL, 0);
|
||||
}
|
||||
|
||||
sigaction(SIGIO, &previous_sigio, NULL);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
Loading…
Reference in New Issue
Block a user