1 // SPDX-License-Identifier: GPL-2.0
3 * User Events Perf Events Test Program
5 * Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
9 #include <linux/user_events.h>
10 #include <linux/perf_event.h>
14 #include <sys/ioctl.h>
17 #include <asm/unistd.h>
19 #include "../kselftest_harness.h"
20 #include "user_events_selftests.h"
22 const char *data_file
= "/sys/kernel/tracing/user_events_data";
23 const char *id_file
= "/sys/kernel/tracing/events/user_events/__test_event/id";
24 const char *fmt_file
= "/sys/kernel/tracing/events/user_events/__test_event/format";
32 static long perf_event_open(struct perf_event_attr
*pe
, pid_t pid
,
33 int cpu
, int group_fd
, unsigned long flags
)
35 return syscall(__NR_perf_event_open
, pe
, pid
, cpu
, group_fd
, flags
);
38 static int get_id(void)
40 FILE *fp
= fopen(id_file
, "r");
46 ret
= fscanf(fp
, "%d", &id
);
55 static int get_offset(void)
57 FILE *fp
= fopen(fmt_file
, "r");
58 int ret
, c
, last
= 0, offset
= 0;
63 /* Read until empty line */
70 if (last
== '\n' && c
== '\n')
76 ret
= fscanf(fp
, "\tfield:u32 field1;\toffset:%d;", &offset
);
85 static int clear(int *check
)
87 struct user_unreg unreg
= {0};
89 unreg
.size
= sizeof(unreg
);
90 unreg
.disable_bit
= 31;
91 unreg
.disable_addr
= (__u64
)check
;
93 int fd
= open(data_file
, O_RDWR
);
98 if (ioctl(fd
, DIAG_IOCSUNREG
, &unreg
) == -1)
102 if (ioctl(fd
, DIAG_IOCSDEL
, "__test_event") == -1)
117 FIXTURE_SETUP(user
) {
118 USER_EVENT_FIXTURE_SETUP(return, self
->umount
);
120 self
->data_fd
= open(data_file
, O_RDWR
);
121 ASSERT_NE(-1, self
->data_fd
);
124 FIXTURE_TEARDOWN(user
) {
125 USER_EVENT_FIXTURE_TEARDOWN(self
->umount
);
127 close(self
->data_fd
);
129 if (clear(&self
->check
) != 0)
130 printf("WARNING: Clear didn't work!\n");
133 TEST_F(user
, perf_write
) {
134 struct perf_event_attr pe
= {0};
135 struct user_reg reg
= {0};
137 struct perf_event_mmap_page
*perf_page
;
138 int page_size
= sysconf(_SC_PAGESIZE
);
142 reg
.size
= sizeof(reg
);
143 reg
.name_args
= (__u64
)"__test_event u32 field1; u32 field2";
145 reg
.enable_addr
= (__u64
)&self
->check
;
146 reg
.enable_size
= sizeof(self
->check
);
148 /* Register should work */
149 ASSERT_EQ(0, ioctl(self
->data_fd
, DIAG_IOCSREG
, ®
));
150 ASSERT_EQ(0, reg
.write_index
);
151 ASSERT_EQ(0, self
->check
);
153 /* Id should be there */
156 offset
= get_offset();
157 ASSERT_NE(-1, offset
);
159 pe
.type
= PERF_TYPE_TRACEPOINT
;
160 pe
.size
= sizeof(pe
);
162 pe
.sample_type
= PERF_SAMPLE_RAW
;
163 pe
.sample_period
= 1;
164 pe
.wakeup_events
= 1;
166 /* Tracepoint attach should work */
167 fd
= perf_event_open(&pe
, 0, -1, -1, 0);
170 perf_page
= mmap(NULL
, page_size
* 2, PROT_READ
, MAP_SHARED
, fd
, 0);
171 ASSERT_NE(MAP_FAILED
, perf_page
);
173 /* Status should be updated */
174 ASSERT_EQ(1 << reg
.enable_bit
, self
->check
);
176 event
.index
= reg
.write_index
;
177 event
.field1
= 0xc001;
178 event
.field2
= 0xc01a;
180 /* Ensure write shows up at correct offset */
181 ASSERT_NE(-1, write(self
->data_fd
, &event
, sizeof(event
)));
182 val
= (void *)(((char *)perf_page
) + perf_page
->data_offset
);
183 ASSERT_EQ(PERF_RECORD_SAMPLE
, *val
);
184 /* Skip over header and size, move to offset */
186 val
= (void *)((char *)val
) + offset
;
188 ASSERT_EQ(event
.field1
, *val
++);
189 ASSERT_EQ(event
.field2
, *val
++);
191 munmap(perf_page
, page_size
* 2);
194 /* Status should be updated */
195 ASSERT_EQ(0, self
->check
);
198 TEST_F(user
, perf_empty_events
) {
199 struct perf_event_attr pe
= {0};
200 struct user_reg reg
= {0};
201 struct perf_event_mmap_page
*perf_page
;
202 int page_size
= sysconf(_SC_PAGESIZE
);
206 reg
.size
= sizeof(reg
);
207 reg
.name_args
= (__u64
)"__test_event";
209 reg
.enable_addr
= (__u64
)&self
->check
;
210 reg
.enable_size
= sizeof(self
->check
);
212 /* Register should work */
213 ASSERT_EQ(0, ioctl(self
->data_fd
, DIAG_IOCSREG
, ®
));
214 ASSERT_EQ(0, reg
.write_index
);
215 ASSERT_EQ(0, self
->check
);
217 /* Id should be there */
221 pe
.type
= PERF_TYPE_TRACEPOINT
;
222 pe
.size
= sizeof(pe
);
224 pe
.sample_type
= PERF_SAMPLE_RAW
;
225 pe
.sample_period
= 1;
226 pe
.wakeup_events
= 1;
228 /* Tracepoint attach should work */
229 fd
= perf_event_open(&pe
, 0, -1, -1, 0);
232 perf_page
= mmap(NULL
, page_size
* 2, PROT_READ
, MAP_SHARED
, fd
, 0);
233 ASSERT_NE(MAP_FAILED
, perf_page
);
235 /* Status should be updated */
236 ASSERT_EQ(1 << reg
.enable_bit
, self
->check
);
238 /* Ensure write shows up at correct offset */
239 ASSERT_NE(-1, write(self
->data_fd
, ®
.write_index
,
240 sizeof(reg
.write_index
)));
241 val
= (void *)(((char *)perf_page
) + perf_page
->data_offset
);
242 ASSERT_EQ(PERF_RECORD_SAMPLE
, *val
);
244 munmap(perf_page
, page_size
* 2);
247 /* Status should be updated */
248 ASSERT_EQ(0, self
->check
);
251 int main(int argc
, char **argv
)
253 return test_harness_run(argc
, argv
);