Skip to content

Commit ba1fae4

Browse files
WangNan0acmel
authored andcommitted
perf test: Add 'perf test BPF'
This patch adds BPF testcase for testing BPF event filtering. By utilizing the result of 'perf test LLVM', this patch compiles the eBPF sample program then test its ability. The BPF script in 'perf test LLVM' lets only 50% samples generated by epoll_pwait() to be captured. This patch runs that system call for 111 times, so the result should contain 56 samples. Signed-off-by: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1446817783-86722-8-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 7af3f3d commit ba1fae4

File tree

6 files changed

+248
-1
lines changed

6 files changed

+248
-1
lines changed

tools/perf/tests/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ perf-y += parse-no-sample-id-all.o
3232
perf-y += kmod-path.o
3333
perf-y += thread-map.o
3434
perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
35+
perf-y += bpf.o
3536
perf-y += topology.o
3637

3738
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c

tools/perf/tests/bpf.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include <stdio.h>
2+
#include <sys/epoll.h>
3+
#include <util/bpf-loader.h>
4+
#include <util/evlist.h>
5+
#include "tests.h"
6+
#include "llvm.h"
7+
#include "debug.h"
8+
#define NR_ITERS 111
9+
10+
#ifdef HAVE_LIBBPF_SUPPORT
11+
12+
static int epoll_pwait_loop(void)
13+
{
14+
int i;
15+
16+
/* Should fail NR_ITERS times */
17+
for (i = 0; i < NR_ITERS; i++)
18+
epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
19+
return 0;
20+
}
21+
22+
static struct {
23+
enum test_llvm__testcase prog_id;
24+
const char *desc;
25+
const char *name;
26+
const char *msg_compile_fail;
27+
const char *msg_load_fail;
28+
int (*target_func)(void);
29+
int expect_result;
30+
} bpf_testcase_table[] = {
31+
{
32+
LLVM_TESTCASE_BASE,
33+
"Test basic BPF filtering",
34+
"[basic_bpf_test]",
35+
"fix 'perf test LLVM' first",
36+
"load bpf object failed",
37+
&epoll_pwait_loop,
38+
(NR_ITERS + 1) / 2,
39+
},
40+
};
41+
42+
static int do_test(struct bpf_object *obj, int (*func)(void),
43+
int expect)
44+
{
45+
struct record_opts opts = {
46+
.target = {
47+
.uid = UINT_MAX,
48+
.uses_mmap = true,
49+
},
50+
.freq = 0,
51+
.mmap_pages = 256,
52+
.default_interval = 1,
53+
};
54+
55+
char pid[16];
56+
char sbuf[STRERR_BUFSIZE];
57+
struct perf_evlist *evlist;
58+
int i, ret = TEST_FAIL, err = 0, count = 0;
59+
60+
struct parse_events_evlist parse_evlist;
61+
struct parse_events_error parse_error;
62+
63+
bzero(&parse_error, sizeof(parse_error));
64+
bzero(&parse_evlist, sizeof(parse_evlist));
65+
parse_evlist.error = &parse_error;
66+
INIT_LIST_HEAD(&parse_evlist.list);
67+
68+
err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
69+
if (err || list_empty(&parse_evlist.list)) {
70+
pr_debug("Failed to add events selected by BPF\n");
71+
if (!err)
72+
return TEST_FAIL;
73+
}
74+
75+
snprintf(pid, sizeof(pid), "%d", getpid());
76+
pid[sizeof(pid) - 1] = '\0';
77+
opts.target.tid = opts.target.pid = pid;
78+
79+
/* Instead of perf_evlist__new_default, don't add default events */
80+
evlist = perf_evlist__new();
81+
if (!evlist) {
82+
pr_debug("No ehough memory to create evlist\n");
83+
return TEST_FAIL;
84+
}
85+
86+
err = perf_evlist__create_maps(evlist, &opts.target);
87+
if (err < 0) {
88+
pr_debug("Not enough memory to create thread/cpu maps\n");
89+
goto out_delete_evlist;
90+
}
91+
92+
perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
93+
evlist->nr_groups = parse_evlist.nr_groups;
94+
95+
perf_evlist__config(evlist, &opts);
96+
97+
err = perf_evlist__open(evlist);
98+
if (err < 0) {
99+
pr_debug("perf_evlist__open: %s\n",
100+
strerror_r(errno, sbuf, sizeof(sbuf)));
101+
goto out_delete_evlist;
102+
}
103+
104+
err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
105+
if (err < 0) {
106+
pr_debug("perf_evlist__mmap: %s\n",
107+
strerror_r(errno, sbuf, sizeof(sbuf)));
108+
goto out_delete_evlist;
109+
}
110+
111+
perf_evlist__enable(evlist);
112+
(*func)();
113+
perf_evlist__disable(evlist);
114+
115+
for (i = 0; i < evlist->nr_mmaps; i++) {
116+
union perf_event *event;
117+
118+
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
119+
const u32 type = event->header.type;
120+
121+
if (type == PERF_RECORD_SAMPLE)
122+
count ++;
123+
}
124+
}
125+
126+
if (count != expect)
127+
pr_debug("BPF filter result incorrect\n");
128+
129+
ret = TEST_OK;
130+
131+
out_delete_evlist:
132+
perf_evlist__delete(evlist);
133+
return ret;
134+
}
135+
136+
static struct bpf_object *
137+
prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
138+
{
139+
struct bpf_object *obj;
140+
141+
obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
142+
if (IS_ERR(obj)) {
143+
pr_debug("Compile BPF program failed.\n");
144+
return NULL;
145+
}
146+
return obj;
147+
}
148+
149+
static int __test__bpf(int index)
150+
{
151+
int ret;
152+
void *obj_buf;
153+
size_t obj_buf_sz;
154+
struct bpf_object *obj;
155+
156+
ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
157+
bpf_testcase_table[index].prog_id,
158+
true);
159+
if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
160+
pr_debug("Unable to get BPF object, %s\n",
161+
bpf_testcase_table[index].msg_compile_fail);
162+
if (index == 0)
163+
return TEST_SKIP;
164+
else
165+
return TEST_FAIL;
166+
}
167+
168+
obj = prepare_bpf(obj_buf, obj_buf_sz,
169+
bpf_testcase_table[index].name);
170+
if (!obj) {
171+
ret = TEST_FAIL;
172+
goto out;
173+
}
174+
175+
ret = do_test(obj,
176+
bpf_testcase_table[index].target_func,
177+
bpf_testcase_table[index].expect_result);
178+
out:
179+
bpf__clear();
180+
return ret;
181+
}
182+
183+
int test__bpf(void)
184+
{
185+
unsigned int i;
186+
int err;
187+
188+
if (geteuid() != 0) {
189+
pr_debug("Only root can run BPF test\n");
190+
return TEST_SKIP;
191+
}
192+
193+
for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) {
194+
err = __test__bpf(i);
195+
196+
if (err != TEST_OK)
197+
return err;
198+
}
199+
200+
return TEST_OK;
201+
}
202+
203+
#else
204+
int test__bpf(void)
205+
{
206+
pr_debug("Skip BPF test because BPF support is not compiled\n");
207+
return TEST_SKIP;
208+
}
209+
#endif

