Skip to content

Commit e224d1c

Browse files
khueyIngo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent fd20bb5 commit e224d1c

File tree

3 files changed

+148
-1
lines changed

3 files changed

+148
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
sigtrap_threads
33
remove_on_exec
4+
watermark_signal

tools/testing/selftests/perf_events/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
CFLAGS += -Wl,-no-as-needed -Wall $(KHDR_INCLUDES)
33
LDFLAGS += -lpthread
44

5-
TEST_GEN_PROGS := sigtrap_threads remove_on_exec
5+
TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal
66
include ../lib.mk
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#define _GNU_SOURCE
3+
4+
#include <errno.h>
5+
#include <fcntl.h>
6+
#include <linux/perf_event.h>
7+
#include <stddef.h>
8+
#include <sched.h>
9+
#include <signal.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <sys/ioctl.h>
13+
#include <sys/mman.h>
14+
#include <sys/syscall.h>
15+
#include <sys/wait.h>
16+
#include <unistd.h>
17+
18+
#include "../kselftest_harness.h"
19+
20+
#define __maybe_unused __attribute__((__unused__))
21+
22+
static int sigio_count;
23+
24+
static void handle_sigio(int signum __maybe_unused,
25+
siginfo_t *oh __maybe_unused,
26+
void *uc __maybe_unused)
27+
{
28+
++sigio_count;
29+
}
30+
31+
static void do_child(void)
32+
{
33+
raise(SIGSTOP);
34+
35+
for (int i = 0; i < 20; ++i)
36+
sleep(1);
37+
38+
raise(SIGSTOP);
39+
40+
exit(0);
41+
}
42+
43+
TEST(watermark_signal)
44+
{
45+
struct perf_event_attr attr;
46+
struct perf_event_mmap_page *p = NULL;
47+
struct sigaction previous_sigio, sigio = { 0 };
48+
pid_t child = -1;
49+
int child_status;
50+
int fd = -1;
51+
long page_size = sysconf(_SC_PAGE_SIZE);
52+
53+
sigio.sa_sigaction = handle_sigio;
54+
EXPECT_EQ(sigaction(SIGIO, &sigio, &previous_sigio), 0);
55+
56+
memset(&attr, 0, sizeof(attr));
57+
attr.size = sizeof(attr);
58+
attr.type = PERF_TYPE_SOFTWARE;
59+
attr.config = PERF_COUNT_SW_DUMMY;
60+
attr.sample_period = 1;
61+
attr.disabled = 1;
62+
attr.watermark = 1;
63+
attr.context_switch = 1;
64+
attr.wakeup_watermark = 1;
65+
66+
child = fork();
67+
EXPECT_GE(child, 0);
68+
if (child == 0)
69+
do_child();
70+
else if (child < 0) {
71+
perror("fork()");
72+
goto cleanup;
73+
}
74+
75+
if (waitpid(child, &child_status, WSTOPPED) != child ||
76+
!(WIFSTOPPED(child_status) && WSTOPSIG(child_status) == SIGSTOP)) {
77+
fprintf(stderr,
78+
"failed to sycnhronize with child errno=%d status=%x\n",
79+
errno,
80+
child_status);
81+
goto cleanup;
82+
}
83+
84+
fd = syscall(__NR_perf_event_open, &attr, child, -1, -1,
85+
PERF_FLAG_FD_CLOEXEC);
86+
if (fd < 0) {
87+
fprintf(stderr, "failed opening event %llx\n", attr.config);
88+
goto cleanup;
89+
}
90+
91+
if (fcntl(fd, F_SETFL, FASYNC)) {
92+
perror("F_SETFL FASYNC");
93+
goto cleanup;
94+
}
95+
96+
if (fcntl(fd, F_SETOWN, getpid())) {
97+
perror("F_SETOWN getpid()");
98+
goto cleanup;
99+
}
100+
101+
if (fcntl(fd, F_SETSIG, SIGIO)) {
102+
perror("F_SETSIG SIGIO");
103+
goto cleanup;
104+
}
105+
106+
p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
107+
if (p == NULL) {
108+
perror("mmap");
109+
goto cleanup;
110+
}
111+
112+
if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {
113+
perror("PERF_EVENT_IOC_ENABLE");
114+
goto cleanup;
115+
}
116+
117+
if (kill(child, SIGCONT) < 0) {
118+
perror("SIGCONT");
119+
goto cleanup;
120+
}
121+
122+
if (waitpid(child, &child_status, WSTOPPED) != -1 || errno != EINTR)
123+
fprintf(stderr,
124+
"expected SIGIO to terminate wait errno=%d status=%x\n%d",
125+
errno,
126+
child_status,
127+
sigio_count);
128+
129+
EXPECT_GE(sigio_count, 1);
130+
131+
cleanup:
132+
if (p != NULL)
133+
munmap(p, 2 * page_size);
134+
135+
if (fd >= 0)
136+
close(fd);
137+
138+
if (child > 0) {
139+
kill(child, SIGKILL);
140+
waitpid(child, NULL, 0);
141+
}
142+
143+
sigaction(SIGIO, &previous_sigio, NULL);
144+
}
145+
146+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)