[PATCH v2 12/18] perf bpf: Compile BPF script use builtin clang support

From: Wang Nan
Date: Mon Sep 26 2016 - 03:28:35 EST


After this patch, perf utilizes builtin clang support to build BPF
script, no longer depend on external clang.

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: builtin compiling successful

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

Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Alexei Starovoitov <ast@xxxxxx>
Cc: He Kuang <hekuang@xxxxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
---
tools/perf/util/bpf-loader.c | 15 +++++++++++----
tools/perf/util/c++/clang-c.h | 26 ++++++++++++++++++++++++++
tools/perf/util/c++/clang.cpp | 29 +++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 2b2c9b8..a5ddb8e 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -14,11 +14,11 @@
#include "debug.h"
#include "bpf-loader.h"
#include "bpf-prologue.h"
-#include "llvm-utils.h"
#include "probe-event.h"
#include "probe-finder.h" // for MAX_PROBES
#include "parse-events.h"
#include "llvm-utils.h"
+#include "c++/clang-c.h"

#define DEFINE_PRINT_FN(name, level) \
static int libbpf_##name(const char *fmt, ...) \
@@ -86,9 +86,16 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
void *obj_buf;
size_t obj_buf_sz;

- err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
- if (err)
- return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
+ perf_clang__init();
+ err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz);
+ perf_clang__cleanup();
+ if (err) {
+ pr_debug("bpf: builtin compiling failed: %d, try external compiler\n", err);
+ err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
+ if (err)
+ return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
+ } else
+ pr_debug("bpf: builtin compiling successful\n");
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
free(obj_buf);
} else
diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
index 22b3936..0eadd79 100644
--- a/tools/perf/util/c++/clang-c.h
+++ b/tools/perf/util/c++/clang-c.h
@@ -1,16 +1,42 @@
#ifndef PERF_UTIL_CLANG_C_H
#define PERF_UTIL_CLANG_C_H

+#include <stddef.h> /* for size_t */
+#include <util-cxx.h> /* for __maybe_unused */
+
#ifdef __cplusplus
extern "C" {
#endif

+#ifdef HAVE_LIBCLANGLLVM_SUPPORT
extern void perf_clang__init(void);
extern void perf_clang__cleanup(void);

extern int test__clang_to_IR(void);
extern int test__clang_to_obj(void);

+extern int perf_clang__compile_bpf(const char *filename,
+ void **p_obj_buf,
+ size_t *p_obj_buf_sz);
+#else
+
+
+static inline void perf_clang__init(void) { }
+static inline void perf_clang__cleanup(void) { }
+
+static inline int test__clang_to_IR(void) { return -1; }
+static inline int test__clang_to_obj(void) { return -1;}
+
+static inline int
+perf_clang__compile_bpf(const char *filename __maybe_unused,
+ void **p_obj_buf __maybe_unused,
+ size_t *p_obj_buf_sz __maybe_unused)
+{
+ return -ENOTSUP;
+}
+
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
index ab3a47c..3d24e50 100644
--- a/tools/perf/util/c++/clang.cpp
+++ b/tools/perf/util/c++/clang.cpp
@@ -164,4 +164,33 @@ void perf_clang__cleanup(void)
perf::LLVMCtx.reset(nullptr);
llvm::llvm_shutdown();
}
+
+int perf_clang__compile_bpf(const char *filename,
+ void **p_obj_buf,
+ size_t *p_obj_buf_sz)
+{
+ using namespace perf;
+
+ if (!p_obj_buf || !p_obj_buf_sz)
+ return -EINVAL;
+
+ llvm::opt::ArgStringList CFlags;
+ auto M = getModuleFromSource(std::move(CFlags), filename);
+ if (!M)
+ return -EINVAL;
+ auto O = getBPFObjectFromModule(&*M);
+ if (!O)
+ return -EINVAL;
+
+ size_t size = O->size_in_bytes();
+ void *buffer;
+
+ buffer = malloc(size);
+ if (!buffer)
+ return -ENOMEM;
+ memcpy(buffer, O->data(), size);
+ *p_obj_buf = buffer;
+ *p_obj_buf_sz = size;
+ return 0;
+}
}
--
1.8.3.4