Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752824AbcLFHPm (ORCPT ); Tue, 6 Dec 2016 02:15:42 -0500 Received: from szxga02-in.huawei.com ([119.145.14.65]:46185 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752335AbcLFHOp (ORCPT ); Tue, 6 Dec 2016 02:14:45 -0500 From: Wang Nan To: CC: , , Wang Nan , Arnaldo Carvalho de Melo , "Alexei Starovoitov" , He Kuang , Jiri Olsa , Zefan Li , Subject: [PATCH v4 10/18] perf clang jit: Actually JIT and hook in bpf loader Date: Tue, 6 Dec 2016 07:13:48 +0000 Message-ID: <20161206071356.5312-11-wangnan0@huawei.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20161206071356.5312-1-wangnan0@huawei.com> References: <20161206071356.5312-1-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5109 Lines: 168 Makes perf_clang__compile_bpf() actually uses clang jit to compile perf hooks. Returns a map through perf_clang__compile_bpf(), and set hooks after bpf_object is created. After this path jitting takes actions for bpf loader. For example: $ cat ./test.c /******************************************************/ #define SEC(name) __attribute__((section(name), used)) SEC("dofork=_do_fork") int dofork(void *ctx) { return 0; } extern int printf(const char *fmt, ...); SEC("perfhook:record_start") void record_start(void) { printf("Welcom to perf record\n"); } SEC("perfhook:record_end") void record_end(void) { printf("Goodbye, perf record\n"); } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /******************************************************/ $ perf record -e ./test.c sleep 1 Welcom to perf record [ perf record: Woken up 1 times to write data ] Goodbye, perf record [ perf record: Captured and wrote 0.014 MB perf.data ] Signed-off-by: Wang Nan Cc: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: He Kuang Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com --- tools/perf/util/bpf-loader.c | 11 ++++++++++- tools/perf/util/c++/clang-c.h | 18 ++++++++++++++++-- tools/perf/util/c++/clang.cpp | 28 +++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 36c8611..bf61a6f 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -85,9 +85,11 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) int err; void *obj_buf; size_t obj_buf_sz; + jitted_funcs_map_t jitted_funcs_map; perf_clang__init(); - err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz); + err = perf_clang__compile_bpf(filename, &obj_buf, + &obj_buf_sz, &jitted_funcs_map); perf_clang__cleanup(); if (err) { pr_warning("bpf: builtin compilation failed: %d, try external compiler\n", err); @@ -101,6 +103,13 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) if (!IS_ERR(obj) && llvm_param.dump_obj) llvm__dump_obj(filename, obj_buf, obj_buf_sz); + /* + * Call perf_clang__hook_jitted_func even IS_ERR(obj) to make sure + * the C++ map pointer is deleted. + */ + if (jitted_funcs_map) + perf_clang__hook_jitted_func(jitted_funcs_map, obj, IS_ERR(obj)); + free(obj_buf); } else obj = bpf_object__open(filename); diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h index 9f75e41..021b1ad 100644 --- a/tools/perf/util/c++/clang-c.h +++ b/tools/perf/util/c++/clang-c.h @@ -8,6 +8,7 @@ extern "C" { #endif +typedef void *jitted_funcs_map_t; #ifdef HAVE_LIBCLANGLLVM_SUPPORT extern void perf_clang__init(void); extern void perf_clang__cleanup(void); @@ -20,7 +21,11 @@ extern void test__clang_callback(int x); extern int perf_clang__compile_bpf(const char *filename, void **p_obj_buf, - size_t *p_obj_buf_sz); + size_t *p_obj_buf_sz, + jitted_funcs_map_t *p_funcs_map); + +extern int +perf_clang__hook_jitted_func(jitted_funcs_map_t map, void *ctx, bool is_err); #else @@ -34,7 +39,16 @@ static inline int test__clang_jit(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) + size_t *p_obj_buf_sz __maybe_unused, + jitted_funcs_map_t *p_funcs_map __maybe_unused) +{ + return -ENOTSUP; +} + +static inline int +perf_clang__hook_jitted_func(jitted_funcs_map_t map __maybe_unused, + void *ctx __maybe_unused, + bool is_err __maybe_unused) { return -ENOTSUP; } diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 3ce2e0e..4a98597 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -391,7 +391,8 @@ void perf_clang__cleanup(void) int perf_clang__compile_bpf(const char *_filename, void **p_obj_buf, - size_t *p_obj_buf_sz) + size_t *p_obj_buf_sz, + jitted_funcs_map_t *p_funcs_map) { using namespace perf; @@ -418,6 +419,31 @@ int perf_clang__compile_bpf(const char *_filename, memcpy(buffer, O->data(), size); *p_obj_buf = buffer; *p_obj_buf_sz = size; + + if (M->doJIT()) + return -1; + + if (p_funcs_map) + *p_funcs_map = (jitted_funcs_map_t)(M->copyJITResult()); + return 0; +} + +int perf_clang__hook_jitted_func(jitted_funcs_map_t map, void *ctx, bool is_err) +{ + std::unique_ptr + hook_map((perf::PerfModule::HookMap *)map); + + /* Do nothing but ensure map is deleted */ + if (is_err) + return -1; + + for (auto i : *hook_map) { + const char *hook_name = i.first.c_str(); + perf_hook_func_t hook_func = i.second; + + if (perf_hooks__set_hook(hook_name, hook_func, ctx)) + return -1; + } return 0; } } -- 2.10.1