diff options
author | Wang Nan <wangnan0@huawei.com> | 2015-11-06 08:49:41 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-11-06 15:49:24 -0500 |
commit | b31de018a6284a25e0fdfeb028e724f8417ec3b1 (patch) | |
tree | 57787908ac178fc06293ec9ee84290f4c81da479 | |
parent | d3e0ce393057cfa907a0c4fe7b1ff56d5c30cca5 (diff) |
perf test: Enhance the LLVM test: update basic BPF test program
This patch replaces the original toy BPF program with the previously
introduced bpf-script-example.c. Dynamically embeddeding it into
'llvm-src-base.c'.
The newly introduced BPF program attaches a BPF program to
'sys_epoll_pwait()'. perf itself never use that syscall, so further test
can verify their result with it. The program would generate 1 sample in
every 2 calls of epoll_pwait() system call.
Since the resulting BPF object is useful per se for further tests,
test_llvm__fetch_bpf_obj() is introduced for creating BPF objects from
source. The LLVM test was rewritten to use it.
Committer note:
Running it:
[root@zoo wb]# perf test -v LLVM
35: Test LLVM searching and compiling :
--- start ---
test child forked, pid 17740
Kernel build dir is set to /lib/modules/4.3.0-rc1+/build
set env: KBUILD_DIR=/lib/modules/4.3.0-rc1+/build
unset env: KBUILD_OPTS
include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: NR_CPUS=4
set env: LINUX_VERSION_CODE=0x40300
set env: CLANG_EXEC=/usr/libexec/icecc/bin/clang
set env: CLANG_OPTIONS=-xc
set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h
set env: WORKING_DIR=/lib/modules/4.3.0-rc1+/build
set env: CLANG_SOURCE=-
llvm compiling command template: echo '/*
* bpf-script-example.c
* Test basic LLVM building
*/
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
#endif
#define BPF_ANY 0
#define BPF_MAP_TYPE_ARRAY 2
#define BPF_FUNC_map_lookup_elem 1
#define BPF_FUNC_map_update_elem 2
static void *(*bpf_map_lookup_elem)(void *map, void *key) =
(void *) BPF_FUNC_map_lookup_elem;
static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
(void *) BPF_FUNC_map_update_elem;
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
};
#define SEC(NAME) __attribute__((section(NAME), used))
struct bpf_map_def SEC("maps") flip_table = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 1,
};
SEC("func=sys_epoll_pwait")
int bpf_func__sys_epoll_pwait(void *ctx)
{
int ind =0;
int *flag = bpf_map_lookup_elem(&flip_table, &ind);
int new_flag;
if (!flag)
return 0;
/* flip flag and store back */
new_flag = !*flag;
bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY);
return new_flag;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o -
test child finished with 0
---- end ----
Test LLVM searching and compiling: Ok
[root@zoo wb]#
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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-6-git-send-email-wangnan0@huawei.com
Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/tests/Build | 9 | ||||
-rw-r--r-- | tools/perf/tests/bpf-script-example.c | 4 | ||||
-rw-r--r-- | tools/perf/tests/llvm.c | 131 | ||||
-rw-r--r-- | tools/perf/tests/llvm.h | 16 |
4 files changed, 129 insertions, 31 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 50de2253cff6..6c095b3d92a9 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -31,9 +31,16 @@ perf-y += sample-parsing.o | |||
31 | perf-y += parse-no-sample-id-all.o | 31 | perf-y += parse-no-sample-id-all.o |
32 | perf-y += kmod-path.o | 32 | perf-y += kmod-path.o |
33 | perf-y += thread-map.o | 33 | perf-y += thread-map.o |
34 | perf-y += llvm.o | 34 | perf-y += llvm.o llvm-src-base.o |
35 | perf-y += topology.o | 35 | perf-y += topology.o |
36 | 36 | ||
37 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c | ||
38 | $(call rule_mkdir) | ||
39 | $(Q)echo '#include <tests/llvm.h>' > $@ | ||
40 | $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@ | ||
41 | $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ | ||
42 | $(Q)echo ';' >> $@ | ||
43 | |||
37 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) | 44 | ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) |
38 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o | 45 | perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o |
39 | endif | 46 | endif |
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c index 410a70b93b93..0ec9c2c03164 100644 --- a/tools/perf/tests/bpf-script-example.c +++ b/tools/perf/tests/bpf-script-example.c | |||
@@ -1,3 +1,7 @@ | |||
1 | /* | ||
2 | * bpf-script-example.c | ||
3 | * Test basic LLVM building | ||
4 | */ | ||
1 | #ifndef LINUX_VERSION_CODE | 5 | #ifndef LINUX_VERSION_CODE |
2 | # error Need LINUX_VERSION_CODE | 6 | # error Need LINUX_VERSION_CODE |
3 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' | 7 | # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' |
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index 8f713f6d32f3..05683c5f183e 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <bpf/libbpf.h> | 2 | #include <bpf/libbpf.h> |
3 | #include <util/llvm-utils.h> | 3 | #include <util/llvm-utils.h> |
4 | #include <util/cache.h> | 4 | #include <util/cache.h> |
5 | #include "llvm.h" | ||
5 | #include "tests.h" | 6 | #include "tests.h" |
6 | #include "debug.h" | 7 | #include "debug.h" |
7 | 8 | ||
@@ -11,16 +12,6 @@ static int perf_config_cb(const char *var, const char *val, | |||
11 | return perf_default_config(var, val, arg); | 12 | return perf_default_config(var, val, arg); |
12 | } | 13 | } |
13 | 14 | ||
14 | /* | ||
15 | * Randomly give it a "version" section since we don't really load it | ||
16 | * into kernel | ||
17 | */ | ||
18 | static const char test_bpf_prog[] = | ||
19 | "__attribute__((section(\"do_fork\"), used)) " | ||
20 | "int fork(void *ctx) {return 0;} " | ||
21 | "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";" | ||
22 | "int _version __attribute__((section(\"version\"), used)) = 0x40100;"; | ||
23 | |||
24 | #ifdef HAVE_LIBBPF_SUPPORT | 15 | #ifdef HAVE_LIBBPF_SUPPORT |
25 | static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) | 16 | static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) |
26 | { | 17 | { |
@@ -28,25 +19,47 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) | |||
28 | 19 | ||
29 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); | 20 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); |
30 | if (IS_ERR(obj)) | 21 | if (IS_ERR(obj)) |
31 | return -1; | 22 | return TEST_FAIL; |
32 | bpf_object__close(obj); | 23 | bpf_object__close(obj); |
33 | return 0; | 24 | return TEST_OK; |
34 | } | 25 | } |
35 | #else | 26 | #else |
36 | static int test__bpf_parsing(void *obj_buf __maybe_unused, | 27 | static int test__bpf_parsing(void *obj_buf __maybe_unused, |
37 | size_t obj_buf_sz __maybe_unused) | 28 | size_t obj_buf_sz __maybe_unused) |
38 | { | 29 | { |
39 | pr_debug("Skip bpf parsing\n"); | 30 | pr_debug("Skip bpf parsing\n"); |
40 | return 0; | 31 | return TEST_OK; |
41 | } | 32 | } |
42 | #endif | 33 | #endif |
43 | 34 | ||
44 | int test__llvm(void) | 35 | static struct { |
36 | const char *source; | ||
37 | const char *desc; | ||
38 | } bpf_source_table[__LLVM_TESTCASE_MAX] = { | ||
39 | [LLVM_TESTCASE_BASE] = { | ||
40 | .source = test_llvm__bpf_base_prog, | ||
41 | .desc = "Basic BPF llvm compiling test", | ||
42 | }, | ||
43 | }; | ||
44 | |||
45 | |||
46 | int | ||
47 | test_llvm__fetch_bpf_obj(void **p_obj_buf, | ||
48 | size_t *p_obj_buf_sz, | ||
49 | enum test_llvm__testcase index, | ||
50 | bool force) | ||
45 | { | 51 | { |
46 | char *tmpl_new, *clang_opt_new; | 52 | const char *source; |
47 | void *obj_buf; | 53 | const char *desc; |
48 | size_t obj_buf_sz; | 54 | const char *tmpl_old, *clang_opt_old; |
49 | int err, old_verbose; | 55 | char *tmpl_new = NULL, *clang_opt_new = NULL; |
56 | int err, old_verbose, ret = TEST_FAIL; | ||
57 | |||
58 | if (index >= __LLVM_TESTCASE_MAX) | ||
59 | return TEST_FAIL; | ||
60 | |||
61 | source = bpf_source_table[index].source; | ||
62 | desc = bpf_source_table[index].desc; | ||
50 | 63 | ||
51 | perf_config(perf_config_cb, NULL); | 64 | perf_config(perf_config_cb, NULL); |
52 | 65 | ||
@@ -54,42 +67,100 @@ int test__llvm(void) | |||
54 | * Skip this test if user's .perfconfig doesn't set [llvm] section | 67 | * Skip this test if user's .perfconfig doesn't set [llvm] section |
55 | * and clang is not found in $PATH, and this is not perf test -v | 68 | * and clang is not found in $PATH, and this is not perf test -v |
56 | */ | 69 | */ |
57 | if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { | 70 | if (!force && (verbose == 0 && |
71 | !llvm_param.user_set_param && | ||
72 | llvm__search_clang())) { | ||
58 | pr_debug("No clang and no verbosive, skip this test\n"); | 73 | pr_debug("No clang and no verbosive, skip this test\n"); |
59 | return TEST_SKIP; | 74 | return TEST_SKIP; |
60 | } | 75 | } |
61 | 76 | ||
62 | old_verbose = verbose; | ||
63 | /* | 77 | /* |
64 | * llvm is verbosity when error. Suppress all error output if | 78 | * llvm is verbosity when error. Suppress all error output if |
65 | * not 'perf test -v'. | 79 | * not 'perf test -v'. |
66 | */ | 80 | */ |
81 | old_verbose = verbose; | ||
67 | if (verbose == 0) | 82 | if (verbose == 0) |
68 | verbose = -1; | 83 | verbose = -1; |
69 | 84 | ||
85 | *p_obj_buf = NULL; | ||
86 | *p_obj_buf_sz = 0; | ||
87 | |||
70 | if (!llvm_param.clang_bpf_cmd_template) | 88 | if (!llvm_param.clang_bpf_cmd_template) |
71 | return -1; | 89 | goto out; |
72 | 90 | ||
73 | if (!llvm_param.clang_opt) | 91 | if (!llvm_param.clang_opt) |
74 | llvm_param.clang_opt = strdup(""); | 92 | llvm_param.clang_opt = strdup(""); |
75 | 93 | ||
76 | err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, | 94 | err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, |
77 | llvm_param.clang_bpf_cmd_template); | 95 | llvm_param.clang_bpf_cmd_template, |
96 | old_verbose ? "" : " 2>/dev/null"); | ||
78 | if (err < 0) | 97 | if (err < 0) |
79 | return -1; | 98 | goto out; |
80 | err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); | 99 | err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); |
81 | if (err < 0) | 100 | if (err < 0) |
82 | return -1; | 101 | goto out; |
83 | 102 | ||
103 | tmpl_old = llvm_param.clang_bpf_cmd_template; | ||
84 | llvm_param.clang_bpf_cmd_template = tmpl_new; | 104 | llvm_param.clang_bpf_cmd_template = tmpl_new; |
105 | clang_opt_old = llvm_param.clang_opt; | ||
85 | llvm_param.clang_opt = clang_opt_new; | 106 | llvm_param.clang_opt = clang_opt_new; |
86 | err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz); | 107 | |
108 | err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz); | ||
109 | |||
110 | llvm_param.clang_bpf_cmd_template = tmpl_old; | ||
111 | llvm_param.clang_opt = clang_opt_old; | ||
87 | 112 | ||
88 | verbose = old_verbose; | 113 | verbose = old_verbose; |
89 | if (err) | 114 | if (err) |
90 | return TEST_FAIL; | 115 | goto out; |
116 | |||
117 | ret = TEST_OK; | ||
118 | out: | ||
119 | free(tmpl_new); | ||
120 | free(clang_opt_new); | ||
121 | if (ret != TEST_OK) | ||
122 | pr_debug("Failed to compile test case: '%s'\n", desc); | ||
123 | return ret; | ||
124 | } | ||
91 | 125 | ||
92 | err = test__bpf_parsing(obj_buf, obj_buf_sz); | 126 | int test__llvm(void) |
93 | free(obj_buf); | 127 | { |
94 | return err; | 128 | enum test_llvm__testcase i; |
129 | |||
130 | for (i = 0; i < __LLVM_TESTCASE_MAX; i++) { | ||
131 | int ret; | ||
132 | void *obj_buf = NULL; | ||
133 | size_t obj_buf_sz = 0; | ||
134 | |||
135 | ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, | ||
136 | i, false); | ||
137 | |||
138 | if (ret == TEST_OK) { | ||
139 | ret = test__bpf_parsing(obj_buf, obj_buf_sz); | ||
140 | if (ret != TEST_OK) | ||
141 | pr_debug("Failed to parse test case '%s'\n", | ||
142 | bpf_source_table[i].desc); | ||
143 | } | ||
144 | free(obj_buf); | ||
145 | |||
146 | switch (ret) { | ||
147 | case TEST_SKIP: | ||
148 | return TEST_SKIP; | ||
149 | case TEST_OK: | ||
150 | break; | ||
151 | default: | ||
152 | /* | ||
153 | * Test 0 is the basic LLVM test. If test 0 | ||
154 | * fail, the basic LLVM support not functional | ||
155 | * so the whole test should fail. If other test | ||
156 | * case fail, it can be fixed by adjusting | ||
157 | * config so don't report error. | ||
158 | */ | ||
159 | if (i == 0) | ||
160 | return TEST_FAIL; | ||
161 | else | ||
162 | return TEST_SKIP; | ||
163 | } | ||
164 | } | ||
165 | return TEST_OK; | ||
95 | } | 166 | } |
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h new file mode 100644 index 000000000000..bd63cee687b5 --- /dev/null +++ b/tools/perf/tests/llvm.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef PERF_TEST_LLVM_H | ||
2 | #define PERF_TEST_LLVM_H | ||
3 | |||
4 | #include <stddef.h> /* for size_t */ | ||
5 | #include <stdbool.h> /* for bool */ | ||
6 | |||
7 | extern const char test_llvm__bpf_base_prog[]; | ||
8 | |||
9 | enum test_llvm__testcase { | ||
10 | LLVM_TESTCASE_BASE, | ||
11 | __LLVM_TESTCASE_MAX, | ||
12 | }; | ||
13 | |||
14 | int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, | ||
15 | enum test_llvm__testcase index, bool force); | ||
16 | #endif | ||