Message ID | 20161126070354.141764-15-wangnan0@huawei.com |
---|---|
State | Accepted |
Commit | 5e08a76525b8f5e9aeb8b27d0466614abec070a9 |
Headers | show |
On Sat, Nov 26, 2016 at 07:03:38AM +0000, Wang Nan wrote: > getBPFObjectFromModule() is introduced to compile LLVM IR(Module) > to BPF object. Add new testcase for it. > > Test result: > $ ./buildperf/perf test -v clang > 51: Test builtin clang support : > 51.1: Test builtin clang compile C source to IR : > --- start --- > test child forked, pid 21822 > test child finished with 0 > ---- end ---- > Test builtin clang support subtest 0: Ok > 51.2: Test builtin clang compile C source to ELF object : > --- start --- > test child forked, pid 21823 > test child finished with 0 > ---- end ---- > Test builtin clang support subtest 1: Ok > > Signed-off-by: Wang Nan <wangnan0@huawei.com> ... > + legacy::PassManager PM; > + if (TargetMachine->addPassesToEmitFile(PM, ostream, > + TargetMachine::CGFT_ObjectFile)) { > + llvm::errs() << "TargetMachine can't emit a file of this type\n"; > + return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; > + } > + PM.run(*Module); I'm pretty sure you want to add FunctionInlingPass as well otherwise I think llvm won't be doing much inlining and only very very simple programs will compile fine. See what we did on bcc side. Also did you consider skipping elf generation and using in memory instead ? That will improve compile/run time.
On 2016/11/27 1:25, Alexei Starovoitov wrote: > On Sat, Nov 26, 2016 at 07:03:38AM +0000, Wang Nan wrote: >> getBPFObjectFromModule() is introduced to compile LLVM IR(Module) >> to BPF object. Add new testcase for it. >> >> Test result: >> $ ./buildperf/perf test -v clang >> 51: Test builtin clang support : >> 51.1: Test builtin clang compile C source to IR : >> --- start --- >> test child forked, pid 21822 >> test child finished with 0 >> ---- end ---- >> Test builtin clang support subtest 0: Ok >> 51.2: Test builtin clang compile C source to ELF object : >> --- start --- >> test child forked, pid 21823 >> test child finished with 0 >> ---- end ---- >> Test builtin clang support subtest 1: Ok >> >> Signed-off-by: Wang Nan <wangnan0@huawei.com> > ... >> + legacy::PassManager PM; >> + if (TargetMachine->addPassesToEmitFile(PM, ostream, >> + TargetMachine::CGFT_ObjectFile)) { >> + llvm::errs() << "TargetMachine can't emit a file of this type\n"; >> + return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; >> + } >> + PM.run(*Module); > I'm pretty sure you want to add FunctionInlingPass as well otherwise > I think llvm won't be doing much inlining and only very very simple > programs will compile fine. See what we did on bcc side. Thank you for your information. I though inlining should be done during C to IR phase, and we have use -O2 for it. Let me check it. > Also did you consider skipping elf generation and using in memory > instead ? That will improve compile/run time. > Maybe in future work? Current design reuse libelf and bpf-loader for loading BPF code. Skipping ELF generation make compiling faster, but require another loader to be coexist with bpf-loader.c, or we need a new libbpf. In my current experience, outputting ELF is not so slow for both server and smartphone. Thank you.
diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c index 57ee160..2964c06 100644 --- a/tools/perf/tests/clang.c +++ b/tools/perf/tests/clang.c @@ -12,6 +12,10 @@ static struct { .func = test__clang_to_IR, .desc = "Test builtin clang compile C source to IR", }, + { + .func = test__clang_to_obj, + .desc = "Test builtin clang compile C source to ELF object", + }, #endif }; @@ -33,7 +37,7 @@ int test__clang(int i __maybe_unused) return TEST_SKIP; } #else -int test__clang(int i __maybe_unused) +int test__clang(int i) { if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table)) return TEST_FAIL; diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h index dcde4b5..22b3936 100644 --- a/tools/perf/util/c++/clang-c.h +++ b/tools/perf/util/c++/clang-c.h @@ -9,6 +9,7 @@ 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); #ifdef __cplusplus } diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp index d84e760..9b11e8c 100644 --- a/tools/perf/util/c++/clang-test.cpp +++ b/tools/perf/util/c++/clang-test.cpp @@ -13,15 +13,13 @@ public: ~perf_clang_scope() {perf_clang__cleanup();} }; -extern "C" { - -int test__clang_to_IR(void) +static std::unique_ptr<llvm::Module> +__test__clang_to_IR(void) { - perf_clang_scope _scope; unsigned int kernel_version; if (fetch_kernel_version(&kernel_version, NULL, 0)) - return -1; + return std::unique_ptr<llvm::Module>(nullptr); std::string cflag_kver("-DLINUX_VERSION_CODE=" + std::to_string(kernel_version)); @@ -30,14 +28,35 @@ int test__clang_to_IR(void) perf::getModuleFromSource({cflag_kver.c_str()}, "perf-test.c", test_llvm__bpf_base_prog); + return M; +} + +extern "C" { +int test__clang_to_IR(void) +{ + perf_clang_scope _scope; + auto M = __test__clang_to_IR(); if (!M) return -1; - for (llvm::Function& F : *M) if (F.getName() == "bpf_func__SyS_epoll_wait") return 0; return -1; } +int test__clang_to_obj(void) +{ + perf_clang_scope _scope; + + auto M = __test__clang_to_IR(); + if (!M) + return -1; + + auto Buffer = perf::getBPFObjectFromModule(&*M); + if (!Buffer) + return -1; + return 0; +} + } diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 715ca0a..2a1a75d 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -13,10 +13,15 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Tooling/Tooling.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/Option/Option.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include <memory> #include "clang.h" @@ -105,12 +110,52 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path) return getModuleFromSource(std::move(CFlags), Path, VFS); } +std::unique_ptr<llvm::SmallVectorImpl<char>> +getBPFObjectFromModule(llvm::Module *Module) +{ + using namespace llvm; + + std::string TargetTriple("bpf-pc-linux"); + std::string Error; + const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error); + if (!Target) { + llvm::errs() << Error; + return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr); + } + + llvm::TargetOptions Opt; + TargetMachine *TargetMachine = + Target->createTargetMachine(TargetTriple, + "generic", "", + Opt, Reloc::Static); + + Module->setDataLayout(TargetMachine->createDataLayout()); + Module->setTargetTriple(TargetTriple); + + std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>()); + raw_svector_ostream ostream(*Buffer); + + legacy::PassManager PM; + if (TargetMachine->addPassesToEmitFile(PM, ostream, + TargetMachine::CGFT_ObjectFile)) { + llvm::errs() << "TargetMachine can't emit a file of this type\n"; + return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; + } + PM.run(*Module); + + return std::move(Buffer); +} + } extern "C" { void perf_clang__init(void) { perf::LLVMCtx.reset(new llvm::LLVMContext()); + LLVMInitializeBPFTargetInfo(); + LLVMInitializeBPFTarget(); + LLVMInitializeBPFTargetMC(); + LLVMInitializeBPFAsmPrinter(); } void perf_clang__cleanup(void) diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h index b4fc2a9..dd8b042 100644 --- a/tools/perf/util/c++/clang.h +++ b/tools/perf/util/c++/clang.h @@ -19,5 +19,8 @@ std::unique_ptr<Module> getModuleFromSource(opt::ArgStringList CFlags, StringRef Path); +std::unique_ptr<llvm::SmallVectorImpl<char>> +getBPFObjectFromModule(llvm::Module *Module); + } #endif
getBPFObjectFromModule() is introduced to compile LLVM IR(Module) to BPF object. Add new testcase for it. Test result: $ ./buildperf/perf test -v clang 51: Test builtin clang support : 51.1: Test builtin clang compile C source to IR : --- start --- test child forked, pid 21822 test child finished with 0 ---- end ---- Test builtin clang support subtest 0: Ok 51.2: Test builtin clang compile C source to ELF object : --- start --- test child forked, pid 21823 test child finished with 0 ---- end ---- Test builtin clang support subtest 1: Ok Signed-off-by: Wang Nan <wangnan0@huawei.com> Cc: 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: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com --- tools/perf/tests/clang.c | 6 ++++- tools/perf/util/c++/clang-c.h | 1 + tools/perf/util/c++/clang-test.cpp | 31 +++++++++++++++++++++----- tools/perf/util/c++/clang.cpp | 45 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/c++/clang.h | 3 +++ 5 files changed, 79 insertions(+), 7 deletions(-) -- 2.10.1