aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-11-06 08:49:43 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-06 15:50:03 -0500
commitba1fae431e74bb427a699187434142fd3fe98390 (patch)
treeaac0b9c41b23c714a2a33320d068b4140cfd82ab /tools
parent7af3f3d55b80cce40ad94b6b8e173dccedaf25e6 (diff)
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/bpf.c209
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/util/bpf-loader.c24
-rw-r--r--tools/perf/util/bpf-loader.h10
6 files changed, 248 insertions, 1 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index a47b21193fb2..f41ebf8849fe 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,6 +32,7 @@ perf-y += parse-no-sample-id-all.o
32perf-y += kmod-path.o 32perf-y += kmod-path.o
33perf-y += thread-map.o 33perf-y += thread-map.o
34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o 34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
35perf-y += bpf.o
35perf-y += topology.o 36perf-y += topology.o
36 37
37$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c 38$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
new file mode 100644
index 000000000000..ec16f7812c8b
--- /dev/null
+++ b/tools/perf/tests/bpf.c
@@ -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
12static 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
22static 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
42static 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
131out_delete_evlist:
132 perf_evlist__delete(evlist);
133 return ret;
134}
135
136static struct bpf_object *
137prepare_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
149static 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);
178out:
179 bpf__clear();
180 return ret;
181}
182
183int 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
204int test__bpf(void)
205{
206 pr_debug("Skip BPF test because BPF support is not compiled\n");
207 return TEST_SKIP;
208}
209#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 66f72d3d6677..7b0120abc137 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -166,6 +166,10 @@ static struct test generic_tests[] = {
166 .func = test_session_topology, 166 .func = test_session_topology,
167 }, 167 },
168 { 168 {
169 .desc = "Test BPF filter",
170 .func = test__bpf,
171 },
172 {
169 .func = NULL, 173 .func = NULL,
170 }, 174 },
171}; 175};
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c80486969f83..3c8734a3abbc 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -66,6 +66,7 @@ int test__fdarray__add(void);
66int test__kmod_path__parse(void); 66int test__kmod_path__parse(void);
67int test__thread_map(void); 67int test__thread_map(void);
68int test__llvm(void); 68int test__llvm(void);
69int test__bpf(void);
69int test_session_topology(void); 70int test_session_topology(void);
70 71
71#if defined(__arm__) || defined(__aarch64__) 72#if defined(__arm__) || defined(__aarch64__)
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index e3afa1b60bb5..4c50411371db 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -34,10 +34,32 @@ struct bpf_prog_priv {
34 struct perf_probe_event pev; 34 struct perf_probe_event pev;
35}; 35};
36 36
37static bool libbpf_initialized;
38
39struct bpf_object *
40bpf__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
37struct bpf_object *bpf__prepare_load(const char *filename, bool source) 60struct bpf_object *bpf__prepare_load(const char *filename, bool source)
38{ 61{
39 struct bpf_object *obj; 62 struct bpf_object *obj;
40 static bool libbpf_initialized;
41 63
42 if (!libbpf_initialized) { 64 if (!libbpf_initialized) {
43 libbpf_set_print(libbpf_warning, 65 libbpf_set_print(libbpf_warning,
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 5eb3629eed8b..9caf3ae4acf3 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -34,6 +34,9 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source);
34int bpf__strerror_prepare_load(const char *filename, bool source, 34int bpf__strerror_prepare_load(const char *filename, bool source,
35 int err, char *buf, size_t size); 35 int err, char *buf, size_t size);
36 36
37struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
38 const char *name);
39
37void bpf__clear(void); 40void bpf__clear(void);
38 41
39int bpf__probe(struct bpf_object *obj); 42int bpf__probe(struct bpf_object *obj);
@@ -55,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
55 return ERR_PTR(-ENOTSUP); 58 return ERR_PTR(-ENOTSUP);
56} 59}
57 60
61static inline struct bpf_object *
62bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
63 size_t obj_buf_sz __maybe_unused)
64{
65 return ERR_PTR(-ENOTSUP);
66}
67
58static inline void bpf__clear(void) { } 68static inline void bpf__clear(void) { }
59 69
60static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} 70static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}