1 // SPDX-License-Identifier: GPL-2.0
2 #include <subcmd/parse-options.h>
5 #include <uapi/linux/filter.h>
8 #include <linux/unistd.h>
9 #include <sys/syscall.h>
10 #include <sys/ioctl.h>
11 #include <linux/time64.h>
12 #include <uapi/linux/seccomp.h>
13 #include <sys/prctl.h>
28 #define LOOPS_DEFAULT 1000000UL
29 static uint64_t loops
= LOOPS_DEFAULT
;
30 static bool sync_mode
;
32 static const struct option options
[] = {
33 OPT_U64('l', "loop", &loops
, "Specify number of loops"),
34 OPT_BOOLEAN('s', "sync-mode", &sync_mode
,
35 "Enable the synchronous mode for seccomp notifications"),
39 static const char * const bench_seccomp_usage
[] = {
40 "perf bench sched secccomp-notify <options>",
44 static int seccomp(unsigned int op
, unsigned int flags
, void *args
)
46 return syscall(__NR_seccomp
, op
, flags
, args
);
49 static int user_notif_syscall(int nr
, unsigned int flags
)
51 struct sock_filter filter
[] = {
52 BPF_STMT(BPF_LD
|BPF_W
|BPF_ABS
,
53 offsetof(struct seccomp_data
, nr
)),
54 BPF_JUMP(BPF_JMP
|BPF_JEQ
|BPF_K
, nr
, 0, 1),
55 BPF_STMT(BPF_RET
|BPF_K
, SECCOMP_RET_USER_NOTIF
),
56 BPF_STMT(BPF_RET
|BPF_K
, SECCOMP_RET_ALLOW
),
59 struct sock_fprog prog
= {
60 .len
= (unsigned short)ARRAY_SIZE(filter
),
64 return seccomp(SECCOMP_SET_MODE_FILTER
, flags
, &prog
);
67 #define USER_NOTIF_MAGIC INT_MAX
68 static void user_notification_sync_loop(int listener
)
70 struct seccomp_notif_resp resp
;
71 struct seccomp_notif req
;
74 for (nr
= 0; nr
< loops
; nr
++) {
75 memset(&req
, 0, sizeof(req
));
76 if (ioctl(listener
, SECCOMP_IOCTL_NOTIF_RECV
, &req
))
77 err(EXIT_FAILURE
, "SECCOMP_IOCTL_NOTIF_RECV failed");
79 if (req
.data
.nr
!= __NR_gettid
)
80 errx(EXIT_FAILURE
, "unexpected syscall: %d", req
.data
.nr
);
84 resp
.val
= USER_NOTIF_MAGIC
;
86 if (ioctl(listener
, SECCOMP_IOCTL_NOTIF_SEND
, &resp
))
87 err(EXIT_FAILURE
, "SECCOMP_IOCTL_NOTIF_SEND failed");
91 #ifndef SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP
92 #define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)
93 #define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64)
95 int bench_sched_seccomp_notify(int argc
, const char **argv
)
97 struct timeval start
, stop
, diff
;
98 unsigned long long result_usec
= 0;
103 argc
= parse_options(argc
, argv
, options
, bench_seccomp_usage
, 0);
105 gettimeofday(&start
, NULL
);
107 prctl(PR_SET_NO_NEW_PRIVS
, 1, 0, 0, 0);
108 listener
= user_notif_syscall(__NR_gettid
,
109 SECCOMP_FILTER_FLAG_NEW_LISTENER
);
111 err(EXIT_FAILURE
, "can't create a notification descriptor");
115 err(EXIT_FAILURE
, "fork");
117 if (prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0))
118 err(EXIT_FAILURE
, "can't set the parent death signal");
120 ret
= syscall(__NR_gettid
);
121 if (ret
== USER_NOTIF_MAGIC
)
129 if (ioctl(listener
, SECCOMP_IOCTL_NOTIF_SET_FLAGS
,
130 SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP
, 0))
132 "can't set SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP");
134 user_notification_sync_loop(listener
);
137 if (waitpid(pid
, &status
, 0) != pid
)
138 err(EXIT_FAILURE
, "waitpid(%d) failed", pid
);
139 if (!WIFSIGNALED(status
) || WTERMSIG(status
) != SIGKILL
)
140 errx(EXIT_FAILURE
, "unexpected exit code: %d", status
);
142 gettimeofday(&stop
, NULL
);
143 timersub(&stop
, &start
, &diff
);
145 switch (bench_format
) {
146 case BENCH_FORMAT_DEFAULT
:
147 printf("# Executed %" PRIu64
" system calls\n\n",
150 result_usec
= diff
.tv_sec
* USEC_PER_SEC
;
151 result_usec
+= diff
.tv_usec
;
153 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
154 (unsigned long) diff
.tv_sec
,
155 (unsigned long) (diff
.tv_usec
/ USEC_PER_MSEC
));
157 printf(" %14lf usecs/op\n",
158 (double)result_usec
/ (double)loops
);
159 printf(" %14d ops/sec\n",
160 (int)((double)loops
/
161 ((double)result_usec
/ (double)USEC_PER_SEC
)));
164 case BENCH_FORMAT_SIMPLE
:
165 printf("%lu.%03lu\n",
166 (unsigned long) diff
.tv_sec
,
167 (unsigned long) (diff
.tv_usec
/ USEC_PER_MSEC
));
171 /* reaching here is something disaster */
172 fprintf(stderr
, "Unknown format:%d\n", bench_format
);