aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-11-06 08:49:41 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-06 15:49:24 -0500
commitb31de018a6284a25e0fdfeb028e724f8417ec3b1 (patch)
tree57787908ac178fc06293ec9ee84290f4c81da479
parentd3e0ce393057cfa907a0c4fe7b1ff56d5c30cca5 (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/Build9
-rw-r--r--tools/perf/tests/bpf-script-example.c4
-rw-r--r--tools/perf/tests/llvm.c131
-rw-r--r--tools/perf/tests/llvm.h16
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
31perf-y += parse-no-sample-id-all.o 31perf-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 34perf-y += llvm.o llvm-src-base.o
35perf-y += topology.o 35perf-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
37ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 44ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
38perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 45perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
39endif 46endif
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 */
18static 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
25static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) 16static 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
36static int test__bpf_parsing(void *obj_buf __maybe_unused, 27static 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
44int test__llvm(void) 35static 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
46int
47test_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;
118out:
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); 126int 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
7extern const char test_llvm__bpf_base_prog[];
8
9enum test_llvm__testcase {
10 LLVM_TESTCASE_BASE,
11 __LLVM_TESTCASE_MAX,
12};
13
14int 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