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

perf clang: Compile BPF script using builtin clang support

After this patch, perf utilizes builtin clang support to build BPF
script, no longer depend on external clang, but fallbacking to it
if for some reason the builtin compiling framework fails.

Test:

$ type clang
-bash: type: clang: not found
$ cat ~/.perfconfig
$ echo '#define LINUX_VERSION_CODE 0x040700' > ./test.c
$ cat ./tools/perf/tests/bpf-script-example.c >> ./test.c
$ ./perf record -v --dry-run -e ./test.c 2>&1 | grep builtin
bpf: successfull builtin compilation
$

Can't pass cflags so unable to include kernel headers now. Will be fixed
by following commits.

Committer notes:

Make sure '-v' comes before the '-e ./test.c' in the command line otherwise the
'verbose' variable will not be set when the bpf event is parsed and thus the
pr_debug indicating a 'successfull builtin compilation' will not be output, as
the debug level (1) will be less than what 'verbose' has at that point (0).

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Joe Stringer <joe@ovn.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/20161126070354.141764-16-wangnan0@huawei.com
[ Spell check/reflow successfull pr_debug string ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
edd695b0 5e08a765

+66 -4
+11 -4
tools/perf/util/bpf-loader.c
··· 14 14 #include "debug.h" 15 15 #include "bpf-loader.h" 16 16 #include "bpf-prologue.h" 17 - #include "llvm-utils.h" 18 17 #include "probe-event.h" 19 18 #include "probe-finder.h" // for MAX_PROBES 20 19 #include "parse-events.h" 21 20 #include "llvm-utils.h" 21 + #include "c++/clang-c.h" 22 22 23 23 #define DEFINE_PRINT_FN(name, level) \ 24 24 static int libbpf_##name(const char *fmt, ...) \ ··· 86 86 void *obj_buf; 87 87 size_t obj_buf_sz; 88 88 89 - err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); 90 - if (err) 91 - return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); 89 + perf_clang__init(); 90 + err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz); 91 + perf_clang__cleanup(); 92 + if (err) { 93 + pr_warning("bpf: builtin compilation failed: %d, try external compiler\n", err); 94 + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); 95 + if (err) 96 + return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); 97 + } else 98 + pr_debug("bpf: successfull builtin compilation\n"); 92 99 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); 93 100 94 101 if (!IS_ERR(obj) && llvm_param.dump_obj)
+26
tools/perf/util/c++/clang-c.h
··· 1 1 #ifndef PERF_UTIL_CLANG_C_H 2 2 #define PERF_UTIL_CLANG_C_H 3 3 4 + #include <stddef.h> /* for size_t */ 5 + #include <util-cxx.h> /* for __maybe_unused */ 6 + 4 7 #ifdef __cplusplus 5 8 extern "C" { 6 9 #endif 7 10 11 + #ifdef HAVE_LIBCLANGLLVM_SUPPORT 8 12 extern void perf_clang__init(void); 9 13 extern void perf_clang__cleanup(void); 10 14 11 15 extern int test__clang_to_IR(void); 12 16 extern int test__clang_to_obj(void); 17 + 18 + extern int perf_clang__compile_bpf(const char *filename, 19 + void **p_obj_buf, 20 + size_t *p_obj_buf_sz); 21 + #else 22 + 23 + 24 + static inline void perf_clang__init(void) { } 25 + static inline void perf_clang__cleanup(void) { } 26 + 27 + static inline int test__clang_to_IR(void) { return -1; } 28 + static inline int test__clang_to_obj(void) { return -1;} 29 + 30 + static inline int 31 + perf_clang__compile_bpf(const char *filename __maybe_unused, 32 + void **p_obj_buf __maybe_unused, 33 + size_t *p_obj_buf_sz __maybe_unused) 34 + { 35 + return -ENOTSUP; 36 + } 37 + 38 + #endif 13 39 14 40 #ifdef __cplusplus 15 41 }
+29
tools/perf/util/c++/clang.cpp
··· 163 163 perf::LLVMCtx.reset(nullptr); 164 164 llvm::llvm_shutdown(); 165 165 } 166 + 167 + int perf_clang__compile_bpf(const char *filename, 168 + void **p_obj_buf, 169 + size_t *p_obj_buf_sz) 170 + { 171 + using namespace perf; 172 + 173 + if (!p_obj_buf || !p_obj_buf_sz) 174 + return -EINVAL; 175 + 176 + llvm::opt::ArgStringList CFlags; 177 + auto M = getModuleFromSource(std::move(CFlags), filename); 178 + if (!M) 179 + return -EINVAL; 180 + auto O = getBPFObjectFromModule(&*M); 181 + if (!O) 182 + return -EINVAL; 183 + 184 + size_t size = O->size_in_bytes(); 185 + void *buffer; 186 + 187 + buffer = malloc(size); 188 + if (!buffer) 189 + return -ENOMEM; 190 + memcpy(buffer, O->data(), size); 191 + *p_obj_buf = buffer; 192 + *p_obj_buf_sz = size; 193 + return 0; 194 + } 166 195 }