Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752937AbcLFHPz (ORCPT ); Tue, 6 Dec 2016 02:15:55 -0500 Received: from szxga02-in.huawei.com ([119.145.14.65]:46150 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752263AbcLFHOp (ORCPT ); Tue, 6 Dec 2016 02:14:45 -0500 From: Wang Nan To: CC: , , Wang Nan , Arnaldo Carvalho de Melo , He Kuang , Jiri Olsa , Zefan Li , Subject: [PATCH v4 08/18] perf clang jit: add PerfModule::doJIT to JIT perfhook functions Date: Tue, 6 Dec 2016 07:13:46 +0000 Message-ID: <20161206071356.5312-9-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: 8486 Lines: 306 PerfModule::doJIT JIT compile perfhook functions and saves result into a map. Add a test case for it. At this stage perfhook functions can do no useful things because they can't invoke external functions and can't return value. Following commits are going to make improvment. Don't hook functions right after jitted because bpf_object is unavailable during jitting but it should be the context of jitted functions. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Arnaldo Carvalho de Melo Cc: He Kuang Cc: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com --- tools/perf/tests/bpf-script-example.c | 8 ++++ tools/perf/tests/clang.c | 4 ++ tools/perf/util/c++/clang-c.h | 2 + tools/perf/util/c++/clang-test.cpp | 32 +++++++++++++++- tools/perf/util/c++/clang.cpp | 71 +++++++++++++++++++++++++++++++++++ tools/perf/util/c++/clang.h | 13 +++++++ 6 files changed, 128 insertions(+), 2 deletions(-) diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c index 268e5f8..265036e 100644 --- a/tools/perf/tests/bpf-script-example.c +++ b/tools/perf/tests/bpf-script-example.c @@ -46,3 +46,11 @@ int bpf_func__SyS_epoll_wait(void *ctx) } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; + +#ifdef TEST_PERF_HOOK +SEC("perfhook:test") +void hook_test(void) +{ + return; +} +#endif diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c index f853e24..e7b35c4 100644 --- a/tools/perf/tests/clang.c +++ b/tools/perf/tests/clang.c @@ -16,6 +16,10 @@ static struct { .func = test__clang_to_obj, .desc = "builtin clang compile C source to ELF object", }, + { + .func = test__clang_jit, + .desc = "builtin clang compile mixed BPF and native code", + }, #endif }; diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h index 0eadd79..5ebcb41 100644 --- a/tools/perf/util/c++/clang-c.h +++ b/tools/perf/util/c++/clang-c.h @@ -14,6 +14,7 @@ extern void perf_clang__cleanup(void); extern int test__clang_to_IR(void); extern int test__clang_to_obj(void); +extern int test__clang_jit(void); extern int perf_clang__compile_bpf(const char *filename, void **p_obj_buf, @@ -26,6 +27,7 @@ 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 test__clang_jit(void) { return -1;} static inline int perf_clang__compile_bpf(const char *filename __maybe_unused, diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp index fb05e56..2b4aa8d 100644 --- a/tools/perf/util/c++/clang-test.cpp +++ b/tools/perf/util/c++/clang-test.cpp @@ -5,6 +5,7 @@ #include #include +#include #include class perf_clang_scope { @@ -14,7 +15,7 @@ public: }; static std::unique_ptr -__test__clang_to_IR(void) +__test__clang_to_IR(bool perfhook) { unsigned int kernel_version; @@ -23,14 +24,22 @@ __test__clang_to_IR(void) std::string cflag_kver("-DLINUX_VERSION_CODE=" + std::to_string(kernel_version)); + std::string cflag_perfhook(perfhook ? "-DTEST_PERF_HOOK=1" : ""); std::unique_ptr M = - perf::getModuleFromSource({cflag_kver.c_str()}, + perf::getModuleFromSource({cflag_kver.c_str(), + cflag_perfhook.c_str()}, "perf-test.c", test_llvm__bpf_base_prog); return M; } +static std::unique_ptr +__test__clang_to_IR(void) +{ + return __test__clang_to_IR(false); +} + extern "C" { int test__clang_to_IR(void) { @@ -59,4 +68,23 @@ int test__clang_to_obj(void) return 0; } +int test__clang_jit(void) +{ + perf_clang_scope _scope; + + auto M = __test__clang_to_IR(true); + if (!M) + return -1; + + if (M->doJIT()) + return -1; + + std::unique_ptr hooks(M->copyJITResult()); + for (auto i : *hooks) + perf_hooks__set_hook(i.first.c_str(), i.second, NULL); + + perf_hooks__invoke_test(); + return 0; +} + } diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 8a0f818..b996ec6 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -14,9 +14,14 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/Option/Option.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/TargetRegistry.h" @@ -24,11 +29,13 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include +#include #include "clang.h" #include "clang-c.h" #include "llvm-utils.h" #include "util-cxx.h" +#include "perf-hooks.h" namespace perf { @@ -190,6 +197,66 @@ PerfModule::toBPFObject(void) return std::move(Buffer); } +/* + * Use a global memory manager so allocated code and data won't be released + * when object destroy. + */ +static llvm::SectionMemoryManager JITMemoryManager; + +int PerfModule::doJIT(void) +{ + using namespace orc; + + prepareJIT(); + + std::unique_ptr TM(EngineBuilder().selectTarget()); + if (!TM) { + llvm::errs() << "Can't get target machine\n"; + return -1; + } + const DataLayout DL(TM->createDataLayout()); + Module->setDataLayout(DL); + Module->setTargetTriple(TM->getTargetTriple().normalize()); + + ObjectLinkingLayer<> ObjectLayer; + IRCompileLayer CompileLayer(ObjectLayer, SimpleCompiler(*TM)); + + auto Resolver = createLambdaResolver( + [](const std::string &Name) { + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { + return RuntimeDyld::SymbolInfo(nullptr); + }); + + std::vector Ms; + Ms.push_back(getModule()); + CompileLayer.addModuleSet(std::move(Ms), + &JITMemoryManager, + std::move(Resolver)); + + + for (Function *F : JITFunctions) { + JITSymbol sym = CompileLayer.findSymbol(F->getName().str(), true); + + /* + * Type of F->getSection() is moving from + * const char * to StringRef. + * Convert it to std::string so we don't need + * consider this API change. + */ + std::string sec(F->getSection()); + std::string hook(&sec.c_str()[sizeof("perfhook:") - 1]); + perf_hook_func_t func = (perf_hook_func_t)(intptr_t)sym.getAddress(); + + if (JITResult[hook]) + llvm::errs() << "Warning: multiple functions on hook " + << hook << ", only one is used\n"; + JITResult[hook] = func; + } + return 0; +} + class ClangOptions { llvm::SmallString FileName; llvm::SmallString<64> KVerDef; @@ -295,6 +362,10 @@ void perf_clang__init(void) LLVMInitializeBPFTarget(); LLVMInitializeBPFTargetMC(); LLVMInitializeBPFAsmPrinter(); + + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); } void perf_clang__cleanup(void) diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h index 1eb71a6..df2eb8f 100644 --- a/tools/perf/util/c++/clang.h +++ b/tools/perf/util/c++/clang.h @@ -7,18 +7,26 @@ #include "llvm/Option/Option.h" #include #include +#include + +#include "util/perf-hooks.h" namespace perf { using namespace llvm; class PerfModule { +public: + typedef std::map HookMap; private: std::unique_ptr Module; std::set Maps; std::set BPFFunctions; std::set JITFunctions; + + HookMap JITResult; + void prepareBPF(void); void prepareJIT(void); public: @@ -26,10 +34,15 @@ class PerfModule { { return Module.get(); } + inline HookMap *copyJITResult(void) + { + return new HookMap(JITResult); + } PerfModule(std::unique_ptr&& M); std::unique_ptr> toBPFObject(void); + int doJIT(void); }; std::unique_ptr -- 2.10.1