tools/perf/tests/builtin-test.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ static struct test generic_tests[] = {
165165
.desc = "Test topology in session",
166166
.func = test_session_topology,
167167
},
168+
{
169+
.desc = "Test BPF filter",
170+
.func = test__bpf,
171+
},
168172
{
169173
.func = NULL,
170174
},

tools/perf/tests/tests.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ int test__fdarray__add(void);
6666
int test__kmod_path__parse(void);
6767
int test__thread_map(void);
6868
int test__llvm(void);
69+
int test__bpf(void);
6970
int test_session_topology(void);
7071

7172
#if defined(__arm__) || defined(__aarch64__)

tools/perf/util/bpf-loader.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,32 @@ struct bpf_prog_priv {
3434
struct perf_probe_event pev;
3535
};
3636

37+
static bool libbpf_initialized;
38+
39+
struct bpf_object *
40+
bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
41+
{
42+
struct bpf_object *obj;
43+
44+
if (!libbpf_initialized) {
45+
libbpf_set_print(libbpf_warning,
46+
libbpf_info,
47+
libbpf_debug);
48+
libbpf_initialized = true;
49+
}
50+
51+
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
52+
if (IS_ERR(obj)) {
53+
pr_debug("bpf: failed to load buffer\n");
54+
return ERR_PTR(-EINVAL);
55+
}
56+
57+
return obj;
58+
}
59+
3760
struct bpf_object *bpf__prepare_load(const char *filename, bool source)
3861
{
3962
struct bpf_object *obj;
40-
static bool libbpf_initialized;
4163

4264
if (!libbpf_initialized) {
4365
libbpf_set_print(libbpf_warning,

tools/perf/util/bpf-loader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source);
3434
int bpf__strerror_prepare_load(const char *filename, bool source,
3535
int err, char *buf, size_t size);
3636

37+
struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
38+
const char *name);
39+
3740
void bpf__clear(void);
3841

3942
int bpf__probe(struct bpf_object *obj);
@@ -55,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
5558
return ERR_PTR(-ENOTSUP);
5659
}
5760

61+
static inline struct bpf_object *
62+
bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
63+
size_t obj_buf_sz __maybe_unused)
64+
{
65+
return ERR_PTR(-ENOTSUP);
66+
}
67+
5868
static inline void bpf__clear(void) { }
5969

6070
static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}

0 commit comments

Comments
 (0)