Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
b31de018 d3e0ce39

+129 -31
+8 -1
tools/perf/tests/Build
··· 31 31 perf-y += parse-no-sample-id-all.o 32 32 perf-y += kmod-path.o 33 33 perf-y += thread-map.o 34 - perf-y += llvm.o 34 + perf-y += llvm.o llvm-src-base.o 35 35 perf-y += topology.o 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 ';' >> $@ 36 43 37 44 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 38 45 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
+4
tools/perf/tests/bpf-script-example.c
··· 1 + /* 2 + * bpf-script-example.c 3 + * Test basic LLVM building 4 + */ 1 5 #ifndef LINUX_VERSION_CODE 2 6 # error Need LINUX_VERSION_CODE 3 7 # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
+101 -30
tools/perf/tests/llvm.c
··· 2 2 #include <bpf/libbpf.h> 3 3 #include <util/llvm-utils.h> 4 4 #include <util/cache.h> 5 + #include "llvm.h" 5 6 #include "tests.h" 6 7 #include "debug.h" 7 8 ··· 12 11 return perf_default_config(var, val, arg); 13 12 } 14 13 15 - /* 16 - * Randomly give it a "version" section since we don't really load it 17 - * into kernel 18 - */ 19 - static const char test_bpf_prog[] = 20 - "__attribute__((section(\"do_fork\"), used)) " 21 - "int fork(void *ctx) {return 0;} " 22 - "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";" 23 - "int _version __attribute__((section(\"version\"), used)) = 0x40100;"; 24 - 25 14 #ifdef HAVE_LIBBPF_SUPPORT 26 15 static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) 27 16 { ··· 19 28 20 29 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); 21 30 if (IS_ERR(obj)) 22 - return -1; 31 + return TEST_FAIL; 23 32 bpf_object__close(obj); 24 - return 0; 33 + return TEST_OK; 25 34 } 26 35 #else 27 36 static int test__bpf_parsing(void *obj_buf __maybe_unused, 28 37 size_t obj_buf_sz __maybe_unused) 29 38 { 30 39 pr_debug("Skip bpf parsing\n"); 31 - return 0; 40 + return TEST_OK; 32 41 } 33 42 #endif 34 43 35 - int test__llvm(void) 44 + static struct { 45 + const char *source; 46 + const char *desc; 47 + } bpf_source_table[__LLVM_TESTCASE_MAX] = { 48 + [LLVM_TESTCASE_BASE] = { 49 + .source = test_llvm__bpf_base_prog, 50 + .desc = "Basic BPF llvm compiling test", 51 + }, 52 + }; 53 + 54 + 55 + int 56 + test_llvm__fetch_bpf_obj(void **p_obj_buf, 57 + size_t *p_obj_buf_sz, 58 + enum test_llvm__testcase index, 59 + bool force) 36 60 { 37 - char *tmpl_new, *clang_opt_new; 38 - void *obj_buf; 39 - size_t obj_buf_sz; 40 - int err, old_verbose; 61 + const char *source; 62 + const char *desc; 63 + const char *tmpl_old, *clang_opt_old; 64 + char *tmpl_new = NULL, *clang_opt_new = NULL; 65 + int err, old_verbose, ret = TEST_FAIL; 66 + 67 + if (index >= __LLVM_TESTCASE_MAX) 68 + return TEST_FAIL; 69 + 70 + source = bpf_source_table[index].source; 71 + desc = bpf_source_table[index].desc; 41 72 42 73 perf_config(perf_config_cb, NULL); 43 74 ··· 67 54 * Skip this test if user's .perfconfig doesn't set [llvm] section 68 55 * and clang is not found in $PATH, and this is not perf test -v 69 56 */ 70 - if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { 57 + if (!force && (verbose == 0 && 58 + !llvm_param.user_set_param && 59 + llvm__search_clang())) { 71 60 pr_debug("No clang and no verbosive, skip this test\n"); 72 61 return TEST_SKIP; 73 62 } 74 63 75 - old_verbose = verbose; 76 64 /* 77 65 * llvm is verbosity when error. Suppress all error output if 78 66 * not 'perf test -v'. 79 67 */ 68 + old_verbose = verbose; 80 69 if (verbose == 0) 81 70 verbose = -1; 82 71 72 + *p_obj_buf = NULL; 73 + *p_obj_buf_sz = 0; 74 + 83 75 if (!llvm_param.clang_bpf_cmd_template) 84 - return -1; 76 + goto out; 85 77 86 78 if (!llvm_param.clang_opt) 87 79 llvm_param.clang_opt = strdup(""); 88 80 89 - err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, 90 - llvm_param.clang_bpf_cmd_template); 81 + err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, 82 + llvm_param.clang_bpf_cmd_template, 83 + old_verbose ? "" : " 2>/dev/null"); 91 84 if (err < 0) 92 - return -1; 85 + goto out; 93 86 err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); 94 87 if (err < 0) 95 - return -1; 88 + goto out; 96 89 90 + tmpl_old = llvm_param.clang_bpf_cmd_template; 97 91 llvm_param.clang_bpf_cmd_template = tmpl_new; 92 + clang_opt_old = llvm_param.clang_opt; 98 93 llvm_param.clang_opt = clang_opt_new; 99 - err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz); 94 + 95 + err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz); 96 + 97 + llvm_param.clang_bpf_cmd_template = tmpl_old; 98 + llvm_param.clang_opt = clang_opt_old; 100 99 101 100 verbose = old_verbose; 102 101 if (err) 103 - return TEST_FAIL; 102 + goto out; 104 103 105 - err = test__bpf_parsing(obj_buf, obj_buf_sz); 106 - free(obj_buf); 107 - return err; 104 + ret = TEST_OK; 105 + out: 106 + free(tmpl_new); 107 + free(clang_opt_new); 108 + if (ret != TEST_OK) 109 + pr_debug("Failed to compile test case: '%s'\n", desc); 110 + return ret; 111 + } 112 + 113 + int test__llvm(void) 114 + { 115 + enum test_llvm__testcase i; 116 + 117 + for (i = 0; i < __LLVM_TESTCASE_MAX; i++) { 118 + int ret; 119 + void *obj_buf = NULL; 120 + size_t obj_buf_sz = 0; 121 + 122 + ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 123 + i, false); 124 + 125 + if (ret == TEST_OK) { 126 + ret = test__bpf_parsing(obj_buf, obj_buf_sz); 127 + if (ret != TEST_OK) 128 + pr_debug("Failed to parse test case '%s'\n", 129 + bpf_source_table[i].desc); 130 + } 131 + free(obj_buf); 132 + 133 + switch (ret) { 134 + case TEST_SKIP: 135 + return TEST_SKIP; 136 + case TEST_OK: 137 + break; 138 + default: 139 + /* 140 + * Test 0 is the basic LLVM test. If test 0 141 + * fail, the basic LLVM support not functional 142 + * so the whole test should fail. If other test 143 + * case fail, it can be fixed by adjusting 144 + * config so don't report error. 145 + */ 146 + if (i == 0) 147 + return TEST_FAIL; 148 + else 149 + return TEST_SKIP; 150 + } 151 + } 152 + return TEST_OK; 108 153 }
+16
tools/perf/tests/llvm.h
··· 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