Skip to content

Commit b31de01

Browse files
WangNan0acmel
authored andcommitted
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>
1 parent d3e0ce3 commit b31de01

File tree

4 files changed

+129
-31
lines changed

4 files changed

+129
-31
lines changed

tools/perf/tests/Build

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,16 @@ perf-y += sample-parsing.o
3131
perf-y += parse-no-sample-id-all.o
3232
perf-y += kmod-path.o
3333
perf-y += thread-map.o
34-
perf-y += llvm.o
34+
perf-y += llvm.o llvm-src-base.o
3535
perf-y += topology.o
3636

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+
3744
ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
3845
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
3946
endif

tools/perf/tests/bpf-script-example.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* bpf-script-example.c
3+
* Test basic LLVM building
4+
*/
15
#ifndef LINUX_VERSION_CODE
26
# error Need LINUX_VERSION_CODE
37
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'

tools/perf/tests/llvm.c

Lines changed: 101 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <bpf/libbpf.h>
33
#include <util/llvm-utils.h>
44
#include <util/cache.h>
5+
#include "llvm.h"
56
#include "tests.h"
67
#include "debug.h"
78

@@ -11,85 +12,155 @@ static int perf_config_cb(const char *var, const char *val,
1112
return perf_default_config(var, val, arg);
1213
}
1314

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-
2415
#ifdef HAVE_LIBBPF_SUPPORT
2516
static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
2617
{
2718
struct bpf_object *obj;
2819

2920
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
3021
if (IS_ERR(obj))
31-
return -1;
22+
return TEST_FAIL;
3223
bpf_object__close(obj);
33-
return 0;
24+
return TEST_OK;
3425
}
3526
#else
3627
static int test__bpf_parsing(void *obj_buf __maybe_unused,
3728
size_t obj_buf_sz __maybe_unused)
3829
{
3930
pr_debug("Skip bpf parsing\n");
40-
return 0;
31+
return TEST_OK;
4132
}
4233
#endif
4334

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)
4551
{
46-
char *tmpl_new, *clang_opt_new;
47-
void *obj_buf;
48-
size_t obj_buf_sz;
49-
int err, old_verbose;
52+
const char *source;
53+
const char *desc;
54+
const char *tmpl_old, *clang_opt_old;
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;
5063

5164
perf_config(perf_config_cb, NULL);
5265

5366
/*
5467
* Skip this test if user's .perfconfig doesn't set [llvm] section
5568
* and clang is not found in $PATH, and this is not perf test -v
5669
*/
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())) {
5873
pr_debug("No clang and no verbosive, skip this test\n");
5974
return TEST_SKIP;
6075
}
6176

62-
old_verbose = verbose;
6377
/*
6478
* llvm is verbosity when error. Suppress all error output if
6579
* not 'perf test -v'.
6680
*/
81+
old_verbose = verbose;
6782
if (verbose == 0)
6883
verbose = -1;
6984

85+
*p_obj_buf = NULL;
86+
*p_obj_buf_sz = 0;
87+
7088
if (!llvm_param.clang_bpf_cmd_template)
71-
return -1;
89+
goto out;
7290

7391
if (!llvm_param.clang_opt)
7492
llvm_param.clang_opt = strdup("");
7593

76-
err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog,
77-
llvm_param.clang_bpf_cmd_template);
94+
err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
95+
llvm_param.clang_bpf_cmd_template,
96+
old_verbose ? "" : " 2>/dev/null");
7897
if (err < 0)
79-
return -1;
98+
goto out;
8099
err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
81100
if (err < 0)
82-
return -1;
101+
goto out;
83102

103+
tmpl_old = llvm_param.clang_bpf_cmd_template;
84104
llvm_param.clang_bpf_cmd_template = tmpl_new;
105+
clang_opt_old = llvm_param.clang_opt;
85106
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;
87112

88113
verbose = old_verbose;
89114
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+
}
91125

92-
err = test__bpf_parsing(obj_buf, obj_buf_sz);
93-
free(obj_buf);
94-
return err;
126+
int test__llvm(void)
127+
{
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;
95166
}

tools/perf/tests/llvm.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)