Skip to content

Commit 3a61638

Browse files
beaubelgraverostedt
authored andcommitted
user_events: Add self-test for perf_event integration
Tests perf can be attached to and written out correctly. Ensures attach updates status bits in user programs. Link: https://lkml.kernel.org/r/20220118204326.2169-10-beaub@linux.microsoft.com Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 745bb7e commit 3a61638

2 files changed

Lines changed: 169 additions & 1 deletion

File tree

tools/testing/selftests/user_events/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
CFLAGS += -Wl,-no-as-needed -Wall -I../../../../usr/include
33
LDLIBS += -lrt -lpthread -lm
44

5-
TEST_GEN_PROGS = ftrace_test dyn_test
5+
TEST_GEN_PROGS = ftrace_test dyn_test perf_test
66

77
TEST_FILES := settings
88

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* User Events Perf Events Test Program
4+
*
5+
* Copyright (c) 2021 Beau Belgrave <beaub@linux.microsoft.com>
6+
*/
7+
8+
#include <errno.h>
9+
#include <linux/user_events.h>
10+
#include <linux/perf_event.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <fcntl.h>
14+
#include <sys/ioctl.h>
15+
#include <sys/stat.h>
16+
#include <unistd.h>
17+
#include <asm/unistd.h>
18+
19+
#include "../kselftest_harness.h"
20+
21+
const char *data_file = "/sys/kernel/debug/tracing/user_events_data";
22+
const char *status_file = "/sys/kernel/debug/tracing/user_events_status";
23+
const char *id_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/id";
24+
const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format";
25+
26+
struct event {
27+
__u32 index;
28+
__u32 field1;
29+
__u32 field2;
30+
};
31+
32+
static long perf_event_open(struct perf_event_attr *pe, pid_t pid,
33+
int cpu, int group_fd, unsigned long flags)
34+
{
35+
return syscall(__NR_perf_event_open, pe, pid, cpu, group_fd, flags);
36+
}
37+
38+
static int get_id(void)
39+
{
40+
FILE *fp = fopen(id_file, "r");
41+
int ret, id = 0;
42+
43+
if (!fp)
44+
return -1;
45+
46+
ret = fscanf(fp, "%d", &id);
47+
fclose(fp);
48+
49+
if (ret != 1)
50+
return -1;
51+
52+
return id;
53+
}
54+
55+
static int get_offset(void)
56+
{
57+
FILE *fp = fopen(fmt_file, "r");
58+
int ret, c, last = 0, offset = 0;
59+
60+
if (!fp)
61+
return -1;
62+
63+
/* Read until empty line */
64+
while (true) {
65+
c = getc(fp);
66+
67+
if (c == EOF)
68+
break;
69+
70+
if (last == '\n' && c == '\n')
71+
break;
72+
73+
last = c;
74+
}
75+
76+
ret = fscanf(fp, "\tfield:u32 field1;\toffset:%d;", &offset);
77+
fclose(fp);
78+
79+
if (ret != 1)
80+
return -1;
81+
82+
return offset;
83+
}
84+
85+
FIXTURE(user) {
86+
int status_fd;
87+
int data_fd;
88+
};
89+
90+
FIXTURE_SETUP(user) {
91+
self->status_fd = open(status_file, O_RDONLY);
92+
ASSERT_NE(-1, self->status_fd);
93+
94+
self->data_fd = open(data_file, O_RDWR);
95+
ASSERT_NE(-1, self->data_fd);
96+
}
97+
98+
FIXTURE_TEARDOWN(user) {
99+
close(self->status_fd);
100+
close(self->data_fd);
101+
}
102+
103+
TEST_F(user, perf_write) {
104+
struct perf_event_attr pe = {0};
105+
struct user_reg reg = {0};
106+
int page_size = sysconf(_SC_PAGESIZE);
107+
char *status_page;
108+
struct event event;
109+
struct perf_event_mmap_page *perf_page;
110+
int id, fd, offset;
111+
__u32 *val;
112+
113+
reg.size = sizeof(reg);
114+
reg.name_args = (__u64)"__test_event u32 field1; u32 field2";
115+
116+
status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED,
117+
self->status_fd, 0);
118+
ASSERT_NE(MAP_FAILED, status_page);
119+
120+
/* Register should work */
121+
ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
122+
ASSERT_EQ(0, reg.write_index);
123+
ASSERT_NE(0, reg.status_index);
124+
ASSERT_EQ(0, status_page[reg.status_index]);
125+
126+
/* Id should be there */
127+
id = get_id();
128+
ASSERT_NE(-1, id);
129+
offset = get_offset();
130+
ASSERT_NE(-1, offset);
131+
132+
pe.type = PERF_TYPE_TRACEPOINT;
133+
pe.size = sizeof(pe);
134+
pe.config = id;
135+
pe.sample_type = PERF_SAMPLE_RAW;
136+
pe.sample_period = 1;
137+
pe.wakeup_events = 1;
138+
139+
/* Tracepoint attach should work */
140+
fd = perf_event_open(&pe, 0, -1, -1, 0);
141+
ASSERT_NE(-1, fd);
142+
143+
perf_page = mmap(NULL, page_size * 2, PROT_READ, MAP_SHARED, fd, 0);
144+
ASSERT_NE(MAP_FAILED, perf_page);
145+
146+
/* Status should be updated */
147+
ASSERT_EQ(EVENT_STATUS_PERF, status_page[reg.status_index]);
148+
149+
event.index = reg.write_index;
150+
event.field1 = 0xc001;
151+
event.field2 = 0xc01a;
152+
153+
/* Ensure write shows up at correct offset */
154+
ASSERT_NE(-1, write(self->data_fd, &event, sizeof(event)));
155+
val = (void *)(((char *)perf_page) + perf_page->data_offset);
156+
ASSERT_EQ(PERF_RECORD_SAMPLE, *val);
157+
/* Skip over header and size, move to offset */
158+
val += 3;
159+
val = (void *)((char *)val) + offset;
160+
/* Ensure correct */
161+
ASSERT_EQ(event.field1, *val++);
162+
ASSERT_EQ(event.field2, *val++);
163+
}
164+
165+
int main(int argc, char **argv)
166+
{
167+
return test_harness_run(argc, argv);
168+
}

0 commit comments

Comments
 (0)